Bodies in a snapshot can now carry an optional side. When they do, each non-mate side gets its own colour on the 3D view, the map and the last-seen outlines. A body without side draws exactly as before, so val, which doesn't send it, looks the same. bun test passes (323 tests). I checked that the new tests fail when the code is broken: with side colouring removed, three tests fail; with today's enemy red changed, two fail; with side dropped from last-seen marks, one fails.
What a game must send for 3+ sides: on every body in snap.players, add side: string, meaning any stable name for the body's side (a team id; in a free-for-all, the player's own id). Keep sending mate: boolean as today, true when the body is on the viewer's side. Mates keep the mate blue, the viewer keeps white, the dead keep grey and enemies keep the chevron, whatever their side.
What changed
New static/engine/sides.js: a fixed palette of six colours, none of them blue, grey or white. Each side gets the next colour the first time it is seen and keeps it for as long as the page is open, so the same side has the same colour every frame. The first side seen gets today's enemy red. A seventh side goes back to the first colour.
scene.js and topdown.js: enemy colours now come from that palette. The 3D view and the map share one record of which side has which colour, so they agree.
presence.js: last-seen marks remember side, so their outlines match the body.
src/engine/body.ts:side is optional in the contract. If it is sent, it must be a string.
Tests
3 sides:scene.test.ts and a new topdown.test.ts draw three enemy sides and get three different colours. The next frame, with the bodies listed in reverse order, gives the same colours.
No side: the same two files pin today's exact colours: #3f9fd6/#d8483f and the mark outline in the 3D view, #4fb3d9/#e35d5b on the map.
Mates and the dead: a mate or a dead body that carries a side stays blue or grey.
Elsewhere:sides.test.ts covers the colour picker, plus small additions to presence.test.ts, body.test.ts and boundary.test.ts. val's real-snapshot test from #41 still passes.
Decisions
No fixed colour per side name: colours go by first sighting, not by the side's name. Two players may see the same side in different colours. Naming fixed colours by side would collide too often with three sides and six colours.
Health bar and chevron unchanged: the enemy's health-bar amber and the chevron stay the same for every side, because they mean "enemy", not "which enemy".
Not done
Nothing in val sends side, so the preview can't show the new colours. In the preview, just check that it looks unchanged: start a round, and teammates should be blue and enemies red, in both the 3D view and the map.
The record of side colours is never cleared within a page. It only grows with the number of different sides seen.
I booted the app and confirmed / loads and the client bundle includes the new module. I haven't played it in a browser.
Bodies in a snapshot can now carry an optional
side. When they do, each non-mate side gets its own colour on the 3D view, the map and the last-seen outlines. A body withoutsidedraws exactly as before, so val, which doesn't send it, looks the same.bun testpasses (323 tests). I checked that the new tests fail when the code is broken: with side colouring removed, three tests fail; with today's enemy red changed, two fail; withsidedropped from last-seen marks, one fails.What a game must send for 3+ sides: on every body in
snap.players, addside: string, meaning any stable name for the body's side (a team id; in a free-for-all, the player's own id). Keep sendingmate: booleanas today, true when the body is on the viewer's side. Mates keep the mate blue, the viewer keeps white, the dead keep grey and enemies keep the chevron, whatever theirside.What changed
static/engine/sides.js: a fixed palette of six colours, none of them blue, grey or white. Each side gets the next colour the first time it is seen and keeps it for as long as the page is open, so the same side has the same colour every frame. The first side seen gets today's enemy red. A seventh side goes back to the first colour.scene.jsandtopdown.js: enemy colours now come from that palette. The 3D view and the map share one record of which side has which colour, so they agree.presence.js: last-seen marks rememberside, so their outlines match the body.src/engine/body.ts:sideis optional in the contract. If it is sent, it must be a string.Tests
scene.test.tsand a newtopdown.test.tsdraw three enemy sides and get three different colours. The next frame, with the bodies listed in reverse order, gives the same colours.side: the same two files pin today's exact colours:#3f9fd6/#d8483fand the mark outline in the 3D view,#4fb3d9/#e35d5bon the map.sidestays blue or grey.sides.test.tscovers the colour picker, plus small additions topresence.test.ts,body.test.tsandboundary.test.ts. val's real-snapshot test from #41 still passes.Decisions
Not done
side, so the preview can't show the new colours. In the preview, just check that it looks unchanged: start a round, and teammates should be blue and enemies red, in both the 3D view and the map./loads and the client bundle includes the new module. I haven't played it in a browser.🤖 Generated with Claude Code
Closes #42