Pick an angle and ask the demo to trisect it with the only two tools the rules allow: a compass and a straightedge. The target rays sit at exactly one-third and two-thirds of the angle.
<p class="hint">A right angle (90°) <b>can</b> be trisected with compass and straightedge. A 60° angle <b>cannot</b> — the part you would need is 20°, and no finite construction can ever produce it (Wantzel, 1837). Pick an angle and press <b>Trisect</b>.</p>
<div class="picker">
<label>Angle:</label>
<button class="ang sel" data-a="90" type="button">90°</button>
<button class="ang" data-a="60" type="button">60°</button>
<button class="ang" data-a="120" type="button">120°</button>
<button class="ang" data-a="180" type="button">180°</button>
</div>
<canvas id="cv" width="340" height="240"></canvas>
<div class="status" id="status">90° is constructible — press Trisect.</div>
<div class="btns">
<button id="trisect" type="button">Trisect</button>
<button id="reset" type="button" class="ghost">Reset</button>
</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .6rem; line-height: 1.45; }
.picker { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin: .2rem 0 .5rem; }
.picker label { font-weight: 600; font-size: .9rem; }
.ang { font: 600 14px system-ui, sans-serif; padding: .35rem .7rem; border: 1px solid #adb1b8;
background: #fff; color: #1d3557; border-radius: 8px; cursor: pointer; }
.ang.sel { background: #1d3557; color: #fff; border-color: #1d3557; }
canvas { background: #f4f7fa; border: 1px solid #cdd9e3; border-radius: 8px; display: block; }
.status { font-size: 1rem; font-weight: 600; margin: .55rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c92f3c; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button#trisect, button#reset { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem;
border: 1px solid #1d3557; background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Trisecting an angle θ means constructing cos(θ/3). The triple-angle identity
// 4·cos³(θ/3) − 3·cos(θ/3) = cos θ
// turns this into a CUBIC. The needed length is constructible (compass+straightedge)
// only when that cubic's root lies in a tower of square-root extensions — degree a
// power of 2. For θ=90°, cos θ=0 → x(4x²−3)=0, root cos30°=√3/2 (degree 2): OK.
// For θ=60°, cos θ=1/2 → 8x³−6x−1=0, no rational root → irreducible (degree 3):
// cos20° is NOT constructible. Wantzel proved this in 1837.
const cv = document.getElementById('cv'), ctx = cv.getContext('2d');
const OX = 60, OY = 190, R = 150; // vertex (apex) and ray length
let angle = 90, done = false;
// Is the cubic 4x³ − 3x − cosθ = 0 reducible over Q (→ constructible)?
// The picker uses only angles whose cosine is rational (0, ±1/2, ±1), so the
// rational-root test is valid: a rational root means the cubic factors → the
// needed length sits in a degree-2 tower → constructible. No rational root means
// the cubic is irreducible (degree 3) → not constructible (Wantzel, 1837).
function constructible(deg) {
const c = Math.cos(deg * Math.PI / 180);
const f = x => 8*x*x*x - 6*x - 2*c; // = 2·(4x³ − 3x − cosθ)
// rational-root candidates p/q with p|const, q|8 (const term = −2c, scaled cases)
const cands = [];
for (let p = -8; p <= 8; p++) for (const q of [1,2,4,8]) cands.push(p/q);
// de-dup and test
const seen = new Set();
for (const x of cands) {
const key = x.toFixed(6); if (seen.has(key)) continue; seen.add(key);
if (Math.abs(f(x)) < 1e-9) return true; // rational root → reducible → constructible
}
return false;
}
function ray(deg) { // canvas point at angle `deg` above the +x axis from vertex
const a = -deg * Math.PI / 180; // canvas y grows downward
return [OX + R * Math.cos(a), OY + R * Math.sin(a)];
}
function line(p, col, w) {
ctx.strokeStyle = col; ctx.lineWidth = w || 2;
ctx.beginPath(); ctx.moveTo(OX, OY); ctx.lineTo(p[0], p[1]); ctx.stroke();
}
function arc() {
ctx.strokeStyle = '#9fb2c8'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.arc(OX, OY, 60, -angle*Math.PI/180, 0); ctx.stroke();
}
function draw() {
ctx.clearRect(0,0,cv.width,cv.height);
arc();
line(ray(0), '#1d3557', 2.5); // base ray
line(ray(angle), '#1d3557', 2.5); // upper ray
// label
ctx.fillStyle = '#1d3557'; ctx.font = '600 14px system-ui';
ctx.fillText(angle + '°', OX + 70, OY - 12);
if (done) {
const ok = constructible(angle);
if (ok) { // exact thirds reachable
line(ray(angle/3), '#0a7d33', 2);
line(ray(2*angle/3), '#0a7d33', 2);
ctx.fillStyle = '#0a7d33';
ctx.fillText((angle/3) + '°', ray(angle/6)[0]+8, ray(angle/6)[1]);
} else { // honest construction falls short — draw a near-miss bisector-of-bisector
// What you CAN build easily is the bisector (angle/2). Show it overshooting the
// first third to make the failure visible; the true 1/3 ray is dashed & unreachable.
line(ray(angle/2), '#e08a00', 2); // a constructible ray (the bisector)
ctx.setLineDash([5,4]);
line(ray(angle/3), '#c92f3c', 1.6); // the UNREACHABLE true third
line(ray(2*angle/3), '#c92f3c', 1.6);
ctx.setLineDash([]);
ctx.fillStyle = '#c92f3c';
ctx.fillText('?', ray(angle/6)[0]+8, ray(angle/6)[1]);
}
}
}
function setStatus(t, cls){ const s=document.getElementById('status'); s.textContent=t; s.className='status '+cls; }
function selBtn(a){ document.querySelectorAll('.ang').forEach(b=>b.classList.toggle('sel', +b.dataset.a===a)); }
document.querySelectorAll('.ang').forEach(b => b.addEventListener('click', () => {
angle = +b.dataset.a; done = false; selBtn(angle); draw();
setStatus(fmt('%angle%° — press Trisect.', { angle: angle }), '');
}));
document.getElementById('trisect').addEventListener('click', () => {
done = true; draw();
const third = angle/3;
if (constructible(angle)) {
setStatus(fmt('✓ %angle%° trisects: %third%° is constructible (degree a power of 2).', { angle: angle, third: third }), 'ok');
console.log(fmt('Trisect %angle%° → %third%°: constructible. cos%third%° =', { angle: angle, third: third }), Math.cos(third*Math.PI/180));
} else {
setStatus(fmt('✗ %angle%° cannot be trisected — %third%° needs an irreducible cubic. (Wantzel, 1837)', { angle: angle, third: third }), 'bad');
console.log(fmt('Trisect %angle%° → %third%°: 8x³−6x−%v%=0 has no rational root → not constructible.', { angle: angle, third: third, v: 2*Math.cos(angle*Math.PI/180) }));
}
});
document.getElementById('reset').addEventListener('click', () => { done=false; draw(); setStatus(fmt('%angle%° — press Trisect.', { angle: angle }),''); });
draw();
<p class="hint">A right angle (90°) <b>can</b> be trisected with compass and straightedge. A 60° angle <b>cannot</b> — the part you would need is 20°, and no finite construction can ever produce it (Wantzel, 1837). Pick an angle and press <b>Trisect</b>.</p>
<div class="picker">
<label>Angle:</label>
<button class="ang sel" data-a="90" type="button">90°</button>
<button class="ang" data-a="60" type="button">60°</button>
<button class="ang" data-a="120" type="button">120°</button>
<button class="ang" data-a="180" type="button">180°</button>
</div>
<canvas id="cv" width="340" height="240"></canvas>
<div class="status" id="status">90° is constructible — press Trisect.</div>
<div class="btns">
<button id="trisect" type="button">Trisect</button>
<button id="reset" type="button" class="ghost">Reset</button>
</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .6rem; line-height: 1.45; }
.picker { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin: .2rem 0 .5rem; }
.picker label { font-weight: 600; font-size: .9rem; }
.ang { font: 600 14px system-ui, sans-serif; padding: .35rem .7rem; border: 1px solid #adb1b8;
background: #fff; color: #1d3557; border-radius: 8px; cursor: pointer; }
.ang.sel { background: #1d3557; color: #fff; border-color: #1d3557; }
canvas { background: #f4f7fa; border: 1px solid #cdd9e3; border-radius: 8px; display: block; }
.status { font-size: 1rem; font-weight: 600; margin: .55rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.bad { color: #c92f3c; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button#trisect, button#reset { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem;
border: 1px solid #1d3557; background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Trisecting an angle θ means constructing cos(θ/3). The triple-angle identity
// 4·cos³(θ/3) − 3·cos(θ/3) = cos θ
// turns this into a CUBIC. The needed length is constructible (compass+straightedge)
// only when that cubic's root lies in a tower of square-root extensions — degree a
// power of 2. For θ=90°, cos θ=0 → x(4x²−3)=0, root cos30°=√3/2 (degree 2): OK.
// For θ=60°, cos θ=1/2 → 8x³−6x−1=0, no rational root → irreducible (degree 3):
// cos20° is NOT constructible. Wantzel proved this in 1837.
const cv = document.getElementById('cv'), ctx = cv.getContext('2d');
const OX = 60, OY = 190, R = 150; // vertex (apex) and ray length
let angle = 90, done = false;
// Is the cubic 4x³ − 3x − cosθ = 0 reducible over Q (→ constructible)?
// The picker uses only angles whose cosine is rational (0, ±1/2, ±1), so the
// rational-root test is valid: a rational root means the cubic factors → the
// needed length sits in a degree-2 tower → constructible. No rational root means
// the cubic is irreducible (degree 3) → not constructible (Wantzel, 1837).
function constructible(deg) {
const c = Math.cos(deg * Math.PI / 180);
const f = x => 8*x*x*x - 6*x - 2*c; // = 2·(4x³ − 3x − cosθ)
// rational-root candidates p/q with p|const, q|8 (const term = −2c, scaled cases)
const cands = [];
for (let p = -8; p <= 8; p++) for (const q of [1,2,4,8]) cands.push(p/q);
// de-dup and test
const seen = new Set();
for (const x of cands) {
const key = x.toFixed(6); if (seen.has(key)) continue; seen.add(key);
if (Math.abs(f(x)) < 1e-9) return true; // rational root → reducible → constructible
}
return false;
}
function ray(deg) { // canvas point at angle `deg` above the +x axis from vertex
const a = -deg * Math.PI / 180; // canvas y grows downward
return [OX + R * Math.cos(a), OY + R * Math.sin(a)];
}
function line(p, col, w) {
ctx.strokeStyle = col; ctx.lineWidth = w || 2;
ctx.beginPath(); ctx.moveTo(OX, OY); ctx.lineTo(p[0], p[1]); ctx.stroke();
}
function arc() {
ctx.strokeStyle = '#9fb2c8'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.arc(OX, OY, 60, -angle*Math.PI/180, 0); ctx.stroke();
}
function draw() {
ctx.clearRect(0,0,cv.width,cv.height);
arc();
line(ray(0), '#1d3557', 2.5); // base ray
line(ray(angle), '#1d3557', 2.5); // upper ray
// label
ctx.fillStyle = '#1d3557'; ctx.font = '600 14px system-ui';
ctx.fillText(angle + '°', OX + 70, OY - 12);
if (done) {
const ok = constructible(angle);
if (ok) { // exact thirds reachable
line(ray(angle/3), '#0a7d33', 2);
line(ray(2*angle/3), '#0a7d33', 2);
ctx.fillStyle = '#0a7d33';
ctx.fillText((angle/3) + '°', ray(angle/6)[0]+8, ray(angle/6)[1]);
} else { // honest construction falls short — draw a near-miss bisector-of-bisector
// What you CAN build easily is the bisector (angle/2). Show it overshooting the
// first third to make the failure visible; the true 1/3 ray is dashed & unreachable.
line(ray(angle/2), '#e08a00', 2); // a constructible ray (the bisector)
ctx.setLineDash([5,4]);
line(ray(angle/3), '#c92f3c', 1.6); // the UNREACHABLE true third
line(ray(2*angle/3), '#c92f3c', 1.6);
ctx.setLineDash([]);
ctx.fillStyle = '#c92f3c';
ctx.fillText('?', ray(angle/6)[0]+8, ray(angle/6)[1]);
}
}
}
function setStatus(t, cls){ const s=document.getElementById('status'); s.textContent=t; s.className='status '+cls; }
function selBtn(a){ document.querySelectorAll('.ang').forEach(b=>b.classList.toggle('sel', +b.dataset.a===a)); }
document.querySelectorAll('.ang').forEach(b => b.addEventListener('click', () => {
angle = +b.dataset.a; done = false; selBtn(angle); draw();
setStatus(fmt('%angle%° — press Trisect.', { angle: angle }), '');
}));
document.getElementById('trisect').addEventListener('click', () => {
done = true; draw();
const third = angle/3;
if (constructible(angle)) {
setStatus(fmt('✓ %angle%° trisects: %third%° is constructible (degree a power of 2).', { angle: angle, third: third }), 'ok');
console.log(fmt('Trisect %angle%° → %third%°: constructible. cos%third%° =', { angle: angle, third: third }), Math.cos(third*Math.PI/180));
} else {
setStatus(fmt('✗ %angle%° cannot be trisected — %third%° needs an irreducible cubic. (Wantzel, 1837)', { angle: angle, third: third }), 'bad');
console.log(fmt('Trisect %angle%° → %third%°: 8x³−6x−%v%=0 has no rational root → not constructible.', { angle: angle, third: third, v: 2*Math.cos(angle*Math.PI/180) }));
}
});
document.getElementById('reset').addEventListener('click', () => { done=false; draw(); setStatus(fmt('%angle%° — press Trisect.', { angle: angle }),''); });
draw();
Comments
Loading comments...