Skip to main content
AC
3D & Games4.6 KBMIT licensed

build-3d-website

Original, written for TechTide client work

Build interactive 3D marketing sites with React Three Fiber and drei: 3D heroes, floating objects, tilt cards, scroll-driven scenes, WebGL showcases. Use when asked for a 3D landing page, WebGL hero, immersive explorer, or a premium wow page, or on mentions of three.js, R3F, tilt card. Not for playable games with mechanics, AI, or saves: use build-3d-game.

  • build
  • website

SKILL.md

Build a 3D Interactive Website

One focused, SSR-safe, performant hero scene beats a sprawling broken one. Build the hero first, guard every SSR and loading edge, and verify on a phone-sized viewport before calling it done.

Two modes

  • Build mode (default). Implement in the current project with R3F plus drei.
  • Prompt mode. Only when the user explicitly asks for a prompt to paste into another builder. Emit a single self-contained master prompt covering scene, interactions, SSR guards, and the perf checklist below.

If the user asks for code targeting a framework this project does not run, refuse and offer prompt mode. Foreign framework components will not run here.

Build workflow

  1. Clarify scope sparingly, two questions max: theme/tone, primary 3D object, key interactions (hover/scroll/click), single page vs multi-section. Ask for a reference image if none was given: screenshots raise fidelity dramatically.
  2. Confirm deps. Check package.json for @react-three/fiber. If missing, add three, @react-three/fiber, @react-three/drei, and dev-dep @types/three with the project's package manager.
  3. Wire SSR-safely. Three.js touches window; server rendering crashes without a guard. Mount the Canvas behind a client-only wrapper (render null until after hydration), and exclude three packages from SSR externalization in the bundler config. Required, not optional.
  4. Build the hero scene first. Pick the closest archetype (floating hero object, tilt cards, scroll-driven explorer, premium showcase) and get it rendering before expanding to other sections.
  5. Perf pass before declaring done: dpr={[1, 2]} cap, frameloop="demand" for static scenes, lazy-load GLTF, <Suspense> fallback on every async asset, touch controls on mobile, prefers-reduced-motion fallback.
  6. Verify per the section below.

Guardrails

  • Never render <Canvas> at module scope or in a server-rendered route body without the client-only wrapper. The reconciler calls window/document at mount.
  • Never load .gltf, .hdr, or large textures without <Suspense fallback={...}>. The route flashes blank otherwise.
  • Never ship without a prefers-reduced-motion branch that stills the animation and shows a static frame.
  • Cap DPR at 2. Uncapped DPR tanks retina and mobile FPS.
  • Camera FOV 35-50 for product and hero shots; 60-75 only for immersive explorers.

Good vs bad

Bad: import the Canvas component at the top of a server-rendered route, ship, and discover "window is not defined" only in production builds.

Good: a ClientOnly wrapper that returns null until mounted, Canvas inside it with dpr={[1, 2]}, GLTF behind Suspense with a branded loading fallback.

Verification

Run the dev server and load the route. Expect no SSR crash, no console errors, and no "Hooks can only be used within the Canvas" warnings. If the SSR crash appears, the Canvas is mounting during server render: add the client-only wrapper and bundler SSR exclusions.

Then open the route at a 375px viewport and take a screenshot. Expect the scene rendered, interactive via touch, and legible. If the scene is blank on mobile only, check DPR cap and texture sizes first.

Completion checklist

  • [ ] Project build succeeds
  • [ ] Route loads with no window is not defined SSR crash
  • [ ] Console clean, no R3F hook warnings
  • [ ] 375px viewport renders and responds to touch
  • [ ] Reduced-motion users see a still frame, not a frozen loading state
  • [ ] All async assets behind Suspense with a real fallback
  • [ ] DPR capped, static scenes on frameloop="demand"

Any box unchecked: not done. Fix or say so.

Footguns

  • Canvas at module scope. Crashes SSR at import time. Fix: client-only wrapper plus SSR exclusion for three packages.
  • GLTF without Suspense. Blank flash, sometimes a permanent blank on slow networks. Fix: <Suspense fallback> around every loader.
  • Uncapped DPR. 3x pixel ratio on phones quarters the frame rate. Fix: dpr={[1, 2]}.
  • Reduced-motion ignored. Accessibility failure and a common audit rejection. Fix: media-query branch that freezes the animation loop with a composed static frame.

More in 3D & Games

All skills