← Back to work
2025

Immersive 3D Portfolio

Cinematic scroll-driven portfolio. 14k GPU particles, WebGL shaders, GSAP scroll animations, Lenis smooth scroll.

ReactViteReact Three FiberGSAPLenisWebGLGLSLTailwind
Immersive 3D Portfolio — project screenshot

Overview

A cinematic single-page portfolio built for a visual effects context. The goal: make the browser feel like a 3D environment, not a webpage. Every scroll event is a deliberate camera move. Every hover is a material response.

Built with React Three Fiber, GSAP ScrollTrigger, Lenis, and hand-written GLSL shaders.

What was built

Particle field — 14,000 GPU particles driven by a custom vertex shader. Curl-noise flow field, mouse repel on hover, scroll-triggered dispersion (particles scatter as you leave the hero). Additive blending + depthWrite: false keeps overdraw cheap. Runs at 60fps on most GPUs.

Kinetic headline — GSAP ScrollTrigger linked headline: letter-spacing expands, skew rotates, words stagger in/out as you scroll. No layout triggers — transform and opacity only.

Stacking project cards — GSAP ScrollTrigger pin + overlap. Each project card slides under the next, creating a physical stacking feel. The scroll scrub is synced to Lenis for perfect smooth physics.

Project planes — Per-project R3F planes with a custom wave + RGB-split shader. Wave amplitude responds to mouse proximity. RGB channels separate on hover for a chromatic aberration effect.

Lenis + GSAP sync — Lenis drives the GSAP ticker directly via gsap.ticker.add. Every scroll effect is synced to the same RAF — no jitter between the particle field and the GSAP animations.

Stack

| Layer | Technology | |-------|-----------| | Build | Vite + React | | 3D | React Three Fiber + Drei | | Shaders | GLSL (custom vertex + fragment) | | Animation | GSAP + ScrollTrigger | | Scroll | Lenis | | Styling | Tailwind CSS | | Deploy | Vercel (Vite preset) |

Performance notes

Key decisions

Why R3F over Three.js direct? React component model makes scene management dramatically simpler. useFrame, useThree, and Drei utilities cut boilerplate to near-zero while keeping full Three.js escape hatches.

Why Lenis over native scroll? Consistent scroll physics across browsers. The ease curve is controllable — the portfolio needed a specific "heavy" feel, not the snappy default browser scroll.

Why Vite not Next.js? No SSR needed for a purely visual portfolio. Vite's HMR is faster for shader iteration — a critical feedback loop when tuning GLSL.

Start a similar project