1// selfOS â resonance: everything is a birth. 2// One continuous loop, each transition a birth into a new axis. Two circles 3// converge and the lines bolden into a 12-spoke wheel (the spokes streak inward 4// from rim to hub); it tilts into depth and spins, decelerating to edge-on â a 5// line â which contracts to a point where the star is born in a flash; the 6// star's rays reach out and become the circle of the next chapter. Candlelight 7// on black, additive. (Caption: "The awareness to know what you want, and the 8// focus to achieve it.") 9(function () { 10 const canvas = document.getElementById("resonanceCanvas"); 11 if (!canvas) return; 12 const ctx = canvas.getContext("2d"); 13 const C = (a) => "rgba(255,248,220," + a + ")"; 14 const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; 15 const TAU = Math.PI * 2; 16 let W = 0, H = 0, DPR = 1; 17 18 function resize() { 19 DPR = Math.min(window.devicePixelRatio || 1, 2); 20 const r = canvas.getBoundingClientRect(); 21 W = Math.max(1, r.width); H = Math.max(1, r.height); 22 canvas.width = Math.round(W * DPR); 23 canvas.height = Math.round(H * DPR); 24 } 25 const clamp = (x) => (x < 0 ? 0 : x > 1 ? 1 : x); 26 const ease = (x) => { x = clamp(x); return x * x * (3 - 2 * x); }; 27 const ss = (x) => { x = clamp(x); return x * x * x * (x * (x * 6 - 15) + 10); }; 28 const loc = (t, a, b) => clamp((t - a) / (b - a), 0, 1); 29 30 function ringE(cx, cy, rx, ry, rot, a, lw, glow) { 31 if (a <= 0.004) return; rx = Math.max(0.1, rx); ry = Math.max(0.1, ry); 32 ctx.beginPath(); ctx.ellipse(cx, cy, rx, ry, rot, 0, TAU); 33 ctx.strokeStyle = C(a); ctx.lineWidth = lw; ctx.shadowColor = C(glow); ctx.shadowBlur = 11; ctx.stroke(); 34 } 35 function seg(x1, y1, x2, y2, a, lw) { 36 if (a <= 0.01) return; 37 ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); 38 ctx.strokeStyle = C(a); ctx.lineWidth = lw; ctx.lineCap = "round"; ctx.shadowColor = C(a * 0.8); ctx.shadowBlur = 6; ctx.stroke(); 39 } 40 function dot(x, y, r, a) { 41 if (a <= 0.01) return; 42 ctx.save(); ctx.fillStyle = C(Math.min(1, a)); ctx.shadowColor = C(Math.min(1, a)); ctx.shadowBlur = r * 3.4; 43 ctx.beginPath(); ctx.arc(x, y, r, 0, TAU); ctx.fill(); ctx.restore(); 44 } 45 // 4-point + sparkle flash: fine points, tiny core 46 function sparkle(cx, cy, len, coreR, a) { 47 if (a <= 0.01 || len <= 0.5) return; 48 ctx.save(); ctx.globalCompositeOperation = "lighter"; 49 ctx.fillStyle = C(Math.min(1, a)); ctx.shadowColor = C(Math.min(1, a)); ctx.shadowBlur = coreR * 5; 50 const w = Math.max(0.5, coreR * 0.45); 51 for (let i = 0; i < 4; i++) { 52 ctx.save(); ctx.translate(cx, cy); ctx.rotate(i * Math.PI / 2); 53 ctx.beginPath(); ctx.moveTo(0, -len); ctx.lineTo(w, 0); ctx.lineTo(0, coreR * 0.5); ctx.lineTo(-w, 0); ctx.closePath(); ctx.fill(); 54 ctx.restore(); 55 } 56 ctx.globalAlpha = 0.45; 57 for (let i = 0; i < 4; i++) { 58 ctx.save(); ctx.translate(cx, cy); ctx.rotate((i + 0.5) * Math.PI / 2); 59 ctx.beginPath(); ctx.moveTo(0, -len * 0.5); ctx.lineTo(w * 0.7, 0); ctx.lineTo(0, coreR * 0.4); ctx.lineTo(-w * 0.7, 0); ctx.closePath(); ctx.fill(); 60 ctx.restore(); 61 } 62 ctx.globalAlpha = 1; 63 ctx.beginPath(); ctx.arc(cx, cy, coreR, 0, TAU); ctx.fill(); 64 ctx.restore(); 65 } 66 67 const RA = 0.30, SPIN = 2.5, PULSEK = 1.7, SPINEND = 0.55; 68 69 function render(t) { 70 ctx.setTransform(DPR, 0, 0, DPR, 0, 0); 71 ctx.clearRect(0, 0, W, H); 72 ctx.globalCompositeOperation = "lighter"; 73 const cx = W / 2, cy = H / 2, M = Math.min(W, H); 74 const Rmax = M * 0.46, Rmeet = Rmax * 0.60, sR = M * 0.052; 75 76 const sp = ss(loc(t, 0.12, SPINEND)); 77 const psi = TAU * SPIN * sp; 78 const tilt = (Math.PI / 2) * ease(loc(t, 0.12, SPINEND)); 79 const pulse = ease(loc(t, 0.50, 0.565)) * (1 - ease(loc(t, 0.565, 0.66))) * PULSEK; 80 const contract = ease(loc(t, 0.55, 0.72)); 81 82 const conv = ease(loc(t, 0, 0.12)); 83 let R = (t < 0.12) ? (Rmax - (Rmax - Rmeet) * conv) : Rmeet * (1 - contract); 84 R *= (1 + 0.06 * pulse); 85 const ry = R * Math.cos(tilt); 86 87 // birth of the wheel: the lines breathe bolder as the circles meet 88 const present = ease(loc(t, 0.10, 0.24)); 89 const swell = ease(loc(t, 0.06, 0.12)) * (1 - ease(loc(t, 0.12, 0.27)));
90 const lwMain = 1.1 + 0.5 * present + 0.8 * swell; 91 const aMain = RA + 0.16 * swell; 92 const glowMain = 0.6 + 0.25 * swell; 93 94 if (t < 0.74) { 95 if (ry > 0.8) ringE(cx, cy, R, ry, 0, aMain, lwMain, glowMain); 96 else seg(cx - R, cy, cx + R, cy, RA + 0.6 * pulse, 1.6 + 1.7 * pulse); 97 } 98 // inner converging circle â meets the outer, boldens with it, then merges away 99 if (t < 0.16) { 100 const e = conv, innerFade = 1 - ease(loc(t, 0.105, 0.15)); 101 ringE(cx, cy, Rmeet * e, Rmeet * e, 0, aMain * e * innerFade, 1.1 + 0.8 * swell, glowMain); 102 } 103 // spokes streak inward from the rim to the hub â birth of the radial axis 104 if (t >= 0.12 && t < 0.74) { 105 const grow = ease(loc(t, 0.13, 0.225)); 106 const spokeA = 0.42 * ease(loc(t, 0.13, 0.24)); 107 const dotFade = 1 - ease(loc(t, 0.46, SPINEND)); 108 for (let k = 0; k < 12; k++) { 109 const b = (k / 12) * TAU + psi; 110 const ox = cx + R * Math.cos(b), oy = cy + ry * Math.sin(b); 111 const gx = ox + grow * (cx - ox), gy = oy + grow * (cy - oy); 112 const depth = 0.5 + 0.5 * Math.sin(b); 113 const sel = Math.pow(Math.max(0, Math.sin(b)), 4); 114 seg(ox, oy, gx, gy, spokeA * (0.2 + 0.35 * depth) + sel * 0.5, sel > 0.5 ? 2.4 : 1.2); 115 if (grow > 0.94 && sel > 0.6) dot(ox, oy, sR * 0.26, sel * 0.6 * dotFade); 116 } 117 } 118 119 // birth of the star at the contraction point; its rays reach out and become the circle 120 if (t >= 0.62) { 121 const boom = ease(loc(t, 0.655, 0.73)) * (1 - ease(loc(t, 0.80, 0.93))); 122 const ex = ease(loc(t, 0.73, 0.98)); 123 const len = sR * 1.15 + (Rmax * 0.9 - sR * 1.15) * ex; // rays reach out to the ring 124 sparkle(cx, cy, len, sR * 0.12, Math.min(1, boom + 0.1)); 125 if (t >= 0.78) { 126 const x = ease(loc(t, 0.78, 1.0)); 127 const rbs = ease(loc(t, 0.78, 0.86)) * (1 - ease(loc(t, 0.86, 1.0))); 128 ringE(cx, cy, x * Rmax, x * Rmax, 0, RA * (0.3 + 0.7 * x) + 0.18 * rbs, 1.0 + 0.7 * rbs, 0.6 + 0.3 * rbs); 129 } 130 } 131 } 132 133 const T = 9.5; 134 let t0 = null, raf = null; 135 function loop(ms) { 136 if (t0 === null) t0 = ms; 137 render(((ms - t0) / 1000 % T) / T); 138 raf = requestAnimationFrame(loop); 139 } 140 function startA() { if (raf == null && !reduce) raf = requestAnimationFrame(loop); } 141 function stopA() { if (raf != null) { cancelAnimationFrame(raf); raf = null; } } 142 function still() { render(0.30); } // a representative wheel for reduced motion 143 144 resize(); 145 window.addEventListener("resize", () => { resize(); if (reduce) still(); }); 146 if (reduce) { still(); return; } 147 if ("IntersectionObserver" in window) { 148 new IntersectionObserver((es) => es.forEach((e) => (e.isIntersecting ? startA() : stopA())), { threshold: 0.05 }).observe(canvas); 149 } else startA(); 150})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.