The Manual, Checked Against The Code
A shared settings UI with a real key-binding surface, an engine-generic Pickup class, a 56-item QA matrix, and a README version corrected to 0.9.13.
One Settings Screen, Two Places
A shared FPSSettingsView used by both the lobby Settings tab and the in-game overlay. Tabs: Graphics / Audio / Controls / Interface. Controls includes a physical keyboard, a virtual keyboard and a CSS mouse diagram, slot-first binding, visible duplicate bindings, a hierarchical action menu, and a Controller subtab that is a disabled placeholder — which is more honest than a shipping half-feature.
Weapon binds default to only blade/primary/secondary on 1/2/3. Labels read Blade, Primary, Secondary. "Authored-feel" toggles are hidden from the public UI.
Pickup Became Engine Code
src/engine/world/Pickup.ts — model loading, optional Havok toss with settle, BSP drop-to-ground with raycast and collision fallback, glow pulse, respawn and server deactivation. FPSPickup subclasses it for weapon/ammo/health/armor.
The point of the split is written in the changelog: so future SHAG submodules can ship pickups without the engine importing a game.
The Leak Sweep
GameTimer, EngineScene, InputSystem, WeaponViewManager and CameraSystem all now store their unsubscribe handles and dispose properly. CameraSystem.registerController() disposes the controller it overwrites. EngineScene.start() is idempotent behind a started flag. A dead engine/player/BotNames.ts — 90 lines, zero importers — was deleted.
Accuracy
The README.md version read 0.9.10. It now reads 0.9.13. The architecture diagram was redrawn and engine/index.ts reframed. A 56-item matrix went into docs/research/0.9.13-QA-improvements.md.
Deferred and documented rather than shipped: further BspMeshBuilder splitting, SweepCollisionBackend splitting, BinaryProtocol extraction, FPSController splitting, headless map-to-server, and Web Worker offload.
Known Issues: none stated — deferred items are listed as deferred, not as caveats.