this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add HTML/JS impl

+104
+104
snc.html
··· 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>