Three Playlists and a UUID
Team gametypes, the soundtrack streamed out of a PK3 with menu/game/endgame playlists, freefly spectator, and a player profile with a UUID v4.
Soundtrack, Finally Described
JSON playlists with name, loop, shuffle and tracks. Three ship:
menu looping
game shuffled
endgame loopingStreamed from washoi_soundtrack.pk3 via PK3Loader.getFileAsURL() Blob URLs, switching on audio unlock, JoinAccept, MatchPhase.PostGame and disconnect, with fadingOutMusic tracking and a loadingRequestId concurrency lock.
Documented in docs/research/MUSIC_SYSTEM.md.
Team Gametypes
GametypeController supports TeamDeathmatch and Duel against Deathmatch. MatchState tracks team scores with assignTeamBalance; Duel enforces 1v1 and sends the excess to spectator. The headless CLI parses --map and --gametype "to circumvent NPM parameter stripping" — a workaround that describes npm more accurately than npm would.
Freefly Spectator
WASD and mouse, Shift for a 3x boost, active on connect before you have joined. Quake-style vertical flight — Space up, C or Ctrl down.
The Profile
PlayerProfile.ts with a UUID v4, keybindings and preferences — sensitivity, FOV, crosshair, UI scale. Stored under shag_player_profile in localStorage, auto-migrating shag_keybindings. Names capped at 32 characters via a name command. BotNames.ts supplies 40 themed names with getNextBotName() de-duplicating.
The Fix Worth Reading
Slide state (camera tilt, speed decay) was being killed at every server
reconciliation (~60Hz), preventing camera animation from ever completingMIN_WALK_NORMAL went 0.75 → 0.7, because cos(45°) ≈ 0.707 > 0.7. Someone worked out what the constant meant and corrected it.
Known Issues: none stated.