2026-06-10 14:26:58 +02:00
# MAP.md — Barkour code index
Vanilla-JS canvas game, no build step. ES modules under `js/` , served statically.
- `index.html` — DOM shell: all screens (menu/host/join/charselect/game/result) as overlay divs; loads PeerJS from CDN (online play only), then `js/main.js` .
- `style.css` — overlay/menu styling; canvas letterboxed to 16:9 via CSS.
- `js/consts.js` — grid (TILE=12, 80× 45 → 960× 540), tile enum `T` , input bitmask `B` , item ids, physics constants, snapshot rate.
- `js/rng.js` — seeded mulberry32 (`makeRng`); `randomSeed()` is UI-side only.
feat: top-down 'Dogpit' arena mode (dota-like view)
Second game mode selectable at dog select (host-authoritative online):
- js/sim_arena.js: top-down sim, same export surface as sim.js — x/y plane
plus a z hop axis (Space / comma); KOs by knocking dogs into abyss pits
- js/mapgen_arena.js: mirrored symmetric arenas — walls, pits, center
clearing, guaranteed spawn-to-center corridors, crystals/spikes/launch
pads, mirrored saw pairs; fallback pit pair since pits are the only KO
mechanic
- specials re-imagined per dog: zoom dash, ram + hop-slam, zip-leash
slingshot, blink, hover (floats over pits/saws/spikes)
- render: arena tiles with wall shadows + void pits, top-down dog drawing
with z-lift over a ground shadow; new fall event/sfx
- B.HOP input bit so 'up' can mean north in top-down (Space also jumps in
side view); mode toggle UI + mode carried in start/rematch net messages
Tested: arena mapgen determinism/symmetry/connectivity + chaotic matches +
pit/hop scenarios headless; local chaos + full P2P arena match (host mode
flip syncs to client) in two headless browsers with zero page errors.
2026-06-10 15:23:22 +02:00
- `js/mapgen.js` — side-view `generateMap(seed)` : ground heightmap, pits, towers, islands, one-way platforms, crystals (hp 3), pads, spikes, rail saws, spawns; `PALETTES` ; `sawPos()` polyline eval (ping-pong or loop).
- `js/mapgen_arena.js` — top-down `generateArena(seed)` : mirrored (left↔right) walls/pits, corner spawns, guaranteed corridors spawn→center, fallback pit pair (pits are the only KO mechanic), mirrored saw pairs.
2026-06-10 14:26:58 +02:00
- `js/physics.js` — center-based AABB vs tile grid: `moveEntity` (per-axis, one-way platform aware), `raycast` , `boxFree` , `standingOnPlat` .
- `js/characters.js` — `CHARS` data (stats + visual params) and `updateCharacter()` : per-dog special movement (air dash / charge+pound / grapple constraint / blink / jetpack).
feat: top-down 'Dogpit' arena mode (dota-like view)
Second game mode selectable at dog select (host-authoritative online):
- js/sim_arena.js: top-down sim, same export surface as sim.js — x/y plane
plus a z hop axis (Space / comma); KOs by knocking dogs into abyss pits
- js/mapgen_arena.js: mirrored symmetric arenas — walls, pits, center
clearing, guaranteed spawn-to-center corridors, crystals/spikes/launch
pads, mirrored saw pairs; fallback pit pair since pits are the only KO
mechanic
- specials re-imagined per dog: zoom dash, ram + hop-slam, zip-leash
slingshot, blink, hover (floats over pits/saws/spikes)
- render: arena tiles with wall shadows + void pits, top-down dog drawing
with z-lift over a ground shadow; new fall event/sfx
- B.HOP input bit so 'up' can mean north in top-down (Space also jumps in
side view); mode toggle UI + mode carried in start/rematch net messages
Tested: arena mapgen determinism/symmetry/connectivity + chaotic matches +
pit/hop scenarios headless; local chaos + full P2P arena match (host mode
flip syncs to client) in two headless browsers with zero page errors.
2026-06-10 15:23:22 +02:00
- `js/sim.js` — **authoritative, DOM-free side-view sim** : `createGame` , `step(game, inputs)` (60 Hz), combat (`hurt`: damage% → knockback), mining/items/hazards/KO/respawn/match-end, `snapshot` /`applySnapshot` for netplay. Sets `game.kind='side'` .
- `js/sim_arena.js` — top-down "Dogpit" sim, **same export surface as sim.js** (main.js swaps modules per match). x/y plane + z hop axis; KOs via pit falls; specials re-imagined per dog (dash cooldown, ram/slam, zip-leash, blink, hover). Sets `game.kind='arena'` .
2026-06-10 14:26:58 +02:00
- `js/input.js` — keyboard → bitmasks; slot 0 = WASD+FGH, slot 1 = arrows+KL;.
fix: address all 21 confirmed findings from multi-agent review + live P2P testing
Sim: clamp knockback under tile size (wall tunneling), bomb/ball terminal
velocity, grapple constraint no longer drags players into terrain, bite
window ends on getting hit, shield/boost cleared on death, spawn invuln
preserved through countdown, spike/saw events only on real damage.
Mapgen: spawn footprint validation (was embedding dogs in 58% of seeds),
saw paths rejected if they grind terrain or sweep spawns, towers no longer
hang slabs over pits. Net: heartbeat+watchdog for dead peers, broker-error
tolerance once P2P link is up, join/host reentrancy guards. UI: text-field
keystrokes no longer hit game hotkeys, audio unlocks on mouse, textBaseline
leak, snapshot carries onGround/landT so client dogs animate.
2026-06-10 14:47:40 +02:00
- `js/net.js` — PeerJS wrapper: `hostRoom` /`joinRoom`; room key = host peer id suffix; signaling via PeerJS cloud, game traffic pure P2P. Runs a 2s heartbeat + 8s watchdog (WebRTC close events are unreliable); broker `network` errors are ignored once the data channel is up.
feat: top-down 'Dogpit' arena mode (dota-like view)
Second game mode selectable at dog select (host-authoritative online):
- js/sim_arena.js: top-down sim, same export surface as sim.js — x/y plane
plus a z hop axis (Space / comma); KOs by knocking dogs into abyss pits
- js/mapgen_arena.js: mirrored symmetric arenas — walls, pits, center
clearing, guaranteed spawn-to-center corridors, crystals/spikes/launch
pads, mirrored saw pairs; fallback pit pair since pits are the only KO
mechanic
- specials re-imagined per dog: zoom dash, ram + hop-slam, zip-leash
slingshot, blink, hover (floats over pits/saws/spikes)
- render: arena tiles with wall shadows + void pits, top-down dog drawing
with z-lift over a ground shadow; new fall event/sfx
- B.HOP input bit so 'up' can mean north in top-down (Space also jumps in
side view); mode toggle UI + mode carried in start/rematch net messages
Tested: arena mapgen determinism/symmetry/connectivity + chaotic matches +
pit/hop scenarios headless; local chaos + full P2P arena match (host mode
flip syncs to client) in two headless browsers with zero page errors.
2026-06-10 15:23:22 +02:00
- `js/render.js` — canvas: cached seeded background, tiles, procedural dog drawing, particles/ghosts driven by sim events (`fxEvents`), HUD, banners. Branches on `game.kind` : side view (`drawTiles`/`drawDog`) vs top-down (`drawTilesArena`/`drawDogTop`, z-height lifts the dog off its shadow).
2026-06-10 14:26:58 +02:00
- `js/audio.js` — WebAudio-synthesized sfx; `playEvents` maps sim events → sounds.
feat: top-down 'Dogpit' arena mode (dota-like view)
Second game mode selectable at dog select (host-authoritative online):
- js/sim_arena.js: top-down sim, same export surface as sim.js — x/y plane
plus a z hop axis (Space / comma); KOs by knocking dogs into abyss pits
- js/mapgen_arena.js: mirrored symmetric arenas — walls, pits, center
clearing, guaranteed spawn-to-center corridors, crystals/spikes/launch
pads, mirrored saw pairs; fallback pit pair since pits are the only KO
mechanic
- specials re-imagined per dog: zoom dash, ram + hop-slam, zip-leash
slingshot, blink, hover (floats over pits/saws/spikes)
- render: arena tiles with wall shadows + void pits, top-down dog drawing
with z-lift over a ground shadow; new fall event/sfx
- B.HOP input bit so 'up' can mean north in top-down (Space also jumps in
side view); mode toggle UI + mode carried in start/rematch net messages
Tested: arena mapgen determinism/symmetry/connectivity + chaotic matches +
pit/hop scenarios headless; local chaos + full P2P arena match (host mode
flip syncs to client) in two headless browsers with zero page errors.
2026-06-10 15:23:22 +02:00
- `js/main.js` — app state machine: screens, char select (incl. mode toggle: `gameMode` 'side'|'arena', host-authoritative over the wire via `mode` /`start`/`rematch` messages), three match drivers (local / host / client) sharing one rAF fixed-timestep loop; `matchSim` points at the active sim module.
2026-06-10 14:26:58 +02:00
- `test/smoke.mjs` — `npm test` : headless mapgen determinism + chaotic full matches + targeted mining/stocks scenarios.
## Conventions & gotchas
- **Client never simulates.** In netplay the joiner only sends input bits and renders `applySnapshot` state; anything render reads must survive the snapshot round-trip (player `st` is re-shaped there).
- **Sim events are the only side-channel**: fx, audio, *and* client tile mutations (`tile`/`crack` events) ride on them. Host accumulates `pendingEvs` between snapshots.
- All sim/mapgen randomness must use the seeded RNG — never `Math.random()` inside `js/sim.js` /`js/mapgen.js`/`js/characters.js` paths.
- Velocities must stay < TILE ( 12 px / tick ) or AABB collision tunnels .
- 7 as an arc end-angle in render means "> 2π" (full circle), a deliberate shorthand.