// Splash — LIGHT-THEME variant (cream paper substrate, dark gold accents). // // Same cinematic beats as the dark version, color-inverted for the bright // tablet experience: ignition → cosmos → particles converge to the LOGO IMAGE // pixel positions → real client logo materialises over the constellation → // subtitle → venus credit → warp out into the EXPLORE puzzle. // // The dark version is preserved verbatim at `splash-dark.jsx` if you ever // want to switch back — just swap the script tag in the HTML. // // Particles sample the actual `universe-logo-transparent.png` so the // constellation traces the real client logo silhouette before the image // itself fades in. function ensureSplashKeys() { if (document.getElementById('splash-light-keys')) return; const s = document.createElement('style'); s.id = 'splash-light-keys'; s.textContent = ` @keyframes spOrbitSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes spOrbitSpinRev { from { transform: rotate(0deg); } to { transform: rotate(-360deg); } } @keyframes spHudPulse { 0%,100% { opacity: 0.55; } 50% { opacity: 0.95; } } @keyframes spDotBreatheLight { 0%,100% { transform: scale(1); filter: drop-shadow(0 0 14px rgba(176,138,63,0.65)); } 50% { transform: scale(1.18); filter: drop-shadow(0 0 28px rgba(176,138,63,0.92)); } } `; document.head.appendChild(s); } // Logo display geometry inside the canvas (2560×1600). Centred slightly above middle. const LOGO_W = 720; const LOGO_H = LOGO_W * (787/1400); // ≈ 405 const LOGO_CX = 1280; const LOGO_CY = 760; const LOGO_LFT = LOGO_CX - LOGO_W/2; const LOGO_TOP = LOGO_CY - LOGO_H/2; function Splash() { const t = useLoop(); const [navigated, setNavigated] = React.useState(false); // Sample logo image pixels → particle target positions in canvas coords. const [logoTargets, setLogoTargets] = React.useState(null); React.useEffect(() => { ensureSplashKeys(); const img = new Image(); img.onload = () => { const cv = document.createElement('canvas'); cv.width = img.naturalWidth; cv.height = img.naturalHeight; const ctx = cv.getContext('2d'); ctx.drawImage(img, 0, 0); const data = ctx.getImageData(0, 0, cv.width, cv.height).data; const stride = 7; const out = []; for (let y = 0; y < cv.height; y += stride) { for (let x = 0; x < cv.width; x += stride) { const a = data[(y * cv.width + x) * 4 + 3]; if (a > 180) { out.push({ x: LOGO_LFT + (x / cv.width) * LOGO_W, y: LOGO_TOP + (y / cv.height) * LOGO_H, }); } } } for (let i = out.length - 1; i > 0; i--) { const j = (Math.random() * (i + 1)) | 0; [out[i], out[j]] = [out[j], out[i]]; } setLogoTargets(out); }; img.src = 'assets/brand/universe-logo-transparent.png'; }, []); React.useEffect(() => { // Once the splash settles, hand off to the EXPLORE puzzle screen. const id = setTimeout(() => { setNavigated(true); navigate('explore'); }, 7800); return () => clearTimeout(id); }, []); // ---------- timing schedule ---------- const ignite = clamp((t - 0.0) / 0.5); const bloomFlash = clamp((t - 0.45)/0.18) * (1 - clamp((t - 0.63)/0.5)); const cosmosP = clamp((t - 0.6) / 1.2); const horizonP = clamp((t - 0.7) / 1.1); const hudP = clamp((t - 1.0) / 1.0); const convergeP = clamp((t - 1.8) / 1.4); const bracketsP = clamp((t - 2.2) / 0.6) * (1 - clamp((t - 3.6)/0.6)); const ringsP = clamp((t - 2.6) / 1.0); const logoP = clamp((t - 3.4) / 1.2); const dispersP = clamp((t - 4.2) / 0.9); const subP = clamp((t - 4.7) / 0.9); const credP = clamp((t - 5.4) / 1.0); const warpP = clamp((t - 7.1) / 0.7); const fade = navigated ? clamp((t - 7.3) / 0.5) : 0; // ---------- particle field ---------- const N = 220; const particles = React.useMemo(() => Array.from({length:N}).map((_,i) => { const a = (i * 137.5) * Math.PI / 180; const r = 520 + (i*47 % 980); return { ox: LOGO_CX + Math.cos(a) * r, oy: LOGO_CY + Math.sin(a) * r * 0.7, seed: i, r: 0.6 + (i%4) * 0.45, }; }), []); const targetFor = (p, i) => { if (logoTargets && logoTargets.length) { return logoTargets[i % logoTargets.length]; } const a = (i * 137.5) * Math.PI / 180; return { x: LOGO_CX + Math.cos(a)*60, y: LOGO_CY + Math.sin(a)*60 }; }; const positions = particles.map((p, i) => { const tgt = targetFor(p, i); let cx, cy; if (t < 1.8) { const k = clamp((t - 0.6) / 1.2); const baseX = lerp(p.ox + (p.seed%7)*8, p.ox + Math.sin(t*0.7 + p.seed)*22, k); const baseY = lerp(p.oy + (p.seed%5)*6, p.oy + Math.cos(t*0.6 + p.seed)*18, k); cx = baseX; cy = baseY; } else if (t < 3.2) { const k = ease.inOutCubic((t - 1.8) / 1.4); cx = lerp(p.ox, tgt.x, k); cy = lerp(p.oy, tgt.y, k); } else if (t < 4.2) { cx = tgt.x + Math.sin(t*1.6 + p.seed) * 1.6; cy = tgt.y + Math.cos(t*1.4 + p.seed) * 1.6; } else { const k = ease.outQuart(dispersP); const a = Math.atan2(tgt.y - LOGO_CY, tgt.x - LOGO_CX) + (p.seed%7)*0.07; const dx = tgt.x + Math.cos(a) * 220 * k; const dy = tgt.y + Math.sin(a) * 220 * k; cx = dx; cy = dy; } return { x: cx, y: cy, r: p.r, seed: p.seed }; }); const streaks = (t > 1.8 && t < 3.2) ? particles.map((p, i) => { const tgt = targetFor(p, i); const k = ease.inOutCubic((t - 1.8) / 1.4); const cx = lerp(p.ox, tgt.x, k); const cy = lerp(p.oy, tgt.y, k); const back = Math.max(0, k - 0.12); const bx = lerp(p.ox, tgt.x, back); const by = lerp(p.oy, tgt.y, back); return { x1: bx, y1: by, x2: cx, y2: cy, op: (1 - Math.abs(k - 0.5) * 1.4) * 0.55 }; }) : []; const particleAlpha = 1 - logoP * 0.55; const tw = (text, p) => text.slice(0, Math.round(text.length * clamp(p))); const warpScale = 1 + warpP * 0.42; // === LIGHT theme palette ================================================ const PARTICLE_COL = '#b08a3f'; // dark gold dots on cream const STREAK_COL = '#c9a05e'; const LINE_COL = '#b08a3f'; const HUD_COL = 'rgba(10,10,10,0.55)'; const HUD_DOT = '#b08a3f'; return (
{/* warm vignette — soft cream rim around an even brighter centre */}
{/* gold core glow that intensifies as logo materialises */}
{/* pre-ignition pulse — a single dark-gold dot pulsing where the logo will appear */} {t < 0.7 && (
)} {/* bloom flash at ignition — cream burst over paper */}
{/* horizon split line — dark gold across the page */}
{/* particles + connecting web + convergence streaks */} {t < 3.4 && positions.map((a,i) => positions.slice(i+1, i+12).map((b,j) => { const d = Math.hypot(a.x-b.x, a.y-b.y); if (d > 110) return null; return ; }))} {streaks.map((s,i) => ( ))} {positions.map((p,i) => ( ))} {/* orbital tick rings */} {[0,1,2].map(i => { const radius = 320 + i*88; const ticks = 60 + i*12; return ( {Array.from({length: ticks}).map((_,k) => { const a = (k / ticks) * Math.PI * 2; const major = k % 10 === 0; const inner = radius - (major ? 11.5 : 5); const outer = radius + (major ? 4 : 2); return ; })} ); })} {/* crosshair targeting brackets framing the logo */} {(() => { const rW = LOGO_W/2 + 63; const rH = LOGO_H/2 + 84; const tip = 38 * bracketsP; const op = bracketsP; const corners = [ [LOGO_CX - rW, LOGO_CY - rH], [LOGO_CX + rW, LOGO_CY - rH], [LOGO_CX - rW, LOGO_CY + rH], [LOGO_CX + rW, LOGO_CY + rH] ]; return corners.map(([x,y], i) => { const sx = i%2 === 0 ? 1 : -1; const sy = i < 2 ? 1 : -1; return ( ); }); })()} {/* === REAL LOGO — monogram (gold) stacked over wordmark (black) === */}
{/* subtitle below the logo */}
{tw('NEHRU NAGAR · AHMEDABAD · MMXXVI', subP)}  
{/* === VENUS CREDIT === */}
A Venus Group of Companies project
35 years of timeless spaces
{/* === CORNER HUD CHROME === */} {(() => { const tlText = 'SALES SUITE · v1.0 · MMXXVI'; const trText = 'LAT 23.0225° N · LON 72.5714° E'; const blText = 'SEQ ∙ 0042 · TR-A1 · NEHRU NAGAR'; const baseSty = {fontSize:14, letterSpacing:'0.32em', color:HUD_COL, textTransform:'uppercase', whiteSpace:'nowrap'}; return ( <>
{tw(tlText, hudP)}
{tw(trText, hudP)}
{tw(blText, hudP)}
); })()}
{/* exit flash — cream burst into the explore puzzle */} {warpP > 0 && (
)} {/* skip CTA — explicit Explore handoff */}
); } window.Splash = Splash;