Trig Projections
Unit circle with sine/cosine projections — useful for teaching angles and the Y-down canvas convention.
Paste into main.js in the editor, then click Restart.
Complete example
javascript
const cx = 160, cy = h / 2;
const r = 100;
const angle = time * 0.8;
const px = cx + r * Math.cos(angle);
const py = cy - r * Math.sin(angle); // flip Y → math "up" is screen up
return {
particles: [
{ x: px, y: py, r: 7, color: '#8B5CF6', label: 'P' },
],
circles: [
{ cx, cy, r, color: 'rgba(255,255,255,0.12)' },
],
lines: [
{ x1: cx, y1: cy, x2: px, y2: py, color: '#F59E0B', width: 1.5 },
{ x1: px, y1: py, x2: px, y2: cy, color: '#EF4444', width: 1, dashed: true },
{ x1: px, y1: py, x2: cx, y2: py, color: '#3B82F6', width: 1, dashed: true },
{ x1: cx - r - 20, y1: cy, x2: cx + r + 20, y2: cy, color: 'rgba(255,255,255,0.08)', width: 1 },
{ x1: cx, y1: cy - r - 20, x2: cx, y2: cy + r + 20, color: 'rgba(255,255,255,0.08)', width: 1 },
],
arcs: [
{ cx, cy, r: 25, startAngle: 0, endAngle: angle % (Math.PI * 2), color: '#8B5CF6', width: 2 },
],
bars: [
{
x: cx + r + 40,
y: cy - Math.abs(Math.sin(angle)) * r,
w: 30,
h: Math.abs(Math.sin(angle)) * r,
color: '#EF4444',
label: 'sin',
},
{
x: cx + r + 80,
y: cy - Math.abs(Math.cos(angle)) * r,
w: 30,
h: Math.abs(Math.cos(angle)) * r,
color: '#3B82F6',
label: 'cos',
},
],
text: {
angle: ((angle % (Math.PI * 2)) * 180 / Math.PI).toFixed(1) + '°',
sin: Math.sin(angle).toFixed(3),
cos: Math.cos(angle).toFixed(3),
},
};Y-up vs canvas
javascript
// Math textbook (Y up):
py = cy - r * Math.sin(angle)
// Raw canvas (Y down) — point would travel the other way:
py = cy + r * Math.sin(angle)See Coordinate System.
Circular orbit (no state)
Same idea without flipping Y — good when you want screen-native motion:
javascript
const cx = w / 2, cy = h / 2;
const angle = time * 1.5;
const r = 120;
const px = cx + r * Math.cos(angle);
const py = cy + r * Math.sin(angle);
return {
particles: [
{ x: px, y: py, r: 10, color: '#8B5CF6', label: 'orbiter' },
{ x: cx, y: cy, r: 6, color: '#F59E0B', label: 'center' },
],
lines: [{ x1: cx, y1: cy, x2: px, y2: py, color: '#F59E0B', width: 1.5 }],
circles: [{ cx, cy, r, color: 'rgba(255,255,255,0.15)' }],
arcs: [
{ cx, cy, r: 30, startAngle: 0, endAngle: angle % (Math.PI * 2), color: '#8B5CF6', width: 2 },
],
vectors: [{
x: 60 * Math.cos(angle + Math.PI / 2),
y: 60 * Math.sin(angle + Math.PI / 2),
ox: px, oy: py, color: '#22C55E', label: 'v',
}],
text: {
theta: (angle % (Math.PI * 2)).toFixed(2) + ' rad',
},
};No state needed — position is a pure function of time.