feat(frontend): cinematic 3D landing page overhaul + page transitions#63
Conversation
Rebuild the landing page around a fully procedural react-three-fiber
scene (no binary assets) and bring every section up to a cohesive,
premium bar.
- HeroExperience: procedural r3f scene (distorted glowing AI core,
frosted-glass document panels, metallic solids, Sparkles particles,
Lightformer environment). Pointer parallax, reduced-motion safe.
WebGL capability detection + error boundary + CSS fallback, software
rendering allowed, and a low-power tier (fewer objects, no shadows/AA,
cheaper materials) for limited-graphics devices. Lighter "cta" variant
pauses its render loop when off-screen.
- LandingPage: full-bleed cinematic hero, floating stats band, numbered
pillars, dark spotlight, bento features, connected stepper workflow,
comparison, dual auto-marquee, use cases, workspace/privacy, accordion
FAQ, and a dark 3D CTA bookend. Fraunces display serif + eyebrow labels
+ rounded icon tiles. Italic gradient headline padding fix; accordion
hover tint (overrides global red) and tighter expanded spacing.
- App: app-wide page transitions (rise/fade in, descend/fade out) driven
by AppLayout, synced with scroll-to-top and navbar visibility, with a
reduced-motion bypass and animationend + timeout fallback.
- CTAs ("Start for free" / "Get Started") now route to /register.
- Add three, @react-three/fiber@8, @react-three/drei@9 (React 18).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
✅ Deploy Preview for docuthinker-ai-app ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Keep the background unchanged on hover (transparent) so the app-wide button:hover red never shows and there is no hover tint at all. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces a procedural 3D WebGL hero experience using React Three Fiber and adds animated page transitions to the frontend, along with associated Three.js dependencies and CSS styles. The feedback highlights three key issues: a bug in the route transition logic where query parameter or hash changes on the same pathname fail to update the rendered location; a performance bottleneck in the 3D scene where the environment map is unnecessarily re-rendered every frame; and a material configuration issue where combining transparency and physical transmission on the document panels can cause depth sorting anomalies.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| useEffect(() => { | ||
| if (location.pathname === displayLocation.pathname) return undefined; |
There was a problem hiding this comment.
When the user navigates to a URL with the same pathname but different query parameters (e.g., ?tab=1 to ?tab=2) or hash, location.pathname === displayLocation.pathname evaluates to true, causing the effect to return early. Because displayLocation is never updated to the new location object, the child routes and components will not receive the updated search/hash parameters and will fail to re-render. To fix this, we should immediately update displayLocation to the new location when the pathname is the same but the location object itself has changed, bypassing the page transition.
useEffect(() => {
if (location.pathname === displayLocation.pathname) {
if (location !== displayLocation) {
setDisplayLocation(location);
}
return undefined;
}| <Environment | ||
| resolution={lowPower ? 128 : 256} | ||
| frames={reduceMotion || lowPower ? 1 : Infinity} | ||
| > |
There was a problem hiding this comment.
The <Environment> component is configured with frames={reduceMotion || lowPower ? 1 : Infinity}. When frames is set to Infinity, the environment map (which renders the child <Lightformer> components into a cube map) is updated every single frame. Since the lightformers in this scene are completely static and do not animate, rendering the environment map every frame is a massive and unnecessary GPU bottleneck that can cause severe frame rate drops and high power consumption. Setting frames={1} will render the environment map once on mount and reuse it, significantly improving performance.
| <Environment | |
| resolution={lowPower ? 128 : 256} | |
| frames={reduceMotion || lowPower ? 1 : Infinity} | |
| > | |
| <Environment | |
| resolution={lowPower ? 128 : 256} | |
| frames={1} | |
| > |
| <meshPhysicalMaterial | ||
| color={PALETTE.panel} | ||
| transmission={0.94} | ||
| thickness={0.6} | ||
| roughness={0.12} | ||
| ior={1.4} | ||
| metalness={0} | ||
| clearcoat={1} | ||
| clearcoatRoughness={0.15} | ||
| attenuationColor={PALETTE.attenuation} | ||
| attenuationDistance={1.6} | ||
| transparent | ||
| opacity={0.92} | ||
| /> |
There was a problem hiding this comment.
For transmissive materials in Three.js, setting transparent={true} and a fractional opacity alongside transmission is generally discouraged. Physical transmission handles its own transparency and refraction pass internally. Forcing the material into the transparent queue by setting transparent={true} can cause severe depth sorting issues (e.g., overlapping panels or particles like <Sparkles> rendering in the wrong order) and makes the glass look washed out. Removing transparent and opacity allows the physical transmission shader to render the frosted glass effect correctly and robustly.
<meshPhysicalMaterial
color={PALETTE.panel}
transmission={0.94}
thickness={0.6}
roughness={0.12}
ior={1.4}
metalness={0}
clearcoat={1}
clearcoatRoughness={0.15}
attenuationColor={PALETTE.attenuation}
attenuationDistance={1.6}
/>The earlier --legacy-peer-deps install left package-lock.json missing transitive entries (@testing-library/dom, typescript, webrtc-adapter, sdp, form-data, @types/node-fetch, aria-query), breaking `npm ci`. Regenerated a full, consistent lockfile; `npm ci` now succeeds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Summary
Rebuilds the landing page around a fully procedural react-three-fiber scene (no binary assets — every shape/material/light is generated in code) and lifts every section to a cohesive, premium bar. Adds app-wide page transitions and routes the primary CTAs to sign-up.
What changed
3D scene —
frontend/src/components/three/HeroExperience.js(new)Sparklesparticles,Lightformerenvironment (no.hdr/.glb/font files).prefers-reduced-motionfreezes animation.failIfMajorPerformanceCaveat: false(allows software/SwiftShader); low-power tier (fewer objects, no shadows/AA, cheaper translucent material); context-loss kept recoverable.ctavariant pauses its render loop when off-screen (IntersectionObserver).Landing page —
frontend/src/pages/LandingPage.jsbutton:hoverred; tighter expanded accordion spacing./register.App-wide transitions —
frontend/src/App.js+frontend/src/index.cssAppLayout(displayLocationlagslocationby one exit), synced with scroll-to-top + navbar visibility,animationend+ timeout-fallback swap, reduced-motion bypass.Deps:
three,@react-three/fiber@8,@react-three/drei@9(React 18 compatible). three.js is lazy-loaded into a separate chunk.Verification
npm run build— compiles clean (only a harmless@mediapipe/tasks-visionsource-map warning from a drei transitive dep).jest— 6 suites, 35/35 pass./register.🤖 Generated with Claude Code