Skip to content
SamarthPD-21Public

About

Resources

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

Revheadz logo

Revheadz

Start it. Rev it. Shift it. A free engine sound simulator that runs entirely in your browser.

Pick one of 35 real machines, from the Toyota Supra and Ferrari F40 to a Formula 1 V10 and a Ducati Panigale, press the start button, and drive it down an endless drag strip with your keyboard or thumbs. The sound follows every throttle input, gear change, limiter bounce and overrun pop in real time, and every run from a standstill is timed. Every engine is built from recordings of that exact machine, and you can switch any of them to the engine-model sound to compare. When you're ready, race a friend or the CPU over the quarter mile, or take any of them down an endless 3D road in Cruise. No install, no account, no server.

Drive screen: a Supra on the endless strip, with the shift log, timing panel and gauges

Drag race: two cars launching off the line in tyre smoke, the tree on green

Cruise: a Porsche 911 GT3 RS on a mountain road, a guardrail along the bend, the map of the road ahead and the odometer

Garage with vehicle cards and filters   Drive screen on a phone in portrait

Features

  • 35 real machines from 23 makes: JDM icons (Supra, Skyline GT-R, RX-7, S2000, WRX STI), supercars and hypercars (F40, LFA, Carrera GT, Aventador SVJ, Zonda, Chiron), American muscle, European sports cars, two Formula 1 cars, Le Mans' Mazda 787B, a WRC rally car and four bikes
  • Real engine recordings for all of them (professional Sonniss recordings and YouTube dyno pulls, cold starts and onboards), turned into RPM-mapped loops by a custom audio pipeline, with a Real / Model switch in the drive screen to hear the engine-model version instead
  • No audible looping: short recorded loops are re-spliced in the browser into seconds of non-repeating sound (cycle-aligned random splicing), and every YouTube clip was screened for voices with a speech recogniser
  • Live turbo sound: a whistle and intake hiss that follow boost, plus blow-off "pssh" or compressor-surge "flutter" when you lift
  • Supercharger whine: the Hellcat's twin-screw blower and the Ninja H2's centrifugal one are driven by the crank, so their whine is locked to the revs: it climbs with every rev, drops on every upshift and keeps singing, softer, when you lift, with no blow-off
  • Physics-based engine and gearbox: inertia, torque curve, turbo lag, clutch slip at pull-away, drag and braking
  • Realistic shifting: torque cut, a rev-matching blip on downshifts, and clutch engagement, heard through the engine note itself
  • Each car's real gearbox: the factory gear count, ratios, final drive, tyre size and gearbox type for every machine, and each type behaves like the real thing. A torque-converter automatic (Hellcat, C63, DB9) slips and multiplies torque pulling away, slurs its shifts and kicks down when you floor it; a dual-clutch (GT-R, PDK, Chiron) keeps driving through each shift; a single-clutch automated manual (LFA, Aventador) cuts hard and bites firmly; a manual cuts the drive completely while the clutch is open; race and bike boxes snap through with a quickshifter. Automated boxes change down on their own as you slow
  • Realistic deceleration: engine braking that pulls harder in low gears, progressive brakes that ease off as you stop, and overrun crackle when you coast at high revs
  • Rev limiter, backfire pops and turbo blow-off, which only fire when you actually coast, never on a gear change
  • Smooth sound: loops are pitched together and crossfade at constant loudness, so revving doesn't click or warble
  • An endless drag strip to drive on: the drive screen is the strip itself, edge to edge, in the same 2.5D scene as the drag race, at night under the floodlights or at dusk with the sun going down (the moon/sun button switches), with your car's tyre smoke, exhaust flames and pops. Three gauges sit in the corner: a tachometer that bounces off the rev limiter, a speedometer, and a boost gauge that reads manifold pressure like the real thing (vacuum with the throttle shut, boost as the turbo or supercharger builds; a vacuum gauge on cars without one). Shift lights over them flash at the car's shift point
  • Timed runs: every launch from a standstill is timed like a road test, with 0–100, 0–200, 100–200 and 0–300 km/h, 60 ft, 1/8 and 1/4 mile, 1/2 mile and 1 km (with the speed at each line) and top speed. The timing lines appear on the road where you launched, and personal bests are kept per car
  • Shift log: a running time slip of every shift and split in the run, with each upshift rated Perfect, Great, Good, Late or Early against the shift light, just like in a drag race (switch it off from the timing panel)
  • Works on phones, with multitouch: see-through pads over the strip, so you hold the gas with one thumb while you shift or brake with the other, in portrait or landscape. On a keyboard, one quiet line of key hints instead
  • Installable: add it to your home screen and it opens full-screen like an app, with its own icon
  • Playground with search (/), filters, sorting, favourites, "Jump back in" for recently driven machines, a Hear it rev preview on every card and a "Surprise me" button
  • Quick vehicle switcher in the drive screen (V): search the whole garage without leaving the cockpit
  • Drag racing: heads-up quarter-mile racing against a friend online (4-letter room code) or the CPU (Easy, Club or Pro). Cars race in seven classes (Street, Muscle, Grand Touring, Supercar, Track, Hyper, Formula), and within a class each car's engine is trimmed so every car runs the same perfect quarter mile (performance parity), so reaction time and shifting decide it, not the car
    • A 2.5D night strip with grandstands, a full Christmas tree (stage bulbs, four ambers, green), tyre smoke off the line, exhaust flames and a cool-down where the cars brake and downshift after the finish
    • Low-poly models built for each kind of machine: cars with fenders and spinning alloy rims, open-wheel Formula 1 cars, and bikes with their riders
    • Shift-light strip, launch and shift ratings, tree beeps, the other car's engine beside you, and a printed time slip with a "why you won/lost" breakdown
    • Pro controls (S+W to stage on the two-step, let go of S on the green, E/Q to shift) or one-button Simple controls
  • Ghost challenges: pick Send a challenge, set a run and send the link. Your friend races your exact run as a see-through ghost car beside them, the time slip shows who won, and they can send their run straight back. The whole run fits in the URL, and nothing in it is trusted: the time is worked out by replaying your inputs, so editing the link can't fake a faster time
  • Online rooms: create a room and send the 4-letter code. The class is shared, so either player can pick it and you both move to it
  • Cruise (/cruise): take any machine down an endless 3D road through hills, forest, desert and mountains, inspired by slowroads.io. The cars drive like the real ones, the day goes by and the weather changes, and you can leave the road and roam. See Cruise below
  • Free to host: a static site you can put on Vercel, Netlify or Cloudflare Pages

Cruise

An endless road you never drive the same way twice. Pick a machine at /cruise, start it, and go.

The road and the world

  • Grown from a seed as you drive: rolling hills, forest, meadow and dry gold country, lakes, and mountain ranges whose slopes rise close beside the road, so it threads the valleys between them
  • Guardrails where a road would have them: round the outside of the bends (both sides of the tight ones) and along drops and embankments, on steel posts with reflectors. The straights are left open, with the odd field gate, so there's plenty of room to run off into the country. Brush a rail and you slide along it in a shower of sparks; hit one square on and it costs you speed
  • Anywhere you like: you steer, and the whole map is yours. Drive across meadows, up hillsides and through the shallows. Go over a crest or off a ledge fast enough and the car leaves the ground. Hills pull you back and push you on, grass and dirt drag at the wheels, steep slopes slide you sideways and deep water stops you
  • Day and weather: let the day go by (an hour a minute) or jump to sunrise, day, golden hour, dusk or night; clear, hazy, foggy or rainy. Headlights and glowing reflectors after dark, a sun that flares in the lens, clouds that drift and glow at sunset, trees and grass that sway, lakes that ripple
  • Your world is remembered: come back and you're on the same road where you left it, with the map loaded from the browser. Back to road (B) puts you on the nearest bit of road

Driving

  • Every car drives like the real one: its own power and torque curve, kerb weight and weight distribution, size and wheelbase, aero drag, drivetrain and everything that spins, so 0-100 km/h and top speed land close to the road tests (a GT3 RS does 3.2 s, a 911 SC 6.8; the Chiron stops at its 420 km/h limiter)
  • Tyres that grip like tyres: force builds with slip to a peak and falls away as they slide; weight shifts forward on the brakes and back under power; a hard bend costs speed; the brakes stop you in a real car's distance, longer in the wet. Set up like road cars, they run wide at the limit rather than snap round, and a slide caught at speed settles instead of throwing you the other way. Let go of the wheel in a slide and it self-centres along it
  • Driver aids as built: ABS, traction and stability control as the car left the factory (an F40 or a '71 'Cuda has none, so it spins its wheels, locks them under hard braking and can spin), or each one set yourself in Settings. Dash lights show each one working
  • Gears: automatic, or manual on E / Q, where a car with a clutch pedal stalls like a real one (brake to a stop in gear and it dies: N, then I)
  • Grip and traction: every car has its own tyres and copes with dirt in its own way (the rally car best, slicks hopeless), the driven wheels can only put down so much, and the HUD shows the surface and your grip on it
  • Autopilot (T): it drives for you, holding the speed you set, slowing for the bends it can see coming and steering along its lane (A / D move it across the road)

The cars

  • Modelled to the real thing: each car is lofted into a smooth body at its real length, width, height and wheelbase, sitting on its real wheels, with its own touches: ducktails, lips, swan-neck and rally wings; bonnet scoops and vents; pop-up, round or slim headlights; the four round taillights of the GT-Rs and the F40; intakes in the flanks of the mid-engined cars; exhausts in the middle, at the corners or in fours
  • Fire and smoke: flames from the exhaust on backfires, overrun pops, the limiter and hard upshifts; tyre smoke pouring off a drift or a burnout; black rubber laid on the road and ruts torn in the grass
  • Felt and heard: the engine's own recordings, plus wind that builds with speed, the drone of the road, a crunch off it, tyres squealing in a slide and a hum through the camera at speed
  • Bikes are in beta: they ride, but their handling and models are still being tuned

On screen

  • A map of the road ahead, bottom left: it turns with you and shows the next 1.3 km, bends tinted by how tight they are, guardrails along the edges and a mark every 500 m
  • An odometer with rolling drums counts each car's kilometres between visits, with a trip meter and a trip computer (distance, time on the move, average speed)
  • Five cameras (C): chase, far, bonnet, a high drone and a film camera by the road. Drag to look round the car

Settings

The Settings button (O) has it all, applied as you change it and remembered:

  • Car: manual or automatic gears, and the driver aids: as the car was built, or ABS, traction control and stability control each on or off
  • Display: resolution (Auto adapts to hold the frame rate, or fix it from 50% to 150%), frame rate (60, 90 by default, 120 or Max, paced exactly on faster screens), field of view and a frame counter
  • Graphics: presets from Low to Ultra, render distance (Near to Extreme: the horizon from 2 to 5.5 km), how thickly trees and grass grow, shadows, glow and clouds
  • Sound: engine, and wind and rain, each on its own

Quick start

Requires Node.js 20+.

git clone https://github.com/SamarthPD-21/Revheadz.git
cd Revheadz
npm install
npm run dev          # http://localhost:3000
Command What it does
npm run dev Development server with hot reload
npm test Unit tests (simulation, gearbox, shifting, audio maths, configs, input, drag racing, timing)
npm run build Runs the tests, then exports the static site to out/
npm run lint ESLint
npm run sounds Regenerates the procedurally generated sounds (needs ffmpeg)

Controls

Keyboard Touch Action
I ENGINE START button, then the ⏻ button in the toolbar Start or stop the engine
W / ↑ (hold) GAS pad, right thumb Throttle
S / ↓ (hold) BRAKE pad, left thumb Brake
E / Q ⌃ / ⌄ buttons above the brake Shift up / down
N N button Neutral
Space Quick throttle blip
M 🔈 button Mute / unmute
F ⛶ button Fullscreen
[ / ] ‹ / › in the header Previous / next vehicle
V Vehicle name in the header Switch vehicle (searchable list)
/ Search the Playground

In Cruise, A / D (or ← / →) steer, B puts you back on the nearest road, C changes camera, T toggles the autopilot (then W / S set its speed), G switches manual and automatic gears, O opens the settings (Esc closes them) and H hides the HUD. Drag the mouse to look round the car. On a touch screen there are steering arrows.

In a drag race, Simple controls put everything on one button (Space, or tap): launch on the green, then shift on every shift light. Pro controls stage with S+W, launch by letting go of S, and shift with E/Q.

Turn your volume down before the first start. Engines are loud. On an iPhone, make sure the silent switch is off.

The garage

Vehicle Year Engine Gearbox Redline Sound
Toyota Supra MK4 1998 Twin-turbo straight-six 6-speed manual 6,800 Real (YouTube)
Nissan Skyline GT-R R34 1999 Twin-turbo straight-six 6-speed manual 8,000 Real (YouTube)
Nissan GT-R R35 2012 VR38DETT 3.8 L twin-turbo V6 6-speed dual-clutch 7,000 Real (Sonniss)
Mazda RX-7 FD3S 1993 Twin-turbo two-rotor Wankel 5-speed manual 8,000 Real (YouTube)
Honda S2000 AP1 2000 Naturally aspirated inline-four 6-speed manual 8,800 Real (YouTube)
Subaru Impreza WRX STI 2006 Turbocharged flat-four 6-speed manual 7,000 Real (YouTube)
Toyota Chaser JZX100 Tourer V 1998 Turbocharged straight-six 5-speed manual 7,000 Real (YouTube)
Nissan 370Z 2009 Naturally aspirated V6 6-speed manual 7,500 Real (YouTube)
Ferrari F40 1987 Twin-turbo flat-plane V8 5-speed manual 7,750 Real (YouTube)
Lexus LFA 2011 Naturally aspirated V10 6-speed automated manual 9,000 Real (YouTube)
Porsche 911 GT3 RS 2019 4.0 L naturally aspirated flat-six, 9,000 rpm 7-speed dual-clutch 8,800 Real (YouTube)
Porsche Carrera GT 2004 Naturally aspirated V10 6-speed manual 8,400 Real (YouTube)
Lamborghini Aventador SVJ 2019 Naturally aspirated V12 7-speed automated manual 8,500 Real (YouTube)
Pagani Zonda F 2005 Naturally aspirated V12 6-speed manual 7,500 Real (YouTube)
Bugatti Chiron 2016 8.0 L quad-turbo W16, 1,500 hp 7-speed dual-clutch 6,700 Real (YouTube)
Ferrari 458 Italia Straight Pipes 2013 4.5 L F136 flat-plane V8, straight pipes 7-speed dual-clutch 8,800 Real (Sonniss)
Audi R8 V10 Plus 2016 Naturally aspirated V10 7-speed dual-clutch 8,500 Real (YouTube)
Chevrolet Corvette Z06 2023 5.5 LT6 flat-plane V8 8-speed dual-clutch 8,500 Real (YouTube)
Ford Mustang GT 2018 5.0 Coyote V8 6-speed manual 7,400 Real (YouTube)
Dodge Challenger SRT Hellcat 2015 Supercharged 6.2 HEMI V8 8-speed automatic 6,200 Real (YouTube)
Plymouth Hemi 'Cuda 1971 426 Hemi big-block V8 4-speed manual 6,200 Real (Sonniss)
BMW M4 (F82) 2014 S55 3.0 L twin-turbo I6 7-speed dual-clutch 7,300 Real (Sonniss)
BMW M3 E46 2001 3.2 S54 inline-6 6-speed manual 7,900 Real (YouTube)
Mercedes-AMG C63 2008-2014 6.2 M156 V8 7-speed automatic 7,000 Real (YouTube)
Porsche 911 SC 1981 3.0 L air-cooled flat-six 5-speed manual 7,200 Real (Sonniss)
Aston Martin DB9 2017 5.9 L NA V12 6-speed automatic 6,750 Real (Sonniss)
Ford Focus RS 2016 2.3 L EcoBoost turbo I4 6-speed manual 6,800 Real (Sonniss)
Ferrari F2004 2004 3.0 L V10, 19,000 rpm 7-speed sequential 18,800 Real (YouTube)
Williams FW29 2007 Toyota RVX-07 2.4 L V8, 19,000 rpm 7-speed sequential 18,500 Real (Sonniss)
Mazda 787B 1991 Four-rotor Wankel 5-speed manual 9,000 Real (YouTube)
Subaru Impreza WRC 2006 Turbocharged flat-four, anti-lag 6-speed sequential 7,500 Real (YouTube)
Ducati Panigale V4 R 2019 1,000 cc V4, twin-pulse, 16,000 rpm 6-speed sequential (quickshifter) 15,500 Real (YouTube)
Kawasaki Ninja H2 2015 998 cc supercharged inline-four 6-speed sequential (quickshifter) 14,000 Real (YouTube)
BMW S1000RR 2015 999 cc inline-four 6-speed sequential (quickshifter) 13,500 Real (Sonniss)
Harley-Davidson Big Twin 2016 45-degree air-cooled V-twin 6-speed manual 5,500 Real (Sonniss)

Each engine's idle and redline match the machine it was recorded from. Vehicle names are used descriptively; the project isn't affiliated with any manufacturer.

How it works

flowchart LR
    Input["Input<br/>keyboard · touch"] --> Sim["Simulation<br/>fixed 120 Hz step"]
    Config["Vehicle config<br/>engine · gearbox · sounds"] --> Sim
    Sim -- "rpm · load · events" --> Audio["Audio engine<br/>Web Audio"]
    Sim -- "rpm · speed · gear" --> UI["Dashboard<br/>canvas, every frame"]
    Loader["Asset loader<br/>fetch · decode · cache"] --> Audio
Loading
  • One owner of state. Only the simulation changes engine state; audio and UI just read it. Because it steps at a fixed 120 Hz, a 60 Hz phone and a 144 Hz monitor behave the same.
  • React stays out of the hot path. RPM and speed are drawn straight onto canvases every frame. React only re-renders when the gear or ignition changes (useSyncExternalStore), or when a split or shift lands in the log.
  • One scene, two layouts. The drag race and the drive screen share a 2.5D canvas renderer (components/drag/scene25d.ts): an isometric camera, models lofted from cross-sections and lit per face, and a painter's sort. It is built to hold 60 fps: if a device falls behind for two seconds running, the canvas drops its resolution a step until it keeps up.
  • The cars are modelled, not imported. Each body style's side profile (the same one the strip draws) is stretched to the real car's length, height and wheelbase, its arches on the real wheel centres (components/cruise/carShapes.ts, which also lists each car's wings, scoops, lamps, intakes and exhausts), then lofted into a smooth skin through 150 cross-sections (components/cruise/carBody.ts): sills tucked under, flanks fullest low down, a shoulder at the beltline, a glasshouse leaning in to a crowned roof, the nose and tail rounded in plan and arches opened round each wheel. The glass is laid over it (the side windows follow the window outline, the screens are shaped panes inside their pillars), with lens headlights, light bars, mirrors, a diffuser, lathe-turned tyres, dished spoked rims with discs and calipers, and a soft contact shadow. The car stands on the ground under each of its tyres, never below the highest, and its body dives and rolls about its middle.
  • Cruise is real 3D. It uses three.js, loaded only on the cruise screen. The road (lib/cruise/road.ts) is a seeded curve: its bend is a sum of slow sine waves with straights mixed in, and its height is the land averaged along it with an 8% grade limit, so it rides the hills like a real road. The ground (lib/cruise/terrain.ts) is fractal noise, flattened into a verge under the road and banked up or down to it. It is drawn as 160 m tiles that are built a few per frame around the camera, plus a coarse far layer out to the horizon. The simulation still only knows speed along a line (plus gravity on a slope); the scene places the car on the road from it and adds the lane, body roll and pitch. Each machine's real figures (lib/cruise/specs.ts: power and torque with their revs, weight and its spread, drag area, drive layout, skidpad grip, aids, and the road tests to check against) give the simulation a road model: a monotone torque curve through the figures, drivetrain losses, rotating inertia and grip-limited brakes (tests/cruise-realism.test.ts holds every car to its 0-100 and top speed). It steers with a dynamic bicycle model (lib/cruise/handling.ts): slip angles at each axle into a "magic formula" tyre curve with a peak and a fall-off, axle loads that shift with braking and power, and a friction circle, so accelerating or braking leaves less grip for cornering; the cornering forces' drag goes back to the simulation as lost speed. The autopilot steers it by pure pursuit; in the air it flies on its own momentum. It stands on the ground through a probe (lib/cruise/ground.ts) that rebuilds the very triangles the ground is drawn with. Built map tiles are kept in IndexedDB (lib/cruise/tileCache.ts) and loaded back on the next visit. The simulation takes optional extras for the cruise, all off on the strip so drag races and replays are untouched: the road model, a traction limit (traction control trims the drive to it; without, drive past it becomes wheelspin, the revs flare and a spinning tyre grips less), a braking limit (ABS holds it; without, the wheels lock) and stalling. Clouds, rippling water, wind in the trees and grass, the dust and spray, and the exhaust flames are small shaders; skid marks are a ring of quads laid behind each sliding tyre (components/cruise/effects.ts). The guardrails are planned in 10 m cells from the seed alone (lib/cruise/barriers.ts: the bends and drops that want one, short gaps closed, stubs dropped, the odd gate cut in), so the road always has the same rails and the scene, its collisions and the map (components/cruise/minimap.ts) agree. The resolution adapts to hold the chosen frame rate (lib/cruise/frameGate.ts paces the frames and measures the screen's refresh).
  • Splits to the millisecond. The page samples the car once a frame, and every split, and the moment the revs reach the shift light, is interpolated between samples, so timing doesn't depend on the frame rate.
  • Sample blending. Each vehicle has looping recordings at several RPMs, for on-load (accelerating) and overrun. Each frame the two loops nearest the current RPM are crossfaded, pitched to match, and blended by engine load. Every loop starts at the same instant and is pitched by the same rpm / sampleRpm rule, so all loops stay in step.
  • Loop shuffling. Loops cut from a fast dyno pull can be under a second long, and looped as-is they buzz with repetition. When a real-recording set loads, lib/audio/loopShuffle.ts re-splices each short loop into ~5 s of material: grains of about one and a half engine cycles in random order, each splice placed where the waveform best matches (a WSOLA-style search) and crossfaded, ending on a splice back to its own start.
  • Shifting in two phases. First the drive cuts out. On an upshift the revs fall under engine braking; on a downshift an automatic blip matches revs, and you hear it. Then the clutch engages: revs blend onto the new gear and torque returns. Each kind of gearbox has its own timing, and the ones with a second clutch or a torque converter keep some drive flowing through the first phase.
  • Lift-offs are judged. Backfires, blow-off and overrun crackle only happen once the throttle has stayed shut for a moment without a gear change, so lifting to shift never triggers them.
  • Drag classes are balanced by maths. Two typical drivers in identical cars finish about ±80 ms apart; a 100 ms car advantage lets the slower car win only ~9% of races (Monte Carlo over the real physics). So within each class every car's engine is trimmed (lib/drag/parity.json, regenerated with GEN_PARITY=1 npx vitest run tests/drag-parity.test.ts) until its perfect run matches the class target within a few ms, and a test keeps it that way.
  • Drag racing is deterministic. A run is the regular physics stepped in 1 ms steps from a fixed staged state, driven only by when the driver launched and shifted. Both browsers replay both drive logs, so they agree on the result to the millisecond, and network lag can't change who wins (each reaction is timed against the player's own tree on their own clock). Each car's shift light sits at its fastest shift point, found by searching its physics, and the drag rev limiter sits there too, so every millisecond late on a shift costs time. Players connect peer to peer over WebRTC (PeerJS; its public broker only introduces them).
  • The same result in every browser. Math.exp can differ in the last bit between JavaScript engines, which would let a replayed run drift. The physics uses its own exponential (lib/sim/portableMath.ts), built only from basic arithmetic, which every engine rounds the same way. A test bans the built-in maths functions from the physics and pins the replayed times of fixed drive logs, so a change that moves them has to bump the replay version.
  • Browser rules respected. Audio starts only from the ignition tap, as autoplay policy requires. It pauses when the tab is hidden and fully stops when you leave the page.

Where the sounds come from

Real recordings. Ten engines come from free, royalty-free Sonniss #GameAudioGDC bundles (Pole Position Production, Dramatic Cat and Game Audio Factory). The other 25 engines come from YouTube videos (dyno pulls, cold starts, pure-sound and onboard clips), credited to each channel on the Credits page. scripts/build-real-sounds.mjs turns raw recordings into game-ready loops, using scripts/real-sounds.json (Sonniss vehicles) and one manifest per vehicle in scripts/real-sounds.d/<id>.json. A source is either a direct url or a youtube video id, downloaded once with yt-dlp.

  1. Track the engine's speed from its cycle frequency, the spacing of the harmonic "comb" every engine produces (RPM = cycle Hz × 120). Noisy sweeps can use hand-checked anchor points read off a spectrogram.
  2. Cut steady-RPM sections, or slices of full-throttle runs, and flatten their pitch to one exact RPM. Gaps no recording covers can be filled by resampling the nearest real loop (shiftFrom).
  3. Loop each section seamlessly with a correlated crossfade. Idle and steady holds can be left untouched to keep their natural character. Loops cut from a second recording can be EQ-matched to the first, so the change in mic or session isn't audible.
  4. Screen for voices. Every YouTube source window and built file was checked with a speech recogniser (faster-whisper) plus a voice-activity detector, and anything with talking was re-cut or replaced.
  5. Finish: use real deceleration loops for overrun where the recording has them (otherwise darker variants), normalise loudness along a smooth RPM curve, cut the real start-up and shutdown sounds, encode .ogg and .mp3, and write the vehicle config and credits.

Engine model. scripts/generate-sounds.mjs is a physical engine model. It uses real firing orders and crank angles, per-bank exhaust pipes with reflections, muffler resonances, intake roar, valvetrain noise, turbo whistle and overrun crackle. Every vehicle gets an engine-model set (in sounds/gen/) for the Real / Model switch. A vehicle can borrow another's voice with "voice": "<id>".

node scripts/build-real-sounds.mjs muscle_v8      # rebuild one vehicle (needs ffmpeg and yt-dlp; downloads sources once)
node scripts/build-real-sounds.mjs --all          # rebuild every real-recording vehicle
node scripts/build-real-sounds.mjs --credits-only # rewrite credits.json from the manifests
npm run sounds                                    # regenerate the engine-model sounds

Source recordings are cached in .sound-cache/, which is not committed.

Project structure

app/                     Pages: home (/), playground (/playground), drive (/drive/[vehicleId]), drag racing (/drag),
                         cruise (/cruise, /cruise/[vehicleId]), credits
components/              React UI: Simulator, TrackView (the endless strip), gauges, shift lights, controls, garage cards
  drag/                  Drag racing UI and the shared 2.5D scene renderer
  cruise/                Cruise in three.js: scene, world, sky, car models, effects, map, odometer, settings
hooks/                   useEngineState: the slow-changing state React subscribes to
lib/
  sim/                   Engine, Gearbox, Simulation: pure TypeScript, no React
  drag/                  Drag racing: deterministic runs, classes and parity trims, CPU driver, peer-to-peer rooms,
                         challenge links, launch and shift ratings
  track/                 Run timer (splits and top speed) and the shift log
  cruise/                Cruise's road, land, guardrails, ground probe, real-car specs, handling, autopilot,
                         frame pacing and map cache
  audio/                 AudioEngine, SampleLayer, loop shuffling, card previews, SynthEngine (AudioWorklet), OneShots, blend maths
  assets/                Sound fetching, decoding and caching
  input/                 Keyboard and touch → throttle, brake and commands
  vehicles/              Typed configs, validation, build-time file checks
public/vehicles/<id>/    config.json + sounds/ (one folder per vehicle)
scripts/                 Sound pipelines: build-real-sounds, generate-sounds, audio-analysis
tests/                   Vitest suites

Adding a vehicle

  1. Copy a folder in public/vehicles/ and edit config.json: engine, gearbox (including type), dynamics, optional turbo, and ui.
  2. Give it sounds, in one of three ways:
    • From recordings: add scripts/real-sounds.d/<id>.json (sources can be YouTube ids) and run node scripts/build-real-sounds.mjs <id>.
    • From the engine model: add a voice to VOICES in scripts/generate-sounds.mjs and run node scripts/generate-sounds.mjs <id>.
    • By hand: drop in .ogg and .mp3 loops named by RPM, and fill in the audio section.
  3. Import the config in lib/vehicles/index.ts and add it to the list.
  4. Credit its sounds: node scripts/build-real-sounds.mjs --credits-only (or edit credits.json by hand).

npm test and npm run build fail if a config is invalid or a referenced sound file is missing. They also fail if the loudest loop at any RPM would be pitched too far from its recording.

Car models (Blender)

Every car in Cruise (not the single-seaters or the bikes) has a model built in Blender by a script, from the car's real length, width, height and wheelbase, its side profile and window outline, and the details listed for it in components/cruise/carShapes.ts (wings, grilles, lamps, intakes, exhausts and so on). The body is lofted into a cage and subdivided into smooth panels; glass, shut lines, lamps, grilles, mirrors, handles and aero are laid onto the finished surface, and each wheel (tyre, spoked rim, disc, caliper) is built at its real size. They're exported as Draco-compressed .glbs, about 300 KB each, to public/vehicles/<id>/model.glb and listed in lib/cruise/models.ts; the game loads them over its built-in bodies (components/cruise/carGltf.ts).

To change a car and rebuild its model:

JITI_JSX=1 npx jiti scripts/blender/export-cars.ts        # the cars' data -> scripts/blender/cars.json
BLENDER=/path/to/blender scripts/blender/build-cars.sh    # every car (or name some: ... build-cars.sh supra_mk4)
PREVIEW_DIR=/tmp/previews scripts/blender/build-cars.sh hellcat   # with three rendered views to check it by

Blender 4.2 or newer; a portable download works (no install needed).

Deploying

The site exports to static files, so any static host works.

Vercel: import the repo at vercel.com/new and deploy; no settings needed. vercel.json caches files under /vehicles/ for a year, so rename a sound file when you change it. Every push to main redeploys.

Optional environment variables:

Variable Purpose
NEXT_PUBLIC_FEEDBACK_URL Shows a "Send feedback" link on the home page (e.g. a Google Form)
NEXT_PUBLIC_SITE_URL Your custom domain, so social share images use absolute URLs
NEXT_PUBLIC_TURN_URLS A TURN relay for online drag rooms, comma-separated (e.g. turn:global.relay.metered.ca:80,turns:global.relay.metered.ca:443?transport=tcp)
NEXT_PUBLIC_TURN_USERNAME / NEXT_PUBLIC_TURN_CREDENTIAL That relay's username and password
NEXT_PUBLIC_PEER_HOST (_PORT, _PATH) Your own PeerJS server, instead of the public one

Online rooms and relays. Two players' browsers connect directly, using free public STUN servers to find each other. That works on most home networks, but when both sit behind strict routers (mobile data, offices, some ISPs) the traffic has to go through a TURN relay, and there's no free public relay left that works without an account. For rooms that connect anywhere, make a free account with a TURN provider (Metered and Cloudflare both have a free tier) and set the three TURN variables above. Without one, a room that can't connect says so after 15 seconds instead of waiting for ever.

Vercel's free Hobby plan is for non-commercial use. If you ever monetise, the same static build runs unchanged on Netlify or Cloudflare Pages.

Tech stack

Next.js (App Router, static export) · TypeScript · Tailwind CSS · Web Audio API with AudioWorklet · Canvas 2D · three.js (WebGL, Cruise) · Vitest · ffmpeg for the sound pipelines

Credits

  • Real engine recordings: Pole Position Production, Dramatic Cat and Game Audio Factory, from the Sonniss #GameAudioGDC bundles, under the Sonniss GDC bundle license (royalty-free, commercial use allowed).
  • YouTube recordings: the channels listed on the Credits page. Their audio is used for this personal project only; it is not covered by an open license.
  • Generated sounds, the Blender-built car models and code: Revheadz. The models are made by our own script in Blender (GPL; Blender's licence doesn't extend to what you make with it); the Draco decoder in public/draco/ is Google's (Apache 2.0), as shipped with three.js.

The in-app Credits page lists every recording used.

About

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages