# HEAVEN'S GATE — Performance Benchmarks

Measured with an automated harness (`test/bench.mjs`) driving the real game in
headless Chromium 149 (Windows 10 x64, 1280×720, device pixel ratio 1) via the
Chrome DevTools Protocol. No mocks — the browser boots the real game, plays it,
and samples the engine's own counters.

## Machine / method

- Headless Chromium 149, GPU-accelerated canvas, vsync-capped
- Scenario sampling: 12–14 s per scenario, fps averaged over the engine's
  per-frame delta history (`G._fps`, 60-frame window)
- Draw calls / instanced counts captured per frame from the renderer
- Population: life-sim target 90 pedestrians + 34 vehicles at full density

## Boot

| Metric | Value |
|---|---|
| Cold boot → title (city generation included) | **2,310 ms** |
| World built | 357 buildings, 634 colliders, 3,330 static instances |
| Code payload | 8 JS files + HTML/CSS, zero dependencies, zero asset downloads |

## Steady-state gameplay (1280×720, render scale 1.0)

| Scenario | FPS | Draw calls/frame | Instances/frame | JS heap |
|---|---|---|---|---|
| On foot — downtown, day | **60.1** | 7 | 1,685 | 12 MB |
| On foot — downtown, night | **60.0** | 7 | 1,795 | 12 MB |
| Driving — through traffic | **60.1** | 7 | 2,310 | 19 MB |
| Shootout — police, night | **60.1** | 7 | 1,400 | 15 MB |

60 fps is the vsync ceiling in every scenario — the engine holds the frame
budget with full crowd density and never engages adaptive resolution
(scale stays 1.0). On weaker GPUs the adaptive scaler (`_adaptivePerf`) trades
render resolution to hold ≥ 48–52 fps automatically.

## Why the draw-call count is 7

The whole frame is five instanced pipelines (sky, ground, boxes, quads ×3
blend groups, lines). Every building, lamp, vehicle, human limb, particle and
decal is an instance of a unit box or a quad — so the CPU submits ~7 draw
calls regardless of scene complexity, and per-frame allocation is zero
(pre-allocated record pools, no GC pressure: heap stays under 20 MB).

## Notes on honesty

- These are headless-Chromium numbers; a normal desktop browser on the same
  machine performs the same or better (headless shares the GPU path).
- Low-end integrated GPUs are handled by adaptive resolution + crowd scaling
  (`perfLevel`), not by dropping simulation features.
- Re-run any time: `node test/pass1.mjs && node test/pass2.mjs && node test/bench.mjs`
