All case studies

DEV3 Technologies · own product

VELOCE: a seven-chapter 3D car film and configurator in Next.js

Our own Next.js template for a fictional luxury marque: one real-time car on a mirror stage, staged across seven scroll chapters with a drive sequence and a live paint, wheel and lighting configurator, built with React Three Fiber.

Industry
Automotive (web template)

Live project preview

DEV3 Technologies · own product — screenshots
Open live demo
Reveal hero — the fictional VELOCE Aria V12 glows in deep red lacquer on a mirror-black studio floor.

Reveal hero — the fictional VELOCE Aria V12 glows in deep red lacquer on a mirror-black studio floor.

The challenge

Car launch pages usually lean on pre-rendered video: heavy to download, impossible to configure and identical on every screen. A real-time car looks better and can be repainted live, but it is easy to get wrong. Glossy paint needs believable reflections, scroll-driven camera moves hitch when React re-renders or when shaders compile mid-scroll, and the same shot that works on a wide desktop crops the car badly on a phone. We wanted a template that reads like a film, runs from one glTF model with no HDR or video assets, stays editable from a single content file and respects visitors who prefer reduced motion.

Our solution

We built VELOCE on Next.js 16 with React Three Fiber 9, three.js 0.187, @react-three/postprocessing and Lenis smooth scroll.

Key design decisions

  • One content file. lib/content.ts holds every chapter's copy and stats, its camera stop, field of view and copy side, a lighting "look" per chapter (environment, sweep, roofline trace, speed, lamps, floor pool), the six paints and the three wheel finishes.
  • No React re-renders on scroll. A small mutable store in lib/journey.ts is read by the scene every frame; React subscribes through useSyncExternalStore only to the chapter, ready and configuration values.
  • A camera on curves. CameraRig.tsx runs Catmull-Rom curves for position and look-at through the stops with a smootherstep ease per leg, and rebuilds the stops for portrait screens: the camera backs off, widens its lens and frames the car above the copy.
  • Paint in the shader. The body uses a clear-coated MeshPhysicalMaterial patched with onBeforeCompile, so a paint change is a wipe from nose to tail with a bright lacquer line at the edge rather than a hard swap.
  • Light without assets. Studio and night environment maps are baked at load from lightformer scenes with PMREMGenerator, and a rect-area light rig, a blurred planar-mirror floor and a horizon dome do the rest.
  • No first-scroll hitch. The loader holds until the glTF is decoded and compileAsync has compiled every shader, including the reflector and composer targets.
  • A fictional brand. The CC BY 4.0 car model from the three.js examples is re-materialed and its maker's emblems are removed from the mesh in code; the credit is shown in the final chapter.

Results

VELOCE ships as a complete Next.js project: seven chapters, a drive sequence with road and speed-line shaders, a live configurator with six paints, three wheel finishes and two lighting setups, and a full reduced-motion mode. It has no environment variables, database or API keys, and it builds either as a normal Next.js app or as a static export.

The project is written in strict TypeScript and passes ESLint, and its screenshots and video tours were captured from the running site on desktop, tablet and phone. The live demo is a static export of the same code.

VELOCE is available on the DEV3 marketplace.

Setup guide

Requirements

  • Node.js 20.9 or newer and npm
  • A modern browser with WebGL 2 (current Chrome, Edge, Safari or Firefox)
  • No environment variables, database or API keys

Install and run

  1. Download the ZIP from your DEV3 account and unzip it.

  2. Open a terminal in the project folder and install the dependencies:

    npm install
    
  3. Start the development server and open the address it prints (port 3180 by default):

    npm run dev
    
  4. Scroll through the seven chapters. The loader waits until the car is decoded and every shader is compiled, so the first visit takes a moment longer.

To change the port, edit the dev and start scripts in package.json.

Build for production

npm run build
npm run start

Run npm run lint to check the code.

Deploy to Vercel

Push the project to a Git repository and import it in Vercel. The defaults (framework Next.js, build command npm run build) work as they are, and no environment variables are needed.

Static export

The project can also be exported as plain files for any static host. next.config.ts switches to a static export when DEMO_EXPORT_BASE is set to the sub-path the site will live under:

DEMO_EXPORT_BASE=/veloce npx next build

Upload the generated out/ folder to that path on your host. To serve the export from the domain root instead, set output: "export" and images: { unoptimized: true } in next.config.ts and run npm run build.

Do not use npm run build:demo for your own site: it is the script for DEV3's hosted live demo and adds a "Get this template" badge.

Licence note

The car model in public/models/ is licensed CC BY 4.0 (by vicent091036, from the three.js examples) and has been modified. The credit is shown in the Reserve chapter. Keep an attribution if you keep the model, or replace it with your own. VELOCE and the Aria V12 are fictional.

How to use

Edit the chapters

All story content is in lib/content.ts. Each entry in CHAPTERS has:

  • label (the chapter rail), kicker, title, tagline and optional stats (label and value pairs)
  • cam and look: the camera position and the point it looks at, in metres around the car
  • fov: the lens for that shot, and shift: how far the car is pushed sideways to make room for the copy

Adding or removing an entry changes the scroll height, the rail and the counter automatically. Keep the LOOKS list the same length as CHAPTERS: each look sets env (environment light), sweep (side light), trace (roofline strip), speed (driving effects), lamps and pool (floor light) for that chapter, and the scene blends between them as you scroll.

The configurator is the chapter with the id atelier, and the driving effects run wherever a look has speed above zero. The brand name and model name are in MODEL and the copy; the page title and description are in app/layout.tsx.

Paints, wheels and lighting

  • PAINTS: a name, a hex colour, metal (metalness) and rough (roughness) per paint. Add, remove or reorder entries; the swatches follow.
  • RIMS: wheel finishes with the same fields.
  • ENVS: the Studio and Night lighting options. The two environment maps are built in components/scene/Stage.tsx from simple panel scenes, so you can change their colours and brightness there.

Swap the car or product

  1. Export your model as glTF binary (.glb), ideally Draco-compressed, with the vehicle centred on the origin, the nose towards -Z and the wheels on the ground.
  2. Replace public/models/car.glb, and car_ao.png (the baked contact shadow) if you have one.
  3. In components/scene/Car.tsx, map your mesh names to the materials: paint, glass, leather, carbon, lamps and wheels. Remove the code that strips the original model's emblems; it only applies to the bundled model.
  4. Re-tune the cam and look values in lib/content.ts for your model's size.

The bundled car is a CC BY 4.0 model and needs an attribution while you use it; the credit text is CREDIT in lib/content.ts.

Colours and fonts

  • Colours are CSS variables at the top of app/globals.css: --bg, --fg, --dim, --faint and the champagne --accent. The canvas background colour is set in components/scene/Experience.tsx.
  • Fonts are loaded with next/font in app/layout.tsx: Instrument Serif for headlines, Inter Tight for text and JetBrains Mono for the HUD. Swap them for any Google font, keeping the CSS variable names.

Effects and motion

  • Post-processing (bloom, chromatic aberration, tone mapping, noise, vignette) is set up in components/scene/Experience.tsx. Lower the bloom intensity or remove an effect to tone the look down.
  • Scroll feel (smoothing, snap delay, chapter jump duration) is in components/Journey.tsx.
  • Visitors with reduced motion turned on get instant jumps and no shake, scramble or aberration automatically; nothing needs configuring.

Related case studies