Posted October 06, 2026 by Fonnesx
A record of the five priority improvements from the Standard Edition roadmap, in the order they were built. Each entry covers what changed, why it mattered, and the key implementation notes.
Version: v1.8.2 Priority: #1 from the roadmap Effort: Small Impact: Huge — instantly makes the engine feel alive
Before this, hitting the redline just clipped the RPM. The needle would sit flat at max and the sound would stay at one pitch. It read as a hard ceiling, not a limiter.
triggerLimiterPop() — a sharp crackle plus a low thud — mimicking a real ignition cut.
limiter>span class=""> state, and the whole container gains a rapid shake animation.
0.012–0.045 to 0.45 during bounce, so the drop is audible in real time rather than smoothed away.
It audibly bounces, visually shakes, and physically drops and recovers RPM. This alone was the single biggest realism boost in the whole Standard edition.
Version: v1.8.3 (shipped with a full audio re-voice as well) Priority: #2 from the roadmap Effort: Small Impact: Huge — realism per line of code
Downshifting in Drive and Drag modes just dropped the gear. Real drivers blip the throttle on a downshift to match revs (heel-toe), and sportbike riders do the same. Without it, the downshift felt like a menu selection, not a mechanical action.
startDownshiftBlip() method fires whenever shiftDown() is called in Drive or Drag mode and the car is moving above ~4 mph.
playBlipSound() emits a short band-passed noise burst, sweeping from 480 Hz up to 1500 Hz — a characteristic "bwap".
⚙️ Gear 3 · 🦶 Blip.
sin(π · progress), so it's smooth in and out — no clicks.
0.05 + strength × 0.11 of the RPM range, so even at 100% it stays musical.
Downshifting now has rhythm. Combined with the tone re-voice, the whole soundtrack became less synthetic and more like a real car or bike.
Version: v1.8.4 (also shipped an RPM-needle sync fix) Priority: #3 from the roadmap Effort: Medium Impact: High — every engine now has a fingerprint
Before this, every engine was built from the same 4 detuned saw oscillators. A V12 sounded like a sped-up V8. An I4 sounded like a slightly smaller V8. There was no character — no sense that each cylinder fires with its own tiny timing and gain variance.
rpm / 120 Hz) drives a subtle amplitude wobble on each oscillator, with a different phase offset per oscillator. This mimics different cylinders sitting at different points in the firing order.
oscGain1…4) so the AM wobble can modulate them independently.
gauge.setRpm() and updateUI(). The needle and digital readout can no longer disagree.
A V8 sounds like a V8. A V12 sounds like a V12. A V-twin sounds like a V-twin. The synth stopped sounding like one engine with a pitch knob.
Version: v1.8.5 Priority: #4 from the roadmap Effort: Small Impact: Big engagement boost
>span class="">Every completed 0–60 or 1/4-mile run was lost the moment it finished. There was no way to compare your last attempt against the one before. No personal best. No sense of progress.
★ prefix.
🏆 New best 0‑60: 5.42s.
localStorage under engineSoundLabHistory_v1, capped at 5 entries per category, and survives page reloads.
onZeroToSixty>span class=""> and onQuarterMile. The app wires these once during init(), and they fire the moment the finish line is crossed.
isBest>span class=""> flag is recomputed on every insert against the trimmed list, so it stays correct after the list rolls over.
Runs now have stakes. You can see the improvement. You know when you've beaten your own best. Small UI, big behavioral change.
Version: v1.8.6 Priority: #5 from the roadmap Effort: Medium Impact: Makes it feel like a real app
The app ran in a browser tab. No install option. No home-screen icon. No offline support. Every launch felt like visiting a website, not opening an app.
PWA / installability
data: URL — the app stays a single file.
apple-touch-icon, apple-touch-icon-precomposed, and manifest icons at 192 and 512 (both any and maskable).
apple-mobile-web-app-capable, status bar style, title) are set so a home-screen launch gives a native-feeling full-screen experience.
beforeinstallprompt listener is registered in the <head> before anything else, so the prompt is captured the instant the browser fires it. A custom installpromptready event re-broadcasts it to the app.
Install button + help
Offline awareness
navigator.onLine === false, and a toast fires on both transitions. Since the entire app is a single self-contained HTML file with zero external dependencies, everything keeps working offline.
Standalone detection
display-mode: standalone/fullscreen/minimal-ui>span class=""> (and the iOS navigator.standalone flag) and adds a standalone class to <body>, which shows a subtle ✓ Installed pill in the header.
Service worker (graceful)
./sw.js. Since a single-file app can't host its own SW, this silently fails in that case — but if you ever drop a sw.js next to the HTML, the app picks it up automatically and gains full SW-based offline caching on top of the manifest-driven install.
btoa(unescape(encodeURIComponent(svg)))>span class="">, then prepending data:image/svg+xml;base64,.
<meta name="theme-color"> is split by prefers-color-scheme so the browser UI chrome matches the light/dark theme.
The app installs like a native app on desktop and mobile. It launches in its own window, works offline, and has a home-screen icon. It stopped feeling like a website and started feeling like software.
Once all five priorities were shipped, three more builds landed as extras:
| # | Priority item | Status | Version |
|---|---|---|---|
| 1 | Rev-limiter bounce | Done | v1.8.2 |
| 2 | Downshift blip | Done | v1.8.3 |
| 3 | Per-cylinder variation | Done | v1.8.4 |
| 4 | Recent run history | Done | v1.8.5 |
| 5 | PWA / offline mode | Done | v1.8.6 |
All five priorities from the original roadmap are complete. Three follow-on releases (bikes, correct tach, faster driving) have landed on top. The current build is v1.8.9.