MilWebWhatsApp
Back to projects

Cinematic 3D site for architecture · React Three Fiber

Lumen

Cinematic 3D experiencePersonal project · demo

Problem

Architecture studios need to convey sophistication and spatial mastery, and a plain website doesn't capture the feel of their work.

Solution

Immersive 3D showcase (React Three Fiber) with cinematic scenes and fluid navigation that present the studio as an experience, not a list of photos.

How it was built

The house anchoring the hero isn't an imported model. It's procedural geometry, assembled in code from Three.js primitives (boxGeometry, planeGeometry, icosahedronGeometry): cantilevered slab, glass facade, furniture, pool and landscaping, all placed with explicit coordinates inside a single House component. The reasoning is practical: with no GLB to download, decode (Draco/Meshopt) or host, the hero starts rendering on the Canvas's first frame. The Residence component already leaves the door open to swap in a real model. A RESIDENCE_GLB constant plus a SceneBoundary (a class-based error boundary catching WebGL and R3F failures) guarantee that if the GLB is missing or fails to load, the scene falls back to the procedural house without breaking the page.

The camera doesn't ride an external timeline library. It's a hand-written keyframe system in CameraRig, with six position and lookAt pairs (facade, entrance, living room, staircase, balcony, pool) interpolated with smoothstep against a journey.progress value between 0 and 1. That progress is written by a GSAP ScrollTrigger pinned to the hero section, with Lenis driving the smooth-scroll rAF and emitting events that ScrollTrigger consumes (lenis.on('scroll', ScrollTrigger.update)). The bridge between the DOM and the R3F render loop is a mutable object (journey.progress) living outside React, read inside useFrame. That avoids re-rendering the component on every scroll tick, which at 60fps would mean hundreds of renders per second.

In-browser WebGL performance was treated as a budget, not luck. Canvas DPR is adaptive: a drei PerformanceMonitor measures real fps over ~1.2s and a hook (useAdaptiveDpr) recalculates the internal resolution within a min/max range. A weak GPU drops to 0.6, a GPU with headroom climbs to 1.6, instead of getting stuck at 17fps with a fixed DPR. Mobile gets a deliberately cheaper scene: a simple transparent-reflection glass material instead of MeshTransmissionMaterial with real transmission, soft PCSS shadows and Bloom turned off, ContactShadows resolution halved. The 3D canvas also only mounts after first paint, via requestIdleCallback with a 1200ms timeout as a safety net, to avoid hurting LCP and TBT. And R3F's frameloop toggles between always and never based on an IntersectionObserver (useInView), so the scene stops rendering the moment it leaves the viewport.

Motion accessibility was built into the 3D scene itself, not just the DOM animations. usePrefersReducedMotion turns off the pointer-following camera parallax and the ambient micro-loops (pool water breathing, warm interior light pulse) in both CameraRig and House, keeping the rest-state values already defined in JSX. Lenis's smooth scroll also gets out of the way entirely when prefers-reduced-motion: reduce is active, and the page falls back to native browser scrolling. That care, combined with a static poster (same framing as the fallback) shown behind the Canvas before it mounts, is what kept the hero fast and accessible without giving up the cinematic effect as the product's differentiator.

100% procedural house

No GLB: volumes, glass, furniture and pool are Three.js geometry generated in code, with a documented fallback path to swap in a real model.

Keyframe camera + scroll

6 positions interpolated with smoothstep, driven by GSAP ScrollTrigger + Lenis outside React's render cycle.

Adaptive DPR from real fps

PerformanceMonitor samples the GPU over ~1.2s and auto-tunes canvas resolution between 0.6 and 1.6.

Graceful mobile/a11y degradation

Cheaper glass, shadows and Bloom on mobile; parallax and micro-loops turn off with prefers-reduced-motion.

More screens

Lumen's 3D hero with the procedural residence and animated headlineArchitecture studio's services sectionInteractive 3D model section (drag to rotate, scroll to zoom)

Stack

  • React
  • Vite
  • TypeScript
  • Three.js · R3F
  • SCSS

Ready to turn your idea into a digital product?

Tell me what you need. I reply fast and send a free quote, no strings attached.

  • Service contract
  • Post-launch support
  • You own the code
  • Free quote