From 97f3bf2c2070dfba4176c69384f936dd53a9b33f Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 6 Apr 2026 01:44:36 +0800 Subject: [PATCH] fix: tune granular splat reveal timing --- components/canvas/world3d/World3DViewer.tsx | 51 ++++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/components/canvas/world3d/World3DViewer.tsx b/components/canvas/world3d/World3DViewer.tsx index d158a8840..33e0e90ec 100644 --- a/components/canvas/world3d/World3DViewer.tsx +++ b/components/canvas/world3d/World3DViewer.tsx @@ -104,10 +104,10 @@ const SPLAT_LOADING_PROFILE: SparkRevealProfile = { const SPLAT_PARTICLE_PROFILE: SparkRevealProfile = { blurAmount: 0.01, preBlurAmount: 0, - minAlpha: 0.19, - maxStdDev: Math.sqrt(2.2), - focalAdjustment: 2.35, - falloff: 0.2, + minAlpha: 0.28, + maxStdDev: Math.sqrt(1.45), + focalAdjustment: 3.05, + falloff: 0.08, opacity: 1, }; @@ -155,6 +155,8 @@ function lerpSparkRevealProfile( }; } +const SPLAT_REVEAL_DURATION_MS = 2600; + const KEY_TO_MOVEMENT: Partial> = { KeyW: "forward", ArrowUp: "forward", @@ -582,23 +584,38 @@ function WorldSplatScene({ const phase = revealPhaseRef.current; const revealElapsed = phase === "revealing" - ? Math.min((performance.now() - revealStartedAtRef.current) / 1650, 1) + ? Math.min((performance.now() - revealStartedAtRef.current) / SPLAT_REVEAL_DURATION_MS, 1) : 0; - const easedReveal = 1 - Math.pow(1 - revealElapsed, 3); + const easedReveal = THREE.MathUtils.smoothstep(revealElapsed, 0, 1); if (phase === "loading") { applySparkRevealProfile(sparkRenderer, splatMesh, SPLAT_LOADING_PROFILE); } else if (phase === "revealing") { - const particleHold = 0.32; - const granularProgress = - easedReveal <= particleHold - ? 0 - : (easedReveal - particleHold) / (1 - particleHold); - const profile = lerpSparkRevealProfile( - SPLAT_PARTICLE_PROFILE, - SPLAT_NORMAL_PROFILE, - THREE.MathUtils.smoothstep(granularProgress, 0, 1) - ); + const particleIntroEnd = 0.2; + const particleHoldEnd = 0.6; + let profile = SPLAT_PARTICLE_PROFILE; + + if (easedReveal < particleIntroEnd) { + profile = lerpSparkRevealProfile( + SPLAT_LOADING_PROFILE, + SPLAT_PARTICLE_PROFILE, + THREE.MathUtils.smoothstep(easedReveal / particleIntroEnd, 0, 1) + ); + } else if (easedReveal < particleHoldEnd) { + const pulse = Math.sin((performance.now() - revealStartedAtRef.current) * 0.008) * 0.02; + profile = { + ...SPLAT_PARTICLE_PROFILE, + minAlpha: SPLAT_PARTICLE_PROFILE.minAlpha + pulse, + focalAdjustment: SPLAT_PARTICLE_PROFILE.focalAdjustment + pulse * 2.4, + }; + } else { + const granularProgress = (easedReveal - particleHoldEnd) / (1 - particleHoldEnd); + profile = lerpSparkRevealProfile( + SPLAT_PARTICLE_PROFILE, + SPLAT_NORMAL_PROFILE, + THREE.MathUtils.smoothstep(granularProgress, 0, 1) + ); + } applySparkRevealProfile(sparkRenderer, splatMesh, profile); } else { applySparkRevealProfile(sparkRenderer, splatMesh, SPLAT_NORMAL_PROFILE); @@ -757,7 +774,7 @@ function WorldSplatViewer({ setOverlayPhase("revealing"); const timer = window.setTimeout(() => { setOverlayPhase("hidden"); - }, 1650); + }, SPLAT_REVEAL_DURATION_MS); return () => window.clearTimeout(timer); }