this repo has no description
1
2<!DOCTYPE html>
3<html lang="en">
4<head>
5<meta charset="utf-8">
6<title>Subjective Necker Cube</title>
7<style>
8 html,body{
9 margin:0;
10 height:100%;
11 display:flex;
12 align-items:center;
13 justify-content:center;
14 background:#fff; /* white background */
15 }
16</style>
17</head>
18<body>
19<canvas id="cube" width="512" height="512"></canvas>
20
21<script>
22(() => {
23 const canvas = document.getElementById('cube');
24 const ctx = canvas.getContext('2d');
25 const W = canvas.width;
26 const H = canvas.height;
27 const CX = W / 2;
28 const CY = H / 2;
29
30 const SCALE = 80;
31 const DISK_RADIUS = 24;
32 const EDGE_THICK = 12;
33
34 const VERTS = [ // corner coordinates of unit cube
35 [-1,-1,-1],[ 1,-1,-1],[ 1, 1,-1],[-1, 1,-1],
36 [-1,-1, 1],[ 1,-1, 1],[ 1, 1, 1],[-1, 1, 1],
37 ];
38 const EDGES = [ // pairs of vertex indices
39 [0,1],[1,2],[2,3],[3,0],
40 [4,5],[5,6],[6,7],[7,4],
41 [0,4],[1,5],[2,6],[3,7],
42 ];
43
44 function rotate([x0,y0,z0], yaw, pitch, roll){
45 // yaw (y axis)
46 let x = x0*Math.cos(yaw) + z0*Math.sin(yaw);
47 let z = -x0*Math.sin(yaw) + z0*Math.cos(yaw);
48 let y = y0;
49
50 // pitch (x axis)
51 [y,z] = [y*Math.cos(pitch) - z*Math.sin(pitch),
52 y*Math.sin(pitch) + z*Math.cos(pitch)];
53
54 // roll (z axis)
55 [x,y] = [x*Math.cos(roll) - y*Math.sin(roll),
56 x*Math.sin(roll) + y*Math.cos(roll)];
57 return [x,y,z];
58 }
59
60 function project([x,y,z]) { // z is ignored
61 return [CX + x*SCALE, CY - y*SCALE];
62 }
63
64 /* ---------- main draw loop ---------- */
65 function draw(tMillis){
66 const t = tMillis * 0.001; // seconds
67 const yaw = 0.5*0.7 * t;
68 const pitch = 0.5*0.3 * t;
69 const roll = 0.5*0.5 * t;
70
71 // clear
72 ctx.clearRect(0,0,W,H);
73
74 // project all vertices for this frame
75 const screen = VERTS.map(v => project(rotate(v, yaw, pitch, roll)));
76
77 /* draw black vertex disks first */
78 ctx.fillStyle = '#000';
79 screen.forEach(([x,y])=>{
80 ctx.beginPath();
81 ctx.arc(x, y, DISK_RADIUS, 0, Math.PI*2);
82 ctx.fill();
83 });
84
85 /* draw thick white edges on top */
86 ctx.lineWidth = EDGE_THICK;
87 ctx.strokeStyle = '#fff'; // same as background
88 ctx.lineCap = 'round';
89 ctx.beginPath();
90 EDGES.forEach(([i,j])=>{
91 const [x1,y1] = screen[i];
92 const [x2,y2] = screen[j];
93 ctx.moveTo(x1,y1);
94 ctx.lineTo(x2,y2);
95 });
96 ctx.stroke();
97
98 requestAnimationFrame(draw);
99 }
100 requestAnimationFrame(draw);
101})();
102</script>
103</body>
104</html>