# Combat feedback — baseline audit (goal: make combat feel and read) Scope: range = `combat.html` / `/combat` (js/combat/CombatScene.js), main game = `index.html?combat` (js/scenes/GameScene.js + js/combat/CombatSystem.js + js/ui/CombatBar.js). Shared: js/combat/{Combat, EnemyShip,Bullet,Fx}.js, data/combat.json. ## What EXISTS today ### VFX (both contexts, shared Fx.js: additive soft-dot flashes/rings/sparks, world-space, stepped in update) - Player shot: muzzle flash (range 30 px / main 26 px, 110 ms) - Enemy shot: muzzle flash (28 px, 100 ms) - Bullet impact: pink flash on enemy hits, blue on player hits (130 ms) - Player hit: generic white flash on the ship (60 px, 140 ms) — NOT distinct shield vs hull - Enemy kill: `Fx.explode` (white core + color bloom + ring + 22 sparks) - Player down: `Fx.explode` + range-only "SIGNAL LOST" center message (main game: no message) - Player respawn: cyan flash - Ram: white flash at contact midpoint - Thrust glow dot (range only) ### SFX - **Zero combat SFX in both contexts.** - Range loads NO audio at all (CombatScene.preload = textures only) → range SFX needs a load step. - Main game loads all 17 files from data/sfx.json in GameScene.preload. - Shared voice exists: `playSfxOn(scene, name)` / `playSfxOneOfOn` (js/utils/Sfx.js) with guards (sfx.enabled, sound manager, audio-cache check). No combat keys in data/sfx.json yet. - Repurposable existing files (no new binaries): scan-01 (ping), ui_click/ui_hover (ticks), ui_window (whoosh), mining-02 (crack), thunder-01..04 (boom set), type-construct (build-up), type-deconstruct (collapse). ### Readability / UI - Range HUD: top-left armor panel (HULL/SHD bars + numbers), top-right KILLS counter, center message. **No damage numbers, no kill feed, no target indicator, no bar hit-flash, no threat cues.** - CombatBar (main game): vertical SHD/HUL gauges (fill = level, updated each frame via setStats), 8 empty skill seats (cast() stub), ENR gauge (static full). **No hit-flash, no numeric readout, no feed, no target read.** - CombatSystem hooks: onPlayerDamage / onPlayerDown / onPlayerUp / onKill / onActiveChange — GameScene wires ONLY onActiveChange (bar swap). The other four are available seams (currently null). - Range has NO hooks at all — its damage/kill/down paths live inline in CombatScene. ### Ship handling - Range (WASD): CombatScene.updatePlayer applies combat.player rotSpeed 4.8 rad/s (instant rate cap), thrust 1500 px/s², brake 0.6×thrust (S/Down), maxSpeed 560 cap. **Drag: combat.player.drag 1.6 is DEAD CONFIG — not read anywhere; effective drag is ship.drag 2.4 from data/ship.json via Ship.update.** - Main game: click-to-fly (Ship.js: ship.json thrust 900, maxSpeed 480, drag 2.4, rotSpeed 10) — mouse steers, combat adds auto-fire only. WASD not used there. - No throttle ramp, no rotation smoothing — both feel instant/steppy (candidate micro-feel gaps). ### Duplication (parity risk) - fire/kill/respawn/damagePlayer logic is COPIED between CombatScene and CombatSystem (each has its own fx.flash calls, its own armor bookkeeping, its own respawn timers). Fx.js itself is shared. - SFX wiring must go into BOTH copy sites (or a shared helper) to stay in sync. ## Gaps vs success criteria (per feedback type) | Event | Range VFX | Main VFX | SFX (both) | Notes | |---|---|---|---|---| | Firing (player) | muzzle flash | muzzle flash | none | distinct sound needed | | Firing (enemy) | muzzle flash | muzzle flash | none | (nice-to-have, distinct + quieter) | | Bullet impact (enemy hit) | flash | flash | none | no damage number | | Shield hit (player) | generic flash | generic flash | none | not distinct from hull hit | | Hull hit (player) | generic flash | generic flash | none | not distinct; bar doesn't flash | | Enemy kill | explode | explode | none | no kill feed | | Player down | explode + msg | explode only | none | main game gives no down cue | | Player respawn | flash | flash | none | none distinct | | Readability item | Range | Main | |---|---|---| | Damage numbers (both sides) | missing | missing | | Target/lock indicator | missing | missing (auto-fire target invisible) | | Threat cues (hostile state) | missing | missing | | Kill feed | KILLS counter only | missing | | Bar hit-flash (SHD/HUL) | N/A (own HUD panel) | missing | ## Ground rules found in code (must keep) - Pure rules in js/combat/Combat.js, tested by dev/combat.test.mjs (344 lines; stubs Phaser; covers applyDamage/headingOf/orbitStep/EnemyShip/Bullet/CombatSystem incl. auto-fire, swept hits, rams, respawn, cast-stub). New pure feel rules belong there + tested. - Fx items are world-space additive dots; combat scene steps fx.update(delta) in its loop. - No arcade colliders; swept circle checks (hitsSwept) in both contexts. - All numbers in data/combat.json; CombatBar built like ActionBar (scene.add.* + container parenting). - data/sfx.json key = play name, asset queued `sfx_`; sfx.enabled master switch. - Theme palette: neon #00e5ff, neon2 #ff2d6f, amber #ffc94d, ink #eaf6ff, dim #7d92c4, faint #3d4c74.