A cinematic, interactive mechanical keyboard product page built with Next.js 15, React Three Fiber, and GSAP. Features a real-time 3D configurator, scroll-driven animations, and Stripe checkout integration.
- Five full-screen sections with GSAP ScrollTrigger-driven animations
- Lenis smooth scrolling synced with GSAP ticker
- Cinematic line-reveal hero text with clip-path masking
- Auto-morphing colorway showcase (6 themes, 2.5s intervals) with state save/restore
- Procedurally generated keycaps from JSON layout data — no pre-baked GLTF models
- Real-time per-keycap color updates via Zustand state → Three.js material sync
- Switch type selector with 3D exploded switch animation (Linear / Tactile / Clicky / Black)
- Scroll-driven wave animation across the keyboard
- Full keyboard configurator: click any key to set its color
- HexColorPicker for precise per-keycap control
- Layout switching between 60% ANSI and TKL 87-key
- Curated color presets with one-click apply
- Smooth page transitions between homepage and studio
- Stripe Checkout — server-side session creation via
/api/checkout/[uid] - Prismic CMS — headless content management for slices
- Web Audio API — ambient keyboard sound on site awaken
- Custom elastic cursor with hover state detection
CanvasErrorBoundaryfor graceful Three.js failure handling- Device capability detection for mobile performance scaling
| Category | Technology |
|---|---|
| Framework | Next.js 15.5, React 19, TypeScript |
| 3D Graphics | Three.js, React Three Fiber, @react-three/drei |
| Animation | GSAP 3.13 (ScrollTrigger), Framer Motion |
| Smooth Scroll | Lenis 1.3 |
| State | Zustand |
| CMS | Prismic |
| Payments | Stripe |
| Styling | Tailwind CSS 4 |
| UI | Radix UI (Dialog), react-colorful |
git clone https://github.com/kahwei-loo/aurora.git
cd aurora
npm installCreate a .env.local file in the root:
# Stripe (use test keys for development)
STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
# Prismic (optional — only needed for CMS slice content)
NEXT_PUBLIC_PRISMIC_ENVIRONMENT=Get your Stripe test keys from the Stripe Dashboard → Developers → API Keys.
npm run devOpen http://localhost:3000.
To test the Stripe checkout flow, use Stripe test card numbers: 4242 4242 4242 4242.
src/
├── app/
│ ├── page.tsx # Main cinematic homepage (5 scroll sections)
│ ├── SceneElements.tsx # Three.js scene root (keyboard + lighting + effects)
│ ├── studio/ # Interactive keyboard configurator
│ ├── api/checkout/[uid]/ # Stripe checkout session API route
│ └── success/ # Post-payment confirmation page
├── components/
│ ├── 3d/ # Three.js components
│ │ ├── InteractiveKeyboard.tsx # Main keyboard mesh
│ │ ├── KeyboardGenerator.tsx # Procedural keycap geometry builder
│ │ ├── ProceduralKeycapV2.tsx # Individual keycap mesh
│ │ ├── SwitchExploded.tsx # Exploded switch animation
│ │ └── SwitchPlayground3D.tsx # Switch type showcase
│ ├── ElasticCursor.tsx # Custom cursor with elastic trailing effect
│ ├── SmoothScroll.tsx # Lenis + GSAP ticker integration
│ ├── ProductModal.tsx # Checkout modal with pricing
│ └── Navbar.tsx # Navigation with page transitions
├── store/
│ └── useKeyboardStore.ts # Zustand store (key colors, switch type, layout)
├── mocks/
│ ├── layout-60-ansi.json # 60% keyboard layout definition
│ └── layout-87-tkl.json # TKL 87-key layout definition
├── hooks/
│ ├── useDeviceCapability.ts # Mobile/desktop detection + performance scaling
│ └── usePageAnimations.ts # GSAP entrance animation orchestration
└── checkout.ts # Client-side checkout trigger
Keycaps are built from JSON layout data at runtime using Three.js BoxGeometry — not imported 3D models. Each key's position, width, and type come from the layout JSON, making it easy to support any keyboard form factor.
The Zustand store holds keyColors: Record<string, string> (key ID → hex). Each ProceduralKeycapV2 subscribes to its own key's color via a selector, so only the changed keycap re-renders — not the whole keyboard.
Section 5 auto-morphs through 6 colorways on scroll-enter. On scroll-exit, it restores the exact user state (colors they set in the studio) using a savedStateRef snapshot.
Lenis smooth scroll is integrated with GSAP ticker (gsap.ticker.add) so all ScrollTrigger animations track Lenis's virtual scroll position, not native scroll.
MIT