All case studies

DEV3 Technologies · own product

XENOVA: a procedural alien world told as a scroll-driven React Three Fiber story

Our own Next.js template: an eight-chapter WebGL journey from orbit to an alien valley, built entirely from GLSL noise and instanced primitives, with day-to-night light moods, animated creatures and an interactive finale.

Industry
Entertainment & creative (web templates)

Live project preview

DEV3 Technologies · own product — screenshots
Open live demo
XENOVA hero — a glowing ringed alien world hangs under two suns beside the field-guide title and planet stats.

XENOVA hero — a glowing ringed alien world hangs under two suns beside the field-guide title and planet stats.

The challenge

Game, film and creative launches want a website that feels like a world, not a brochure. Most 3D landing pages solve that with a single hero model and heavy downloads, and they stop at the hero. We wanted a whole story: a camera that travels from space to the ground, scenes that change light from morning to night, creatures that move and respond, and copy that stays readable, all without shipping a gigabyte of assets, without React re-rendering on every scroll tick, and with a calm version for visitors who ask for reduced motion.

Our solution

We built XENOVA on Next.js 16 with React 19, React Three Fiber 9, three.js and Lenis, as a template DEV3 sells and as a reference for our own immersive projects.

Key design decisions

  • Everything procedural. The planet, rings, clouds, terrain, sky, flora, creatures and glyphs are GLSL noise and instanced primitives, so there are no models or textures to license, compress or wait for.
  • Two realms, one camera. An orbit realm with an ease-in dive and a surface realm where the camera follows a Catmull-Rom path through eight shots. A full-screen veil shader covers the hand-over between them.
  • Scroll outside React. Scroll progress, velocity and pointer live in a mutable per-frame store; only the chapter index and ready state reach React through useSyncExternalStore.
  • Shared light moods. One set of uniforms (two suns, sky, fog, night, aurora, wave) is blended per frame from a table of chapter moods, so every surface shader shifts from day to night together.
  • Instancing at scale. About 14,000 fronds, the trees and pods, and 27 creatures of about 30 parts each are drawn as instanced meshes, with tentacle sway and bell breathing in vertex shaders.
  • No first-scroll hitch. Every shader in both realms is compiled up front before the intro finishes.
  • Reduced motion as a first-class mode. No fly-in, instant chapter jumps, slower scene clock, no chromatic aberration and instant text.

Results

XENOVA ships as a complete Next.js template: eight chapters, a HUD, field notes, a procedural glyph alphabet with a decode effect and an interactive signal finale, with copy and stats for every chapter in one file.

The repository passes tsc --noEmit and ESLint, builds as a normal Next.js app or a static export, and includes a Playwright script that captures every chapter at desktop, tablet and phone sizes; the marketing screenshots and video tour were produced from it. A public live demo runs as a static export on dev3.tech.

XENOVA is available on the DEV3 marketplace.

Setup guide

Requirements

  • Node.js 20.9 or newer and npm
  • A browser with WebGL2 for development and testing

No environment variables, API keys, database or external services are needed.

Install and run

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

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

    npm install
    
  3. Start the development server:

    npm run dev
    

    The dev script uses port 3200; open that port on your machine in a browser and scroll through the eight chapters. Change the -p 3200 flag in package.json if the port is taken.

  4. Optional checks: npm run typecheck and npm run lint.

Build for production

npm run build
npm run start

npm run build produces a standard Next.js production build that npm run start serves.

Deploy to Vercel

Push the folder to a Git repository and import it in Vercel. The defaults (framework Next.js, build command npm run build) work as is; there are no environment variables to set.

Deploy as a static site

The template can be exported to plain HTML, CSS and JavaScript for any static host (Netlify, Cloudflare Pages, S3, an Nginx folder). next.config.ts switches to static export when DEMO_EXPORT_BASE is set to the sub-path the site will live under:

DEMO_EXPORT_BASE=/xenova npx next build

The site is written to out/; upload that folder so it is served at the same sub-path. The included build:demo script is the one used for the DEV3 live demo. It also sets NEXT_PUBLIC_DEMO_DOWNLOAD_URL, which shows a small "Get this template" badge, so leave that variable unset for your own site.

Updates

Download the new version from Account → Downloads on dev3.tech and compare it with your copy. Keep your changes in lib/lore.ts, lib/mood.ts and app/globals.css so they are easy to carry over.

How to use

Where things live

File What it controls
lib/lore.ts All chapter copy: kicker, title, tagline, four stats, field note, accent colour and HUD values (local time and air)
lib/mood.ts The light mood of each chapter: sky, fog, both suns, ambient, night, stars, aurora and wave
lib/world.ts The valley layout, the scatter of plants, pods and towers, and the camera SHOTS for each chapter
components/scene/ The 3D scene: space, sky and terrain, flora, habitat, the stone ring and the creatures
components/ui/ Loader, HUD, chapter rail and panels, field notes, glyph effects, the signal form and cursor
app/globals.css Page colours, spacing and type styles
app/layout.tsx Fonts, page title and description

Edit the story

Open lib/lore.ts. The CHAPTERS array has one entry per chapter, in order. Change the title, kicker, tagline, stats (label and value pairs) and fact (the field note) to your own text. All names and figures in the demo are fiction, so replace them before you go live.

Each chapter fills one screen of scroll and has a matching camera shot in lib/world.ts and a light mood in lib/mood.ts. If you remove or add a chapter, keep those three lists the same length and in the same order.

Change colours and light

  • Page colours: edit the CSS variables at the top of app/globals.css: --bg, --fg, --dim, --faint, --accent and --lume (the glow green).
  • Per-chapter accent: the accent field of each chapter in lib/lore.ts tints the kicker, rail and HUD for that chapter.
  • Scene light: each row of the moods table in lib/mood.ts sets the sky zenith and horizon, fog colour and density, the two suns (elevation, azimuth and intensity), ambient light and the night, star, aurora and wave levels. The scene blends between rows as the visitor scrolls.
  • Glow and grade: bloom, tone mapping, grain and vignette are set in components/scene/Experience.tsx.

Change fonts

The three typefaces (Unbounded for display, Instrument Serif for body, JetBrains Mono for the HUD) are loaded with next/font/google in app/layout.tsx. Swap the imports for other Google fonts, or use next/font/local with your own files, and keep the --font-display, --font-serif and --font-mono variable names.

Change camera moves

Each entry of SHOTS in lib/world.ts is a camera position and a look-at point. Move them to reframe a chapter; the camera follows a smooth curve through them. PORTRAIT_LOOK overrides the look-at point on portrait phones.

Swap or add 3D content

The template draws everything procedurally, so there are no model or texture files to replace. To restyle the world, adjust the shapes, counts and colours in the scene components and the GLSL in lib/shaders*.ts. To show your own model (a ship, a character, a logo), load a GLB with three.js's GLTFLoader (or R3F's useLoader) in a new component and add it inside the scene in Experience.tsx, placed near the camera shot of the chapter it belongs to. Keep models compressed and light so phones stay smooth.

The signal form

The last chapter's form (components/ui/Signal.tsx) shows the message in glyphs and a canned reply; it sends nothing anywhere. To collect sign-ups, call your own newsletter or form endpoint in its submit handler.

Interaction and accessibility

Visitors can tap to make the creatures flash, and use the arrow keys or Page Up / Page Down to move between chapters. Reduced-motion visitors get instant chapter jumps and calmer animation automatically; keep that behaviour if you add new effects by checking journey.reduced.

Related case studies