memoscan
← all memos

Memo 0x48b63845…f65c04 on Ethereum

0xc485e340…8dfd·#25,809,447·view on Etherscan
const IP_STATE = window.INFLECTION_POINTS || {}; const SEED_SAFE = Number.isFinite(Number(IP_STATE.seed)) ? Number(IP_STATE.seed) : Number.isFinite(Number(IP_STATE.tokenId)) ? Number(IP_STATE.tokenId) : 1; function makeRng(seed) { // deterministic PRNG (mulberry32) let t = seed >>> 0; return function () { t += 0x6D2B79F5; let x = t; x = Math.imul(x ^ (x >>> 15), x | 1); x ^= x + Math.imul(x ^ (x >>> 7), x | 61); return ((x ^ (x >>> 14)) >>> 0) / 4294967296; }; } function mix32(x) { x >>>= 0; x ^= x >>> 16; x = Math.imul(x, 0x7feb352d); x ^= x >>> 15; x = Math.imul(x, 0x846ca68b); x ^= x >>> 16; return x >>> 0; } function randRange(rng, a, b) { return a + (b - a) * rng(); } (() => { const svgArt = document.querySelector("#art"); if (!svgArt) return; // Keep blink-slow safe without relying on contract-injected CSS variables. document.documentElement.style.setProperty("--ric-blink-slow", "0.8s"); const rng = makeRng(SEED_SAFE); const toMaskedGroup = (el) => el?.closest?.('g[data-ric-layer]'); const toAnimGroup = (el) => el?.closest?.('g.g-to'); const normalizeBlink = (value) => String(value || "").trim().toLowerCase(); // foreignObjects live under: outer g[data-ric-layer] > inner g.g-to > foreignObject const allFOs = Array.from(svgArt.querySelectorAll(":scope > g[data-ric-layer] > g.g-to > foreignObject")); const allAnimGroups = Array.from(new Set(allFOs.map(toAnimGroup).filter(Boolean))); const allOuterGroups = Array.from( document.querySelectorAll("#art > g[data-ric-layer]") ); const fastTargets = allOuterGroups.filter((g) => normalizeBlink(g.getAttribute("data-blink")) === "fast" ); const slowTargets = allOuterGroups.filter((g) => normalizeBlink(g.getAttribute("data-blink")) === "slow" ); // Optional future role; old v3 kinds are only a fallback and do not affect current Inflection layers. const outlineGroups = Array.from( new Set( allFOs .filter((fo) => { const outer = toMaskedGroup(fo); const role = normalizeBlink(outer?.getAttribute("data-phase-role")); if (role === "outline") return true; return !!fo.querySelector( '[data-kind="outline"], [data-kind="outline2"], [data-kind="mouth"], [data-kind="eyes"]' ); }) .map(toAnimGroup) .filter(Boolean) ) ); const phase3Targets = allAnimGroups.filter((g) => !outlineGroups.includes(g)); const originalOrder = allOuterGroups.slice(); const originalIndex = new Map(originalOrder.map((g, i) => [g, i])); let phase = 3; let transitioning = false; function clearBlinks() { fastTargets.forEach((el) => { el.classList.remove("blink-fast"); el.style.animationDelay = ""; }); slowTargets.forEach((el) => { el.classList.remove("blink-slow"); el.style.animationDelay = ""; }); } function forceRestartAnimation(el) { el.classList.remove("phase3-unfold", "phase3-return", "phase3-outline", "phase3-outline-return"); el.style.animation = "none"; void el.offsetWidth; // force reflow el.style.animation = ""; } function clearPhase3Vars(g) { g.style.transform = ""; g.style.animationDelay = ""; g.style.removeProperty("--toCx"); g.style.removeProperty("--toCy"); g.style.removeProperty("--outDx"); g.style.removeProperty("--outDy"); g.style.removeProperty("--rot"); g.style.removeProperty("--dur"); g.style.removeProperty("--delay"); g.style.removeProperty("--s"); g.style.removeProperty("--retDur"); } function clearOutlineVars(g) { g.style.transform = ""; g.style.animationDelay = ""; g.style.removeProperty("--outlineDur"); g.style.removeProperty("--outlineDelay"); g.style.removeProperty("--outlineRetDur"); g.style.removeProperty("--rotSign"); } function clearPhase3All() { phase3Targets.forEach((g) => { g.classList.remove("phase3-unfold", "phase3-return"); clearPhase3Vars(g); }); outlineGroups.forEach((g) => { g.classList.remove("phase3-outline", "phase3-outline-return"); clearOutlineVars(g); }); } function bringOutlinesToFront() { const outlineOuterGroups = Array.from( new Set(outlineGroups.map(toMaskedGroup).filter(Boolean)) ); outlineOuterGroups.forEach((g) => svgArt.appendChild(g)); } async function restoreOriginalOrder(stepMs = 18) { const current = Array.from(svgArt.querySelectorAll(':scope > g[data-ric-layer]')) .sort((a, b) => (originalIndex.get(a) ?? 1e9) - (originalIndex.get(b) ?? 1e9)); for (const g of current) { svgArt.appendChild(g); if (stepMs > 0) await new Promise((r) => setTimeout(r, stepMs)); } } function setupPhase3ForFO(group, baseSeed, index, centerX = 400, centerY = 400) { const childFO = group?.querySelector?.("foreignObject") || group; const localSeed = mix32((baseSeed >>> 0) ^ mix32(index + 1)); const r = makeRng(localSeed); let bx, by, bw, bh; try { const bb = childFO.getBBox(); bx = bb.x; by = bb.y; bw = bb.width; bh = bb.height; } catch { bx = parseFloat(childFO.getAttribute("x")) || 0; by = parseFloat(childFO.getAttribute("y")) || 0; bw = parseFloat(childFO.getAttribute("width")) || 0; bh = parseFloat(childFO.getAttribute("height")) || 0; } const cx = bx + bw / 2; const cy = by + bh / 2; const toCx = centerX - cx; const toCy = centerY - cy; const ang = randRange(r, 0, Math.PI * 2); const dist = randRange(r, 120, 340); const outDx = Math.cos(ang) * dist; const outDy = Math.sin(ang) * dist; const dir = r() < 0.5 ? -1 : 1; const rotDeg = dir * randRange(r, 120, 520); const dur = randRange(r, 1.2, 2.4); const delay = randRange(r, 0.0, 0.45); group.style.setProperty("--toCx", `${toCx.toFixed(2)}px`); group.style.setProperty("--toCy", `${toCy.toFixed(2)}px`); group.style.setProperty("--outDx", `${outDx.toFixed(2)}px`); group.style.setProperty("--outDy", `${outDy.toFixed(2)}px`); group.style.setProperty("--rot", `${rotDeg.toFixed(1)}deg`); group.style.setProperty("--dur", `${dur.toFixed(2)}s`); group.style.setProperty("--delay", `${delay.toFixed(2)}s`); group.classList.add("phase3-unfold"); } function startPhase3() { clearBlinks(); svgArt && svgArt.classList.add("phase3-active"); phase3Targets.forEach(forceRestartAnimation); outlineGroups.forEach(forceRestartAnimation); bringOutlinesToFront(); outlineGroups.forEach((g) => { const outer = toMaskedGroup(g); const role = normalizeBlink(outer?.getAttribute("data-phase-role")); const isReverse = role === "outline-reverse" || !!g.querySelector('[data-kind="outline2"]'); g.style.setProperty("--rotSign", isReverse ? "-1" : "6"); g.style.setProperty("--outlineDur", `${randRange(rng, 0.7, 1.05).toFixed(2)}s`); g.style.setProperty("--outlineDelay", `${randRange(rng, 0.0, 0.15).toFixed(2)}s`); g.classList.add("phase3-outline"); }); phase3Targets.forEach((g, i) => setupPhase3ForFO(g, SEED_SAFE, i, 400, 400)); } function startReturnToBase(thenPhase1 = true, after = null) { clearBlinks(); svgArt && svgArt.classList.remove("phase3-active"); outlineGroups.forEach((g) => { forceRestartAnimation(g); g.style.setProperty("--outlineRetDur", `${randRange(rng, 0.65, 0.9).toFixed(2)}s`); g.classList.add("phase3-outline-return"); }); phase3Targets.forEach((g) => { forceRestartAnimation(g); g.style.setProperty("--retDur", `${randRange(rng, 0.85, 1.15).toFixed(2)}s`); g.classList.add("phase3-return"); }); const RETURN_MS = 1250; restoreOriginalOrder(20); window.setTimeout(() => { clearPhase3All(); if (typeof after === "function") { after(); return; } if (thenPhase1) { fastTargets.forEach((el, i) => { el.style.animationDelay = `${i * 0.1}s`; el.classList.add("blink-fast"); }); } }, RETURN_MS); } function applyPhase(p) { clearBlinks(); clearPhase3All(); if (p === 0) return; requestAnimationFrame(() => { if (p === 1) { fastTargets.forEach((el, i) => { el.style.animationDelay = `${i * 0.1}s`; el.classList.add("blink-fast"); }); return; } if (p === 2) { fastTargets.forEach((el, i) => { el.style.animationDelay = `${i * 0.1}s`; el.classList.add("blink-fast"); }); slowTargets.forEach((el, i) => { el.style.animationDelay = `${i * 0.05}s`; el.classList.add("blink-slow"); }); return; } if (p === 3) { fastTargets.forEach((el, i) => { el.style.animationDelay = `${i * 0.1}s`; el.classList.add("blink-fast"); }); startPhase3(); } }); } function gotoPhase(next) { next = Math.max(0, Math.min(3, Number(next) || 0)); if (transitioning) return; const prev = phase; if (next === prev) return; if (prev === 3 && next !== 3) { phase = next; setActiveButton(); transitioning = true; startReturnToBase(false, () => { transitioning = false; applyPhase(next); setActiveButton(); }); return; } phase = next; applyPhase(next); setActiveButton(); } function setActiveButton() { const panel = document.getElementById("phasePanel"); if (!panel) return; panel.querySelectorAll("button[data-phase]").forEach((btn) => { const p = parseInt(btn.getAttribute("data-phase"), 10); btn.classList.toggle("active", p === phase); }); } applyPhase(phase); setActiveButton(); window.gotoPhase = gotoPhase; function handleArtworkTap(ev) { if (ev.target && ev.target.closest && ev.target.closest("#phasePanel")) return; ev.preventDefault?.(); gotoPhase((phase + 1) % 4); } if (window.PointerEvent) { document.addEventListener("pointerup", handleArtworkTap, { passive: false }); } else { document.addEventListener("touchend", handleArtworkTap, { passive: false }); } (function initPhasePanel() { const panel = document.getElementById("phasePanel"); if (!panel) return; const toggle = document.getElementById("phasePanelToggle"); const collapse = (collapsed) => { panel.classList.toggle("collapsed", collapsed); if (toggle) toggle.textContent = collapsed ? "▶" : "◀"; }; collapse(false); let hideTimer = window.setTimeout(() => collapse(true), 10000); const resetAutoHide = () => { window.clearTimeout(hideTimer); hideTimer = window.setTimeout(() => collapse(true), 10000); }; toggle && toggle.addEventListener("click", (e) => { e.stopPropagation(); const isCollapsed = panel.classList.contains("collapsed"); collapse(!isCollapsed); resetAutoHide(); }); panel.querySelectorAll("button[data-phase]").forEach((btn) => { btn.addEventListener("click", (e) => { e.stopPropagation(); const p = parseInt(btn.getAttribute("data-phase"), 10); gotoPhase(p); resetAutoHide(); }); }); setActiveButton(); })(); window.addEventListener("DOMContentLoaded", () => { document.documentElement.classList.remove("ready"); const revealTargets = Array.from( document.querySelectorAll("#art foreignObject") ); document.documentElement.classList.add("ready"); revealTargets.forEach((fo, i) => { fo.classList.add("reveal"); fo.style.animationDelay = `${i * 0.1}s`; fo.addEventListener( "animationend", () => { fo.classList.remove("reveal"); fo.style.animation = ""; fo.style.animationDelay = ""; }, { once: true } ); }); }); })(); </script> </body> </html>