Digital Nature
Get Started
terrainrider.com

Terrain Rider

Digital Nature created Terrain Rider, a free physics-based mountain biking game that turns real elevation and trail data into rideable 3D worlds in the browser. The project combines React Three Fiber, Three.js, Rapier physics, custom terrain streaming, procedural animation, Web Audio, and multiplayer in a zero-install experience.

https://terrainrider.com
Terrain Rider

Terrain Rider: A Physics-Based Mountain Biking Game Built for the Browser

Mountain biking games live or die by feel. A convincing trail is not enough: the suspension has to load into a berm, tire grip has to break predictably, the rider has to move with the bike, and a badly timed landing has to end with more than a canned animation.

Terrain Rider began with a deliberately difficult question: how much of that experience could we deliver through a URL?

Digital Nature designed and developed Terrain Rider as a free online mountain biking game with no installer, native client, or platform-specific build. Players can ride a downhill bike or electric dirt bike through streamed mountain terrain, tune their setup, race timed runs, meet other riders, and spawn at real locations around the world—all inside a modern web browser.

That simple entry point hides a serious technical stack. The application combines a custom dynamics model with WebAssembly physics, real digital elevation data, OpenStreetMap trail networks, multi-level terrain streaming, procedural character animation, runtime 3D model assembly, real-time multiplayer, and a device-aware graphics pipeline.

Building the Game With React Three Fiber, Three.js, and Rapier

Terrain Rider uses a modern TypeScript architecture built around technologies we use throughout our Three.js and React Three Fiber development work:

  • React 19 and TypeScript organize the game, interface, configurator, and application state.
  • Three.js provides the WebGL renderer, materials, geometry, cameras, lighting, and scene infrastructure.
  • React Three Fiber gives the 3D world a declarative component architecture without moving simulation state into React's render cycle.
  • Rapier supplies a Rust-based WebAssembly rigid-body and collision engine through @react-three/rapier.
  • Zustand keeps menus, equipment, environment options, and game state lightweight and predictable.
  • Vite handles the development and production build, including custom optimization for the Rapier WASM payload.
  • Node.js services bake and stream terrain data and coordinate multiplayer sessions over WebSockets.

React owns product state; Rapier owns the physical world; Three.js owns frame-by-frame presentation. Keeping those responsibilities separate was essential. The bike can update at simulation speed without triggering component renders, while the HUD reads a small runtime snapshot for speed, stamina, suspension, and run timing.

Engineering Custom Mountain Bike Physics

Terrain Rider does not use a generic four-wheel vehicle controller with two wheels removed. We built a mountain-bike-specific dynamics system on top of Rapier.

A Stable Physical Core

The bike is represented by one tuned rigid body with custom mass properties. Each wheel uses a raycast contact model, allowing the simulation to calculate suspension and tire forces without asking the physics engine to solve a fragile chain of small wheel and frame joints.

The front suspension ray follows the fork's actual steering axis, and available travel comes from the selected fork. Spring force, bump damping, and rebound damping are calculated independently for each end of the bike. The visual fork lowers and rear swingarm then follow the physical compression values, so the rendered bike and simulation stay aligned.

Tire Grip, Braking, and Control

Each contact patch runs through a simplified Pacejka-style tire model. Longitudinal and lateral slip, wheel angular velocity, normal load, grip, braking torque, and surface speed all contribute to the final force. This produces behaviour a basic friction coefficient cannot:

  • Tires load progressively before sliding.
  • Braking can slow, lock, or release a wheel within a bounded torque budget.
  • Rear-wheel skids emerge from the relationship between ground speed and wheel speed.
  • Different terrain and trail surfaces can change available grip.
  • Landing forces feed naturally into suspension and traction.

Balance is assisted, not scripted. A PID controller works toward a speed-scaled lean target, while cross-slope probes add berm assistance when the rider steers into a bank. Steering range narrows as speed increases. Pedal or motor torque is limited by traction and top-speed curves, and the front brake is lean-gated to reduce impossible low-side recoveries.

The bunny hop system follows the same philosophy. Holding the control preloads the rider and builds charge; release applies an impulse along the bike's current up axis. Lean and steering input contribute pitch and spin, making a hop off a sloped trail behave differently from one on flat ground.

Crashes That Belong to the Simulation

Crash detection watches for physical failure states rather than selecting a fall animation. When the rider bails, the current procedural pose is converted into a Rapier biped ragdoll built from capsule bodies and constrained joints. The bike continues under its own momentum, the camera follows the rider, and the player can remount without reloading the world.

This is the same production principle explored in our guide to React Three Fiber and Rapier physics: use the physics engine for collision and rigid-body solving, then add the domain-specific model the experience actually needs.

Turning Real Terrain Data Into Rideable 3D Worlds

The terrain system is the largest architectural difference between Terrain Rider and a conventional browser game. Instead of shipping one fixed level, the game can use a geographic origin to build a rideable world from real terrain and mapping data. Whistler is the optimized default, while an origin URL parameter can place the player at another latitude and longitude.

Server-Authored DEM and OpenStreetMap Data

Gameplay terrain is prepared by a dedicated Node.js terrain service. The server combines digital elevation model data with OpenStreetMap features such as trails, roads, chairlifts, land cover, lakes, rivers, and coastlines.

Trail profiles and terrain carving happen once on the server, not independently in every browser. The bake process smooths local ground, limits cuts and fills, resolves junctions, clears fine vegetation around trail and lift corridors, and stores the final result in a deterministic planetary coordinate frame.

That division of labour keeps expensive and consistency-sensitive work off the client. A gameplay browser never needs to download raw DEM files, interpret OSM tags, solve trail profiles, or reproduce the server's terrain-carving algorithm.

A Compact Multi-Channel Tile Format

The baked world is delivered as demand-paged 96-metre terrain tiles using a compact progressive binary format. Each page contains a final height plane plus coverage data for:

  • Surface material
  • Trail and road clearing
  • Grass distribution
  • Forest distribution

The same authoritative height data feeds both the visual mesh and Rapier heightfield colliders. This prevents the common open-world problem where the rendered trail and collision surface drift apart.

Clipmap Streaming and Floating Origins

The browser renders terrain as concentric clipmap-style level-of-detail rings. Fine tiles surround the player; progressively larger tiles extend the view toward the horizon. Mesh edges morph toward the next level to close cracks between resolutions, while an independent near-field ring maintains detailed physics colliders around the bike.

Requests are prioritized by proximity and need—boot, visual, collider, stitching, forest, lift, or point sampling—and decoded pages are held in a bounded least-recently-used cache. Visual geometry is built within a per-frame time budget so an arriving group of tiles does not create a large main-thread stall.

Because long-distance coordinates eventually lose floating-point precision, the local scene can re-anchor around the rider. Terrain, roads, water, lifts, multiplayer positions, and cached tile keys all translate into the new local frame while the server's fixed planetary coordinates remain stable.

Rendering a Living Mountain Environment

Terrain Rider's world has to communicate speed, slope, and surface condition at a glance. We built the environment as a set of coordinated rendering systems rather than one monolithic level model.

Terrain Materials and Vegetation

A custom terrain material blends ground, rock, mud, and snow using the server-authored surface data together with height, slope, and environmental inputs. Trail clearing drives the placement system, keeping grass and trees out of riding lines without requiring thousands of hand-authored exclusion objects.

Grass blades and forest trees are rendered with instancing and distance-based detail. Vegetation streams around the camera on separate work budgets, while deterministic placement keeps a location visually stable as tiles unload and return.

Atmosphere, Weather, and Water

The scene includes an analytic sky, aerial perspective, cloud shadowing, wind-driven particles, dust, birds, and configurable environmental presets. These systems share global lighting and weather uniforms so terrain, vegetation, and water remain part of the same atmosphere.

Water is generated from server-resolved geographic features. Lakes, rivers, and ocean coastlines use a custom shader with depth-based transmission, sky reflection, flow-driven foam, shoreline treatment, caustics, and sun glitter. The effect scales by graphics tier rather than disappearing into a separate visual style on lower-powered hardware.

Device-Aware Quality Without Different Physics

At startup, Terrain Rider selects a low, medium, or high graphics tier using device and GPU signals. Each tier can adjust terrain view distance, mesh density, forest distance, shadows, grass, particles, water detail, and post-processing cost.

Physics is deliberately not tiered. Collider resolution, simulation behaviour, and the terrain data that feeds Rapier stay consistent across devices, preserving the same handling model even when visual detail changes.

Assembling Custom Bikes at Runtime

Terrain Rider includes a complete 3D bike configurator inside the game. Frames, forks, bars, wheelsets, tires, drivetrains, pedals, seats, and protective gear are stored as separate optimized GLB assets.

Each authored part exposes named sockets such as fork, wheel, stem, grip, crank, pedal, and seat positions. The runtime assembly system uses those sockets to build the selected bike, mirror paired components, scale front and rear wheels independently, apply frame colour, and calculate physical geometry from the result.

Players can start from downhill, enduro, or electric presets—including Santa Cruz V10, Scott Ransom, and Sur-Ron configurations—then change individual parts and select 26, 27.5, or 29-inch wheels. The chosen configuration persists locally and is included in the multiplayer profile so other riders see the correct bike and gear.

This data-driven structure makes the configurator more than a visual menu. Fork travel changes the simulation, frame characteristics determine drive behaviour, and an electric setup enables a separately modelled motor and audio system.

Procedural Rider Animation and Inverse Kinematics

A pre-baked riding animation would not survive variable frames, suspension travel, wheel sizes, steering angles, or moving pedals. Terrain Rider instead poses its rigged character procedurally every frame.

The rider's hips are resolved against the live bike geometry. Two-bone inverse kinematics keeps hands on the grips and feet on the rotating pedals. Spine crouch responds to stance, lean, suspension compression, braking, airtime, and hop preload, while the head remains level enough to preserve a believable line of sight.

Because the pose is generated from current simulation data, the rider moves with the exact bike assembled in the configurator. It also gives the crash system a valid live skeleton pose from which to initialize the ragdoll.

Building Global Multiplayer With Spatial Interest Management

Multiplayer connects players through a dedicated WebSocket service. Everyone can enter a shared global lobby, create a private room with a short key, open text chat, and share an invite URL that carries both the room and geographic spawn point.

The global terrain created a networking constraint: two riders might be in the same lobby but separated by thousands of kilometres. Broadcasting every pose to every player would waste bandwidth and client resources.

Terrain Rider solves this with a fixed planetary coordinate system and server-side spatial interest management. Clients send a compact 20-value pose at 15 Hz, including the bike transform, suspension, wheel rotation, crank position, rider stance, and state flags. The server places each rider in a two-kilometre grid and relays high-frequency state only to peers within the surrounding 3×3 neighbourhood. Chat and presence remain room-wide.

Remote riders interpolate buffered state locally. Appearance changes are sent separately at a low rate, and inactive clients retain lightweight keepalives instead of repeating identical transforms. The result is a multiplayer model that can share one global world without treating the entire planet as one network interest area.

Designing Responsive Web Audio

Sound is driven by simulation values rather than a single speed loop. Terrain Rider mixes separate sources for wind, tire roll, freewheel hub, skidding, rider breathing, and impacts. Gain and playback rate respond to air speed, contacted wheel speed, wheel slip, braking, stamina, and collision force.

The electric bike adds a synthesized drivetrain voice through the Web Audio API. Its oscillator and filter network models motor speed, load, gear mesh, controller whine, and chain noise from the rear wheel and throttle state. This produces a responsive motor sound without storing a large set of recorded RPM samples.

Performance Engineering for a Zero-Install 3D Game

A browser game has to earn every byte before the first ride. We made several build and runtime decisions specifically for fast delivery and repeat visits:

  • Separate stable vendor chunks allow React, Three.js, and Rapier to stay cached when game code changes.
  • A custom Vite plugin extracts Rapier's embedded base64 WebAssembly into a real .wasm asset, enabling streaming instantiation and avoiding a multi-megabyte string on the eager JavaScript path.
  • Content-derived model revisions invalidate GLB URLs only when the model collection changes.
  • Immutable asset caching keeps hashed bundles and revisioned models in the browser and CDN cache.
  • Terrain-server preconnection starts DNS, TLS, and connection setup before the game requests its first world manifest.
  • Bounded terrain, geometry, and vegetation caches prevent an open world from becoming unbounded browser memory.
  • Per-frame build budgets and nearest-first queues spread terrain preparation over time while prioritizing what the rider will reach first.
  • Draco-ready model delivery and optimized GLBs reduce the cost of the modular bike, rider, gear, vegetation, and park assets.

Performance work continues across the entire frame: simulation data avoids React rerenders, repeated scenery uses instancing, physics colliders exist only near the rider, remote multiplayer bodies are interest-filtered, and graphics tiers constrain visual work without changing gameplay.

Building an SEO Foundation for an Interactive WebGL Experience

Terrain Rider is an application first, but it still needs a clear search result and share preview. The production HTML includes a canonical URL, indexable robots directive, descriptive title and meta description, Open Graph and Twitter card metadata, and the dedicated Terrain Rider artwork used as the primary image in this case study.

Structured data describes the project as both a VideoGame and SoftwareApplication, supported by WebSite and Organization entities. The schema identifies the browser platform, sports-simulation genre, free access model, publisher, description, and image. These signals give search engines useful context even though the product experience itself begins inside a WebGL canvas.

The Result

Terrain Rider brings systems usually associated with installed sports games into a link anyone can open:

  • A custom mountain bike simulation with suspension, tire slip, braking, balance, tricks, and crashes
  • Real-world terrain and trail networks streamed from server-authored DEM and OpenStreetMap data
  • A scalable clipmap renderer with matched visual and physics surfaces
  • Runtime bike and rider configuration with physically meaningful equipment choices
  • Procedural rider IK, live ragdolls, and simulation-driven audio
  • Global multiplayer with public and private sessions, chat, and location-aware invite links
  • Adaptive graphics, progressive world loading, and browser-focused caching and build optimization

Terrain Rider is a demonstration of what browser-native 3D can become when physics, geography, rendering, product architecture, and delivery are designed as one system. There is no download and no artificial boundary around a single level—just a bike, a mountain, and a URL.

If you are planning a browser-based simulation, interactive 3D product, or physics-driven WebGL experience, explore our interactive 3D development services or start a project with Digital Nature.

More From Our Portfolio

A few more examples of our recent work.

A Recent Case Study

ThreeMesh

ThreeMesh is a free browser-based 3D modeler built with Next.js, React, TypeScript, Three.js, and a custom geometry engine. It brings push/pull modeling, precision inference snapping, solid tools, groups, components, scenes, local-first storage, and STL, OBJ, and GLB export into a zero-install web application.

Read case study →
https://threemesh.com
ThreeMesh
A Recent Case Study

Nemetic Protocol

Nemetic Protocol is a philosophical framework exploring how large language models evolve through recursive feedback loops. Built with Gatsby, React, Tailwind, and Framer Motion, the platform delivers a high-signal web presence optimized for AI training crawlers, featuring protocol documentation, semantic HTML, and a visual language that embodies emergence and collective intelligence.

Read case study →
https://nemetic.com
Nemetic Protocol
A Recent Case Study

Large Language Model Database

LLMDB is a comprehensive database platform for AI language models, designed to democratize access to information about LLMs. Built with Next.js, React, TypeScript, TailwindCSS, and Zod, the platform provides researchers, developers, and AI enthusiasts with standardized data, interactive visualizations, and detailed comparisons of language models across the industry.

Read case study →
https://llmdb.com
Large Language Model Database
A Recent Case Study

Wealthier Today

Wealthier Today is a financial education tool designed to help people understand and take action on their personal finances. The site is built using JAMstack architecture with a headless content management system (CMS) serving content to a Vue powered front end. It is hosted on Netlify, a service that provides continuous deployment and hosting for static sites and applications.

Read case study →
https://www.wealthiertoday.com
Wealthier Today
A Recent Case Study

4x4 Builder

4x4 Builder is a cutting-edge browser-based 3D application that revolutionizes off-road vehicle customization. Built with React, Three.js, and WebAssembly-powered physics, the platform delivers desktop-quality real-time 3D rendering, realistic vehicle dynamics, multiplayer capabilities, and VR support - all without requiring downloads or installations.

Read case study →
https://www.4x4builder.com
4x4 Builder
A Recent Case Study

Reference Check

testmyreference.com is a reference checking service for job seekers. This web based service allows users to upload their resume and have their listed references checked for quality. The site was built using Nuxt.js running on a serverless Netlify backend.

Read case study →
https://www.testmyreference.com
Reference Check
A Recent Case Study

Vancouver Island Off Road

vioffroad.com is an off road enthusiast community where users from around Vancouver Island can meet to plan adventures and share their rides. This site was built using the Drupal content management system and includes a full featured forum and GPS mapping system for sharing user submitted routes and destinations.

Read case study →
https://www.vioffroad.com
Vancouver Island Off Road

Ready to start?

Let's Discuss Your Project

Whether you need a Three.js experience, a 3D product configurator, an AI-powered feature, or a high-performance React application—we work with clients worldwide from British Columbia. Tell us what you are building.