Created
June 16, 2026 21:07
-
-
Save jmikedupont2/1251a4bbb697f69bf88f2334c263e1a2 to your computer and use it in GitHub Desktop.
The Penteract in the Monster — a 5-cube shadow
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>The Penteract in the Monster — a 5-cube shadow</title> | |
| <style> | |
| html,body{margin:0;height:100%;background:#05060e;color:#e9e9f3; | |
| font-family:"Segoe UI",system-ui,Helvetica,Arial,sans-serif;overflow:hidden} | |
| #wrap{position:fixed;inset:0} | |
| canvas{display:block;width:100%;height:100%} | |
| #hud{position:fixed;left:0;right:0;bottom:0;padding:14px 20px 18px; | |
| background:linear-gradient(0deg,rgba(5,6,14,.94),rgba(5,6,14,0)); | |
| pointer-events:none} | |
| #title{font-size:23px;font-weight:700;letter-spacing:.5px; | |
| text-shadow:0 0 18px rgba(155,108,255,.6)} | |
| #thm{font-family:"Cascadia Code",Consolas,monospace;font-size:12.5px; | |
| color:#8ad7ff;margin-top:3px} | |
| #text{font-size:14.5px;line-height:1.5;margin-top:5px;max-width:980px; | |
| color:#cdd0e6} | |
| #bar{position:fixed;top:0;left:0;height:3px;background:#9b6cff;width:0%; | |
| box-shadow:0 0 10px #9b6cff} | |
| #ctl{position:fixed;top:12px;right:16px;display:flex;gap:8px;z-index:5} | |
| #ctl button{pointer-events:auto;background:rgba(155,108,255,.16); | |
| color:#e9e9f3;border:1px solid rgba(155,108,255,.5);border-radius:7px; | |
| padding:6px 11px;font-size:13px;cursor:pointer} | |
| #ctl button:hover{background:rgba(155,108,255,.34)} | |
| #dots{position:fixed;top:15px;left:16px;display:flex;gap:7px;z-index:5} | |
| .dot{width:10px;height:10px;border-radius:50%;background:rgba(255,255,255,.22); | |
| cursor:pointer;pointer-events:auto;transition:all .2s} | |
| .dot.on{background:#9b6cff;box-shadow:0 0 9px #9b6cff;transform:scale(1.25)} | |
| #legend{position:fixed;top:42px;left:16px;font-size:12px;color:#aab; | |
| z-index:4;line-height:1.6} | |
| #legend b{font-family:"Cascadia Code",Consolas,monospace} | |
| </style> | |
| </head> | |
| <body> | |
| <div id="wrap"><canvas id="cv"></canvas></div> | |
| <div id="bar"></div> | |
| <div id="ctl"> | |
| <button id="prev">← Prev</button> | |
| <button id="play">❙❙ Pause</button> | |
| <button id="next">Next →</button> | |
| </div> | |
| <div id="dots"></div> | |
| <div id="legend"></div> | |
| <div id="hud"> | |
| <div id="title"></div> | |
| <div id="thm"></div> | |
| <div id="text"></div> | |
| </div> | |
| <script> | |
| const DATA = {"axes": [2, 3, 5, 23, 47], "corners": [{"e": 0, "idx": 0, "bits": [0, 0, 0, 0, 0], "exps": [0, 0, 0, 0, 0], "deg": "1", "digits": 1}, {"e": 1, "idx": 2, "bits": [1, 0, 0, 0, 0], "exps": [2, 0, 0, 0, 0], "deg": "21,296,876", "digits": 8}, {"e": 2, "idx": 8, "bits": [0, 1, 0, 0, 0], "exps": [0, 6, 0, 0, 0], "deg": "3.617 x 10^13", "digits": 14}, {"e": 3, "idx": 168, "bits": [1, 1, 0, 0, 0], "exps": [18, 19, 0, 0, 0], "deg": "1.033 x 10^26", "digits": 27}, {"e": 4, "idx": 15, "bits": [0, 0, 1, 0, 0], "exps": [0, 0, 9, 0, 0], "deg": "8.980 x 10^15", "digits": 16}, {"e": 5, "idx": 35, "bits": [1, 0, 1, 0, 0], "exps": [3, 0, 8, 0, 0], "deg": "7.731 x 10^19", "digits": 20}, {"e": 6, "idx": 160, "bits": [0, 1, 1, 0, 0], "exps": [0, 17, 7, 0, 0], "deg": "6.432 x 10^25", "digits": 26}, {"e": 7, "idx": 150, "bits": [1, 1, 1, 0, 0], "exps": [3, 6, 7, 0, 0], "deg": "4.176 x 10^25", "digits": 26}, {"e": 8, "idx": 5, "bits": [0, 0, 0, 1, 0], "exps": [0, 0, 0, 1, 0], "deg": "19,360,062,527", "digits": 11}, {"e": 9, "idx": 4, "bits": [1, 0, 0, 1, 0], "exps": [2, 0, 0, 1, 0], "deg": "18,538,750,076", "digits": 11}, {"e": 10, "idx": 25, "bits": [0, 1, 0, 1, 0], "exps": [0, 19, 0, 1, 0], "deg": "3.503 x 10^18", "digits": 19}, {"e": 11, "idx": 43, "bits": [1, 1, 0, 1, 0], "exps": [1, 12, 0, 1, 0], "deg": "6.405 x 10^20", "digits": 21}, {"e": 12, "idx": 18, "bits": [0, 0, 1, 1, 0], "exps": [0, 0, 2, 1, 0], "deg": "3.966 x 10^16", "digits": 17}, {"e": 13, "idx": 118, "bits": [1, 0, 1, 1, 0], "exps": [18, 0, 8, 1, 0], "deg": "4.004 x 10^24", "digits": 25}, {"e": 14, "idx": 52, "bits": [0, 1, 1, 1, 0], "exps": [0, 1, 9, 1, 0], "deg": "1.480 x 10^21", "digits": 22}, {"e": 15, "idx": 19, "bits": [1, 1, 1, 1, 0], "exps": [1, 1, 2, 1, 0], "deg": "6.035 x 10^16", "digits": 17}, {"e": 16, "idx": 1, "bits": [0, 0, 0, 0, 1], "exps": [0, 0, 0, 0, 1], "deg": "196,883", "digits": 6}, {"e": 17, "idx": 3, "bits": [1, 0, 0, 0, 1], "exps": [1, 0, 0, 0, 1], "deg": "842,609,326", "digits": 9}, {"e": 18, "idx": 100, "bits": [0, 1, 0, 0, 1], "exps": [0, 19, 0, 0, 1], "deg": "6.000 x 10^23", "digits": 24}, {"e": 19, "idx": 6, "bits": [1, 1, 0, 0, 1], "exps": [1, 1, 0, 0, 1], "deg": "293,553,734,298", "digits": 12}, {"e": 20, "idx": 9, "bits": [0, 0, 1, 0, 1], "exps": [0, 0, 2, 0, 1], "deg": "1.255 x 10^14", "digits": 15}, {"e": 21, "idx": 20, "bits": [1, 0, 1, 0, 1], "exps": [2, 0, 7, 0, 1], "deg": "2.510 x 10^17", "digits": 18}, {"e": 22, "idx": 30, "bits": [0, 1, 1, 0, 1], "exps": [0, 1, 7, 0, 1], "deg": "2.858 x 10^19", "digits": 20}, {"e": 23, "idx": 36, "bits": [1, 1, 1, 0, 1], "exps": [1, 3, 8, 0, 1], "deg": "1.304 x 10^20", "digits": 21}, {"e": 24, "idx": 21, "bits": [0, 0, 0, 1, 1], "exps": [0, 0, 0, 1, 1], "deg": "2.905 x 10^17", "digits": 18}, {"e": 25, "idx": 38, "bits": [1, 0, 0, 1, 1], "exps": [2, 0, 0, 1, 1], "deg": "1.723 x 10^20", "digits": 21}, {"e": 26, "idx": 10, "bits": [0, 1, 0, 1, 1], "exps": [0, 3, 0, 1, 1], "deg": "1.902 x 10^14", "digits": 15}, {"e": 27, "idx": 7, "bits": [1, 1, 0, 1, 1], "exps": [1, 1, 0, 1, 1], "deg": "3.879 x 10^12", "digits": 13}, {"e": 28, "idx": 24, "bits": [0, 0, 1, 1, 1], "exps": [0, 0, 3, 1, 1], "deg": "2.986 x 10^18", "digits": 19}, {"e": 29, "idx": 13, "bits": [1, 0, 1, 1, 1], "exps": [1, 0, 2, 1, 1], "deg": "1.109 x 10^15", "digits": 16}, {"e": 30, "idx": 27, "bits": [0, 1, 1, 1, 1], "exps": [0, 6, 7, 1, 1], "deg": "3.605 x 10^18", "digits": 19}, {"e": 31, "idx": 66, "bits": [1, 1, 1, 1, 1], "exps": [2, 3, 7, 1, 1], "deg": "2.180 x 10^22", "digits": 23}]}; | |
| const AX = DATA.axes, CO = DATA.corners; | |
| // per-axis colours for the 5 primes {2,3,5,23,47} | |
| const AXCOL = ["#ff5d5d","#ffb24d","#ffe14d","#4dd0ff","#b06bff"]; | |
| const cv = document.getElementById('cv'), g = cv.getContext('2d'); | |
| let W=0,H=0,DPR=1; | |
| function resize(){DPR=Math.min(2,window.devicePixelRatio||1); | |
| W=cv.clientWidth;H=cv.clientHeight;cv.width=W*DPR;cv.height=H*DPR; | |
| g.setTransform(DPR,0,0,DPR,0,0);} | |
| window.addEventListener('resize',resize); | |
| // ---- geometry of the penteract ------------------------------------------- | |
| // 5 axis directions in 3D, spread out symmetrically; coord in {-1,1}^5. | |
| function unit(v){const n=Math.hypot(v[0],v[1],v[2]);return[v[0]/n,v[1]/n,v[2]/n];} | |
| const AXDIR = [ | |
| unit([ 1.0, 0.15, 0.30]), | |
| unit([ 0.30, 1.0, 0.10]), | |
| unit([-0.20, 0.15, 1.0 ]), | |
| unit([ 0.85, -0.75, -0.55]), | |
| unit([-0.80, -0.70, 0.55]), | |
| ].map(v=>v.map(x=>x*1.05)); | |
| // edges: pairs of corners differing in exactly one bit | |
| const EDGES=[]; | |
| for(let a=0;a<32;a++)for(let b=a+1;b<32;b++){ | |
| const x=a^b; if((x&(x-1))===0) EDGES.push([a,b, Math.log2(x)|0]); | |
| } | |
| // 5D rotation of the {-1,1}^5 coordinate, then map to 3D via AXDIR. | |
| function corner5(e,t){ | |
| let c=[]; for(let k=0;k<5;k++) c.push(((e>>k)&1)?1:-1); | |
| // rotate pairs of 5D coordinate planes at different rates -> "hyper" morph | |
| const planes=[[0,2,0.55],[1,3,0.40],[2,4,0.31],[0,4,0.23],[1,4,0.17]]; | |
| for(const [i,j,sp] of planes){ | |
| const a=t*sp, ca=Math.cos(a), sa=Math.sin(a); | |
| const ci=c[i], cj=c[j]; | |
| c[i]=ci*ca - cj*sa; c[j]=ci*sa + cj*ca; | |
| } | |
| let p=[0,0,0]; | |
| for(let k=0;k<5;k++){p[0]+=c[k]*AXDIR[k][0];p[1]+=c[k]*AXDIR[k][1];p[2]+=c[k]*AXDIR[k][2];} | |
| return p; | |
| } | |
| // view rotation (slow yaw/pitch) + perspective projection | |
| function project(p,yaw,pitch,scale,cx,cy){ | |
| let x=p[0],y=p[1],z=p[2]; | |
| let cz=Math.cos(yaw),sz=Math.sin(yaw); let x1=x*cz - z*sz, z1=x*sz + z*cz; | |
| let cp=Math.cos(pitch),sp=Math.sin(pitch); let y1=y*cp - z1*sp, z2=y*sp + z1*cp; | |
| const d=6.2, f=d/(d - z2*0.9); | |
| return [cx + x1*scale*f, cy + y1*scale*f, z2, f]; | |
| } | |
| // ---- scenes --------------------------------------------------------------- | |
| const SCENES=[ | |
| {id:"intro",title:"THE PENTERACT", | |
| thm:"MonsterShadows.cube5_shadow (proved by native_decide)", | |
| text:"A penteract is the 5-dimensional hypercube: 32 vertices, 80 edges. It is "+ | |
| "spinning here in all five dimensions at once. We will see that the Monster "+ | |
| "group hides one of these inside its character table.", | |
| mode:"cube", reveal:0}, | |
| {id:"axes",title:"FIVE AXES = FIVE PRIMES", | |
| thm:"MonsterShadows.axes5 = [2, 3, 5, 23, 47]", | |
| text:"The 5 directions of the cube are coloured by 5 supersingular primes "+ | |
| "{2, 3, 5, 23, 47}. Moving along axis k flips whether prime p_k divides the "+ | |
| "representation's degree.", | |
| mode:"cube", reveal:0, axes:true}, | |
| {id:"corners",title:"32 CORNERS = 32 REPRESENTATIONS", | |
| thm:"MonsterShadows.cube5_distinct (the 32 corners are Nodup)", | |
| text:"Each corner is a genuine Monster irreducible representation. Corner e (a "+ | |
| "5-bit address) is the degree divisible by exactly the primes whose bit is "+ | |
| "set. All 32 distinct degrees appear \u2014 the full corner set is realized.", | |
| mode:"cube", reveal:1, labels:true}, | |
| {id:"shadow",title:"HOW IT LIVES THERE \u2014 THE SHADOW", | |
| thm:"MonsterShadows.cube5_shadow_exists = true", | |
| text:"Project the spinning cube straight down onto its 5 prime-columns: the 32 "+ | |
| "corners cast a 32\u00d75 grid in which every one of the 2^5 = 32 divisibility "+ | |
| "patterns occurs exactly once. That grid is the shadow living in the matrix.", | |
| mode:"shadow"}, | |
| {id:"max",title:"FIVE IS MAXIMAL", | |
| thm:"MonsterShadows.no_cube6_shadow = true", | |
| text:"Could a 6-cube fit? For every choice of 6 of the 15 supersingular primes at "+ | |
| "least one of the 64 corners is missing \u2014 a hole in the shadow. So the "+ | |
| "penteract is the largest hypercube the Monster degrees cast. 5 is maximal.", | |
| mode:"hole"}, | |
| ]; | |
| let scene=0, playing=true, t0=performance.now(), sceneStart=t0, phase=0; | |
| const DUR=[7000,7000,9000,9000,8500]; | |
| const dotsEl=document.getElementById('dots'); | |
| SCENES.forEach((s,i)=>{const d=document.createElement('div');d.className='dot'; | |
| d.onclick=()=>goto(i);dotsEl.appendChild(d);}); | |
| function goto(i){scene=(i+SCENES.length)%SCENES.length;sceneStart=performance.now(); | |
| updateHUD();} | |
| document.getElementById('next').onclick=()=>goto(scene+1); | |
| document.getElementById('prev').onclick=()=>goto(scene-1); | |
| const playBtn=document.getElementById('play'); | |
| playBtn.onclick=()=>{playing=!playing;playBtn.innerHTML=playing?"❙❙ Pause":"▶ Play";}; | |
| function updateHUD(){ | |
| const s=SCENES[scene]; | |
| document.getElementById('title').textContent=s.title; | |
| document.getElementById('thm').textContent=s.thm; | |
| document.getElementById('text').textContent=s.text; | |
| [...dotsEl.children].forEach((d,i)=>d.classList.toggle('on',i===scene)); | |
| const leg=document.getElementById('legend'); | |
| if(s.axes||s.mode==='shadow'||s.mode==='hole'){ | |
| leg.innerHTML = AX.map((p,k)=> | |
| `<div><span style="color:${AXCOL[k]}">■</span> axis ${k} <b>p=${p}</b></div>` | |
| ).join(""); | |
| } else leg.innerHTML=""; | |
| } | |
| // smoothstep | |
| function ss(x){x=Math.max(0,Math.min(1,x));return x*x*(3-2*x);} | |
| function draw(now){ | |
| const s=SCENES[scene]; | |
| const tlocal=(now-sceneStart); | |
| if(playing && tlocal>DUR[scene]) goto(scene+1); | |
| const spin=now*0.001; | |
| g.clearRect(0,0,W,H); | |
| // subtle starfield-ish bg vignette | |
| const grd=g.createRadialGradient(W/2,H*0.42,40,W/2,H*0.42,Math.max(W,H)*0.7); | |
| grd.addColorStop(0,"#0c1024");grd.addColorStop(1,"#04050c"); | |
| g.fillStyle=grd;g.fillRect(0,0,W,H); | |
| if(s.mode==="cube"||s.mode==="axes") drawCube(s,now,spin); | |
| else if(s.mode==="shadow") drawShadow(s,now,tlocal); | |
| else if(s.mode==="hole") drawHole(s,now,tlocal,spin); | |
| const prog=(scene+Math.min(1,tlocal/DUR[scene]))/SCENES.length; | |
| document.getElementById('bar').style.width=(prog*100).toFixed(1)+"%"; | |
| requestAnimationFrame(draw); | |
| } | |
| function drawCube(s,now,spin){ | |
| const cx=W*0.5, cy=H*0.42, scale=Math.min(W,H)*0.20; | |
| const yaw=spin*0.5, pitch=Math.sin(spin*0.31)*0.5+0.35; | |
| const t=now*0.0011; | |
| const P=CO.map(c=>project(corner5(c.e,t),yaw,pitch,scale,cx,cy)); | |
| // edges (painter: sort by avg depth) | |
| const es=EDGES.map(([a,b,k])=>({a,b,k,z:(P[a][2]+P[b][2])/2})); | |
| es.sort((u,v)=>u.z-v.z); | |
| for(const ed of es){ | |
| const A=P[ed.a],B=P[ed.b]; | |
| const depth=ss((ed.z+3)/6); | |
| let col, w; | |
| if(s.axes){col=AXCOL[ed.k]; w=1.1+1.6*depth;} | |
| else {const a=(0.18+0.5*depth); col=`rgba(150,130,255,${a})`; w=0.7+1.5*depth;} | |
| g.strokeStyle=col; g.lineWidth=w; | |
| g.beginPath();g.moveTo(A[0],A[1]);g.lineTo(B[0],B[1]);g.stroke(); | |
| } | |
| // vertices | |
| const order=[...Array(32).keys()].sort((u,v)=>P[u][2]-P[v][2]); | |
| for(const i of order){ | |
| const Pi=P[i], c=CO[i], depth=ss((Pi[2]+3)/6), f=Pi[3]; | |
| const r=(2.4+3.4*depth)*f; | |
| // colour vertex by popcount of bits (how many primes divide) | |
| const pc=c.bits.reduce((a,b)=>a+b,0); | |
| const hue=265 - pc*16; | |
| g.fillStyle=`hsla(${hue},85%,${42+depth*22}%,${0.55+0.45*depth})`; | |
| g.beginPath();g.arc(Pi[0],Pi[1],r,0,7);g.fill(); | |
| if(s.labels && depth>0.34){ | |
| g.fillStyle=`rgba(235,235,250,${0.30+0.7*depth})`; | |
| g.font=`${(9+5*depth)|0}px Consolas,monospace`; | |
| g.textAlign="center"; | |
| g.fillText("#"+c.idx, Pi[0], Pi[1]-r-3); | |
| } | |
| } | |
| } | |
| // project the 32 corners onto a 32 x 5 grid that "drops" out of the cube | |
| function drawShadow(s,now,tlocal){ | |
| const t=now*0.0011; | |
| const cx=W*0.5, cy=H*0.30, scale=Math.min(W,H)*0.15; | |
| const yaw=now*0.0004, pitch=0.5; | |
| const drop=ss((tlocal-600)/2600); // 0..1 cube -> grid | |
| // grid layout | |
| const gx0=W*0.5-(5*38)/2, gy0=H*0.46; | |
| const cw=38, ch=Math.min(13,(H*0.46)/32); | |
| // current positions interpolate cube vertex -> grid cell centre | |
| for(let e=0;e<32;e++){ | |
| const c=CO[e]; | |
| const Pc=project(corner5(e,t),yaw,pitch,scale,cx,cy); | |
| for(let k=0;k<5;k++){ | |
| const tx=gx0+k*cw+cw/2, ty=gy0+e*ch+ch/2; | |
| const x=Pc[0]+(tx-Pc[0])*drop, y=Pc[1]+(ty-Pc[1])*drop; | |
| const on=c.bits[k]; | |
| const rr=(1.6+1.4*(1-drop))*Pc[3]; | |
| g.fillStyle= on? AXCOL[k] : `rgba(90,95,130,${0.25+0.2*drop})`; | |
| g.globalAlpha = on? (0.55+0.45*drop) : (0.5); | |
| g.fillRect(x-cw*0.42*drop- (1-drop)*rr, y-ch*0.40*drop-(1-drop)*rr, | |
| cw*0.84*drop+(1-drop)*2*rr, ch*0.80*drop+(1-drop)*2*rr); | |
| } | |
| } | |
| g.globalAlpha=1; | |
| if(drop>0.6){ | |
| g.fillStyle="rgba(220,225,245,"+((drop-0.6)/0.4).toFixed(2)+")"; | |
| g.font="12px Consolas,monospace";g.textAlign="center"; | |
| for(let k=0;k<5;k++) g.fillText("p="+AX[k], gx0+k*cw+cw/2, gy0-6); | |
| g.textAlign="right"; | |
| g.fillStyle="rgba(160,165,195,"+((drop-0.6)/0.4).toFixed(2)+")"; | |
| for(let e=0;e<32;e+=4) g.fillText("#"+CO[e].idx, gx0-8, gy0+e*ch+ch*0.85); | |
| } | |
| } | |
| // scene 5: build a 6-cube grid and punch a hole in one corner | |
| function drawHole(s,now,tlocal,spin){ | |
| // show a 6-cube (64 corners) projection with one missing corner highlighted | |
| const cx=W*0.5, cy=H*0.42, scale=Math.min(W,H)*0.16; | |
| const yaw=spin*0.4, pitch=Math.sin(spin*0.27)*0.4+0.3; | |
| const t=now*0.0010; | |
| const AX6=[unit([1,0.1,0.3]),unit([0.25,1,0.05]),unit([-0.2,0.1,1]), | |
| unit([0.8,-0.7,-0.5]),unit([-0.75,-0.65,0.5]),unit([0.5,0.6,-0.8])] | |
| .map(v=>v.map(x=>x*0.95)); | |
| function c6(e){let c=[];for(let k=0;k<6;k++)c.push(((e>>k)&1)?1:-1); | |
| const planes=[[0,2,0.5],[1,3,0.37],[2,4,0.29],[3,5,0.21],[0,5,0.15]]; | |
| for(const[i,j,sp]of planes){const a=t*sp,ca=Math.cos(a),sa=Math.sin(a); | |
| const ci=c[i],cj=c[j];c[i]=ci*ca-cj*sa;c[j]=ci*sa+cj*ca;} | |
| let p=[0,0,0];for(let k=0;k<6;k++){p[0]+=c[k]*AX6[k][0];p[1]+=c[k]*AX6[k][1];p[2]+=c[k]*AX6[k][2];} | |
| return p;} | |
| const missing=43; // the "hole": a corner with no rep | |
| const P=[];for(let e=0;e<64;e++)P.push(project(c6(e),yaw,pitch,scale,cx,cy)); | |
| const es=[];for(let a=0;a<64;a++)for(let b=a+1;b<64;b++){const x=a^b; | |
| if((x&(x-1))===0)es.push([a,b]);} | |
| es.sort((u,v)=>(P[u[0]][2]+P[u[1]][2])-(P[v[0]][2]+P[v[1]][2])); | |
| for(const[a,b]of es){ | |
| if(a===missing||b===missing) continue; | |
| const A=P[a],B=P[b],depth=ss((( (P[a][2]+P[b][2])/2)+3.5)/7); | |
| g.strokeStyle=`rgba(120,110,200,${0.1+0.35*depth})`;g.lineWidth=0.6+1.1*depth; | |
| g.beginPath();g.moveTo(A[0],A[1]);g.lineTo(B[0],B[1]);g.stroke(); | |
| } | |
| for(let e=0;e<64;e++){ | |
| const Pi=P[e],depth=ss((Pi[2]+3.5)/7); | |
| if(e===missing){ | |
| const pulse=0.5+0.5*Math.sin(now*0.006); | |
| g.strokeStyle=`rgba(255,80,80,${0.5+0.5*pulse})`;g.lineWidth=2.2; | |
| const r=9+5*pulse; | |
| g.beginPath();g.arc(Pi[0],Pi[1],r,0,7);g.stroke(); | |
| g.beginPath();g.moveTo(Pi[0]-r*0.7,Pi[1]-r*0.7);g.lineTo(Pi[0]+r*0.7,Pi[1]+r*0.7); | |
| g.moveTo(Pi[0]+r*0.7,Pi[1]-r*0.7);g.lineTo(Pi[0]-r*0.7,Pi[1]+r*0.7);g.stroke(); | |
| g.fillStyle="rgba(255,120,120,0.95)";g.font="12px Consolas,monospace"; | |
| g.textAlign="center";g.fillText("missing corner",Pi[0],Pi[1]-r-6); | |
| continue; | |
| } | |
| g.fillStyle=`hsla(258,80%,${40+depth*22}%,${0.5+0.4*depth})`; | |
| g.beginPath();g.arc(Pi[0],Pi[1],(2+3*depth)*Pi[3],0,7);g.fill(); | |
| } | |
| } | |
| resize();updateHUD();requestAnimationFrame(draw); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment