// anim-prism.jsx — Variation 1: Prisma // A thin white beam enters from the left, hits a prism point, fans into the // visible spectrum. The magenta wavelength isolates and 3 beams of magenta // tones converge into the M. Tagline + breath loop. const PrismAnim = ({ t, duration }) => { // local helpers const clamp01 = (v) => Math.max(0, Math.min(1, v)); const easeOut = (x) => 1 - Math.pow(1 - x, 3); const easeIn = (x) => x * x * x; const easeIO = (x) => x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2; const lerp = (a, b, x) => a + (b - a) * x; const seg = (t0, t1, te = easeIO) => te(clamp01((t - t0) / (t1 - t0))); // Phases (5.4s total — last 0.4s blends into loop start for seamless loop) const TBeamDraw = seg(0.10, 1.10, easeOut); // beam draws in const TPrismHit = seg(1.00, 1.40, easeOut); // prism dot flares const TFan = seg(1.20, 2.40, easeOut); // spectrum fans out const TIsolate = seg(2.30, 3.10, easeIO); // other colors fade, magenta isolates const TConverge = seg(2.80, 3.60, easeIO); // magenta beams converge to M position const TReveal = seg(3.40, 4.10, easeOut); // M materializes via wipe const TFlash = seg(3.90, 4.30, easeOut); // bright flash on lock const TTagline = seg(4.20, 4.80, easeOut); // tagline fades in const breath = 0.5 + 0.5 * Math.sin(t / duration * Math.PI * 2 * 1); // 1 cycle/loop const subtleBreath = 1 - 0.03 * Math.max(0, Math.sin((t - 4.5) * Math.PI / 0.8)); // Loop crossfade: last 0.35s fades opacity of whole pulsing piece into start const loopFade = clamp01((duration - t) / 0.35); // Geometry — centered on canvas const CX = 960,CY = 540; const M_W = 520, M_H = 283; // Use % + translate so centering is bulletproof regardless of parent layout quirks. // Vertical offset: pull up so M+tagline group reads as balanced around canvas center. const M_TOP_PCT = 38; // y center as % of stage height (38% → above middle) // Spectrum band colors (red→violet) with magentas added const bands = [ { h: '#ff2d4a', label: 'R' }, { h: '#ff7a1a', label: 'O' }, { h: '#ffd60a', label: 'Y' }, { h: '#34d399', label: 'G' }, { h: '#38bdf8', label: 'C' }, { h: '#6366f1', label: 'B' }, { h: '#a855f7', label: 'V' }]; // Beam parameters const beamStartX = -100; const beamEndX = CX - 6; // stops just before prism point const beamY = CY; const beamLen = lerp(0, beamEndX - beamStartX, TBeamDraw); const beamTipX = beamStartX + beamLen; // Prism dot scale / glow const prismScale = 0.2 + 1.6 * TPrismHit - 0.4 * TFan; // flares then settles const prismOpacity = clamp01(TPrismHit - TFan * 0.6); // Spectrum fan: each band is a long thin gradient at an angle const fanLen = lerp(0, 1600, TFan); const fanOpacity = lerp(0, 1, TFan) * (1 - TIsolate * 0.85); // Magenta isolation: 3 beams (the three M tones) converging on M strokes const magenta3 = [ { color: '#7a1b54', angle: -10, label: 'plum' }, // dark plum { color: '#c66689', angle: 0, label: 'pink' }, // mid pink { color: '#e6217a', angle: 10, label: 'hot' } // hot magenta ]; // M wipe progress — vertical sweep from bottom-up reveal using clip-path const wipeAmt = TReveal; // 0..1 // clip-path inset from top: visible portion grows from bottom up const wipeInset = (1 - wipeAmt) * 100; // Flash opacity (white fullscreen flash on lock) const flashOpacity = TFlash * (1 - TFlash * 0.85); // Final logo opacity & glow pulse (after reveal) const logoVisible = clamp01((t - 3.4) / 0.35); const finalPulse = t > 4.2 ? 0.85 + 0.15 * Math.sin((t - 4.2) * 2 * Math.PI / 1.4) : 0; return (