Three.js is overkill for most sites. Raw WebGL boilerplate, camera setup, lighting math, render loops — it's 300 lines of setup before you draw your first triangle. But React Three Fiber (R3F) is WebGL with the training wheels on: it's React-for-3D, and it turns a three-minute mental model into a shipping reality. This is how we build hero scenes and product showcases at Aidxn in 2026.
Why R3F Over Raw Three.js
R3F is a React renderer for Three.js. Instead of manually creating a scene, camera, renderer, and plugging them into a canvas, you write JSX: a <Canvas>, a <PerspectiveCamera>, a <mesh> with a geometry and material. The props are threaded directly to Three.js objects. Changes trigger re-renders. It feels like React because it is React — your brain doesn't have to context-switch between imperative WebGL and declarative React.
For marketing sites, this matters. You're wiring a 3D scene to scroll position, page state, or click handlers — all native React. In raw Three.js, you'd be reaching into the scene graph manually, updating uniforms, managing update loops. R3F lets you think in React primitives and get Three.js performance for free.
The Stack: drei, postprocessing, leva
drei is the utility belt: pre-built 3D objects (models, text, environment maps), helpers (OrbitControls, PerspectiveCamera), and effects. Instead of building a 3D text geometry from scratch, you drop in <Text3D> and pass your string. Saves 200 lines per feature.
postprocessing is the film grain, bloom, color grading layer. A hero scene with no post-processing looks flat. Add tone mapping, bloom, and noise and it reads premium. The API is simple:
{`
`}
leva is a dev-time control panel. You tune camera position, bloom intensity, light angles — all live, no recompile. Ship with leva disabled; your designer can tweak values live and you copy the config into code.
Scroll-Driven Cameras & Performance
Portfolio hero scenes usually animate as the user scrolls. You bind scroll progress (0–1) to camera position or object rotation. The pattern: useScroll() hook from drei, map scroll position to camera.position.y, and the scene re-renders on every scroll frame. On desktop, this stays 60fps. On mobile, it's trickier.
Mobile performance budget: target 30fps, not 60. Reduce device pixel ratio by 0.5 on phones, skip postprocessing on low-end devices, use LOD (level-of-detail) models. The code:
{`const dpr = isMobile ? 0.5 : 1;
const usePostprocessing = !isMobile;
`}
Test on a real iPhone 12 / Android flagship before declaring "mobile-ready". Simulator performance is fiction.
FAQs
Does R3F work on older browsers?
Needs WebGL 2 support (iOS 15+, Android 10+). For no-WebGL fallback, render a static image or video instead. Zero users notice the difference.
Should I use prefers-reduced-motion?
Yes. On prefers-reduced-motion: reduce, skip the scroll animation loop entirely. Render a single static frame. Your scene still loads, just doesn't move.
How do I load a 3D model?
Use useGLTF() from drei. Drop a .glb file in public, pass the path, and the model loads asynchronously. Bake lighting and textures in your 3D tool (Blender, Cinema 4D) before export.
Can I hook it to analytics?
Yes. Emit events on scroll milestones or click interactions. Track which hero scene users scrolled through, use that signal in your sales funnel.
The Verdict
3D hero scenes are no longer "nice-to-have" — they're table stakes for premium portfolio and SaaS landing pages. R3F removes the gatekeeping. No WebGL math, no render loop debugging, just React. Pair it with drei and postprocessing, test on mobile hardware, and you've got a 2026 hero that converts. Ship one this sprint. See how your scroll metrics change. Book your custom 3D implementation at /pricing, or read our shader fundamentals at /blog/glsl-shader-backgrounds-marketing-sites.