Skip to content
enqamPublic

About

Trackmania-style arcade racer with a hand-painted, anime look. Loops, wall-rides, drift turbos, leaderboard and ghosts. Runs in any WebGL2 browser.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

RIFTLINE — painted speed

A Trackmania-style time-attack racer with a hand-painted, Arcane / anime look. Loops, wall-rides, ballistic jumps, boost pads, drift mini-turbos, checkpoints with splits, ghosts and medals. It runs in any WebGL2 browser, so the same build plays natively on Apple Silicon and x86 Macs/PCs.

Everything is procedural. There are no model, texture or audio files: the tracks, city, car, brush-stroke textures, engine sound and soundtrack are all generated at load time.

Play it in your browser: https://enqam.github.io/riftline/

Run it

npm install
npm run dev          # http://localhost:5199

Other scripts:

npm run build        # optimised multi-file build in dist/  (serve with: npm run preview)
npm run build:single # ONE self-contained HTML file in dist-single/ (double-click to play, works offline)
npm run sim          # headless check: builds every track, lets the AI drive it, reports times/falls

Append ?fps to the URL for an FPS / resolution readout. The dev and preview servers listen on 0.0.0.0:5199, so other devices on your network can join at http://<this-mac's-ip>:5199.

Controls

Action Keyboard Gamepad
Accelerate W / ↑ RT (or A)
Brake / reverse S / ↓ LT (or X)
Steer A D / ← → Left stick / d-pad
Drift Space / Shift (hold through a corner, release for a mini-turbo) RB / LB
Respawn at last checkpoint (keeps your speed) Enter / Backspace B
Instant restart R / Delete Y
Camera (chase / far / hood) C View
Toggle ghost G
Music on / off M
Pause Esc / P Start

Braking while steering hard at speed also starts a drift. A drift charges through blue, then orange, then pink. Release it to cash in a mini-turbo.

Tracks

  1. Gilded Ascent: golden hour over a clockwork city of spires, domes and airships. It has a loop, a kicker jump and a 48° banked hairpin.
  2. Neon Undercroft: a toxic night undercity with neon signs, a near-vertical 150° wall-ride, a loop and a jump.
  3. Skyshard Rift: twilight among floating isles and giant crystals, with a drop start, a double loop, a 170° wall-ride and two big jumps.

Each track's author medal time comes from the built-in AI driver. Gold, silver and bronze are scaled from it.

Drivers, leaderboard and ghosts

You enter a driver name before your first race. Change it any time with the name button at the top of the main menu. Every finish is posted to the leaderboard (main menu → Leaderboard, ← → to switch tracks). Each driver keeps their best time per track. The results screen shows your rank and the top five.

While racing you chase up to two ghosts:

  • Gold: the track record holder, with a name tag.
  • Cyan: your own best.

If a track has no record yet, you race the author's (AI) ghost.

Where the board lives:

  • npm run dev / npm run preview. The Vite server also serves a small API (server/leaderboard.js). Everyone playing against that machine, for example over the network at http://<this-mac's-ip>:5199, shares one board and one record ghost per track. It's stored in data/leaderboard.json. To reset the board, stop the server, delete that file, and start it again.
  • Single-file build, static hosting (including the GitHub Pages link above) or the Artifact. There is no server, so the board and ghosts are kept in that browser's local storage instead.

The API is a LAN-party convenience with basic input checks. It isn't hardened against someone deliberately posting fake times.

How it looks the way it does

  • Painterly toon shading (src/render/materials.js). Two cel bands whose edges are broken up by a generated brush-stroke texture, coloured ambient in the shadows, a warm terminator band, a hard anime specular, and a rim light that flares up when a subject is backlit.
  • One-pass G-buffer. Every material writes HDR colour and view-space normal + depth to two render targets (MRT, with MSAA).
  • Post (src/render/pipeline.js):
    • ink outlines from depth/normal discontinuities, with wobbly line weight so they look hand-inked
    • mip-chain bloom
    • sun shafts and an anime lens flare
    • filmic tonemapping, then split-tone grading
    • anime speed lines, plus zoom blur and chromatic aberration while boosting
    • paper grain and vignette
  • Sky (src/render/sky.js). A gradient sky with an anime sun and halo rings, stepped painted clouds, skyline silhouettes, stars and aurora. Toon water, a toxic sea or a sea of clouds sits below, with cel-shaded cumulus puffs above.
  • Instanced scenery (src/render/environment.js):
    • towers with procedural windows, domes, spires, clock faces and airships
    • neon signs and pipes
    • floating isles with trees and crystals

Gameplay / physics

  • Track builder (src/track/builder.js). Tracks are chains of blocks (straight, turn, loop, ramp, ballistic jump, landing) integrated like a turtle with yaw / pitch / bank, then sampled every metre. Jump gaps follow the exact ballistic arc for a design speed.
  • Surface queries (src/track/surface.js). Closest point and road frame against the ribbon. A local search keeps continuity through loops, and a spatial hash handles landings on other sections.
  • Car (src/physics/car.js):
    • fixed 120 Hz step, with render interpolation for smooth 60/120 Hz displays
    • spring/damper suspension plus speed-squared downforce, so the car sticks through loops and wall-rides
    • tyres with a capped sideways force, so cornering hard at speed slides rather than tracking like rails
    • speed-preserving drift, boost pads and air control
  • Collision. The road slab is solid from below, from the sides and at its end caps (miss a jump and you hit the landing ramp's face). Barriers are solid from both sides. Buildings, pillars, isles, crystals, pylons and lamps are solid (src/physics/world.js), and flat roofs can be driven on. Touching the sea, smog or cloud floor respawns you.
  • Autopilot (src/game/autopilot.js). Brakes to a curvature-based speed envelope. It drives the attract mode and sets author times.

Performance

Measured on Apple M4 Pro at 1536×1152 internal resolution with 4× MSAA: about 3 ms per frame, CPU and GPU combined. The game adapts to slower x86 integrated GPUs on its own:

  • In Auto quality it starts on High and scales the internal resolution down (to 50–70%) when frames go over budget. If that isn't enough, it drops a preset (Medium: no MSAA; Low: 1× pixel ratio, smaller shadow map, fewer bloom levels).
  • Scenery is instanced. The whole road with its walls is one draw call.
  • Post effects run at reduced resolution where they can.

You can force a preset in Settings. If a laptop struggles, try Low and turn off ink outlines.

Project layout

src/
  main.js            game loop, state machine, FX wiring, ghosts, medals, dynamic resolution
  track/             track layouts, block integrator, surface queries
  physics/           car model + tuning constants
  render/            materials/shaders, pipeline, sky, track mesh, environment, car, particles
  game/              camera rig, input, race/checkpoints, autopilot, storage/ghosts, leaderboard client
  audio/             procedural engine, SFX and generative music (WebAudio)
  ui/                menus, HUD, results (DOM + CSS)
server/leaderboard.js  leaderboard + record-ghost API (Vite plugin)
tools/sim.mjs        headless track validator (writes top-down maps to tools/out/)

About

Trackmania-style arcade racer with a hand-painted, anime look. Loops, wall-rides, drift turbos, leaderboard and ghosts. Runs in any WebGL2 browser.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages