1. Scope and source of truth
This document describes the Godot 4 client as it exists in this repository. It is based on the current GDScript, scenes, project settings, resources, Colyseus integration, and map compiler. It does not describe the missing backend except where the client establishes a concrete contract with it.
The documentation uses the following status terms:
- Implemented: there is an active, end-to-end code path in the current client. This is a source-level assessment; the game was not executed as part of this documentation audit.
- Partial: code exists, but it is disabled by default, lacks a consumer or UX, has an explicit TODO, or does not complete the full behavior suggested by its name.
- Not implemented: no functioning client code exists. A visible button, signal, placeholder scene, or README roadmap entry is not treated as an implementation.
Related documents:
- CLIENT_CODE_REFERENCE.md — file-by-file API and scene reference.
- CLIENT_GAMEPLAY.md — gameplay, protocol, movement, synchronization, UI, animation, and audio.
- CLIENT_DEVELOPMENT.md — setup, extension recipes, debugging, testing, map workflow, and export notes.
2. Runtime profile
The application is a 2D Godot client named
Chickens Must Die.
project.godot declares Godot feature version
4.7 with the Compatibility renderer. The logical
viewport is 1600 x 1200, canvas items are stretched
with expand aspect behavior, and texture filtering
defaults to nearest-neighbor.
The configured main scene is:
res://core/screens/menu_screen/main_menu_screen.tscn
The client depends on two enabled editor plugins:
-
Colyseus SDK for Godot — native GDExtension used
for room transport, state callbacks, and reconnection.
addons/colyseus/version.jsonreports0.17.11;plugin.cfgreports plugin version0.17.0. - Damped Oscillator 1.0 — provides spring-like property animation for UI buttons, the menu logo, and the global swipe impact.
The repository includes Colyseus binaries for Windows, Linux, macOS arm64, iOS arm64, Android, and Web. Presence of a binary does not mean the project has an export preset or a tested release path for that platform. Only Web and Windows Desktop presets are configured.
3. Architectural style
The client combines four patterns:
- Autoload services own process-wide configuration, networking, logging, scene transitions, settings, global UI, and audio.
- Scene composition assembles screens and gameplay entities from small Godot scenes.
- Component-based actors keep movement input, movement simulation, interpolation, reconciliation, animation, and camera behavior separate from player identity and mass.
- Server-authoritative replication treats Colyseus room state as the authoritative source for player and seed existence and positions.
At a high level:
project.godot
-> autoload services and GlobalUi
-> MainMenuScreen
-> JoinScreen
-> NetworkManager.join_or_create("my_room")
-> joined_room signal
-> Game scene
-> World/MapLoader
-> PlayerManager
-> SeedManager
-> ChatController + ChatPanel
The backend is not included. The client cannot enter the gameplay scene through its normal flow until a compatible room join succeeds.
4. Project structure
| Path | Responsibility |
|---|---|
actors/ |
Player scenes, player behavior components, and the replicated seed entity. |
core/globals/ |
Autoload services and global configuration. |
core/screens/ |
Main menu, join screen, and optional splash/intro screen. |
game/ |
Gameplay composition, replicated entity managers, and chat bridge. |
ui/ |
Global UI, settings, chat presentation, buttons, cursor, and parallax effect. |
world/ |
Runtime world scene, map loader, source Tiled JSON, compiled client JSON, and TypeScript compiler. |
addons/colyseus/ |
Vendored Colyseus GDExtension and platform binaries. |
addons/DampedOscillator/ |
Vendored UI animation plugin and its demo. |
assets/ |
Fonts, sprites, UI textures, cursor graphics, music, and sound effects. |
docs/ |
Technical and product documentation. |
There are 37 application GDScript files and 20 non-addon
.tscn scenes, excluding temporary
.tmp scene files.
5. Autoload services
Autoloads are declared in project.godot in the
following order.
| Autoload | Type | Responsibility | Important state |
|---|---|---|---|
Config |
Script | Build environment, client version, grid size, movement mode, player speed, log endpoint. |
CLIENT_ENV, MOVEMENT_TYPE,
PLAYER_BASE_SPEED.
|
NetConfig |
Script | Environment-dependent Colyseus URL and synchronization tuning. | Debug filters, interpolation speeds, send interval, reconciliation settings. |
SceneManager |
Script | Scene path registry and scene changes; returns to menu when a session ends. | is_transitioning. |
NetworkManager |
Script | Owns the Colyseus client/room, connection state machine, room lifecycle, outgoing messages, and incoming message routing. |
client, room,
callbacks, connection_state.
|
GameLogger |
Script | Structured in-memory/development logging and rate-limited HTTP reporting for critical events. |
history, report queue, debug log throttles.
|
GlobalEffects |
Script | Runtime-created fade and swipe overlays. | Active tweens and swipe offsets. |
SettingsManager |
Script | Loads, applies, and saves three audio volume values. |
master_volume, music_volume,
sfx_volume.
|
GlobalUi |
Scene | Always-present canvas layer with settings button, mute button, settings menu, and custom mouse cursor. | UI node state. |
UiAudioManager |
Scene |
Plays the shared UI click sound on the SFX bus.
|
One AudioStreamPlayer. |
MusicManager |
Scene | Two-player music crossfade service. | Current track and active player. |
DampedOscillator |
Plugin script | Animates arbitrary properties with damped spring motion. | Plugin-managed animation instances. |
Dependency direction
Most scene scripts may call autoloads. Autoloads avoid direct references to gameplay scenes, with two deliberate exceptions:
-
SceneManagerknows scene paths and listens toNetworkManager.game_session_ended. -
GlobalUicontains reusable UI scenes that callNetworkManagerandSettingsManager.
NetworkManager does not reach into the current scene.
It emits signals, and screen/game controllers decide how to react.
This keeps room lifecycle separate from scene composition.
6. Scene architecture
Main menu
main_menu_screen.tscn is the startup scene. It contains
a darkened parallax background, OPTIONS and EXIT buttons, a
clickable logo, START, inactive LEADERBOARD and CREDITS buttons, a
version label, and a local SettingsMenu instance.
MainMenuScreen._ready() starts the only registered
music track (menu) and displays
Config.VERSION. START changes directly to the join
scene. Clicking the logo loads the splash scene; the splash is
therefore optional and is not an automatic boot scene.
Join screen
join_screen.tscn contains:
- a four-skin
CharacterPreview, - previous/next buttons,
- a nickname
LineEdit, - join status text,
- join and back buttons,
- another parallax background.
The screen validates only that the trimmed nickname is non-empty. It
disables editing while connecting and delegates the actual join to
NetworkManager. joined_room loads the
gameplay scene; connection_error restores the form.
Gameplay scene
game/game.tscn is intentionally small:
Game (game.gd)
|- World (world.tscn)
| `- Map (map_loader.gd)
|- PlayerManager (player_manager.gd)
|- SeedManager (seed_manager.gd)
`- Chat (chat_panel.tscn + chat_controller.gd)
Game initializes the PlayerManager with
the room callback adapter and local session ID. It listens to full
room state changes and applies the players and
seeds collections. A deferred first application handles
state that may have arrived before the scene finished loading.
Player inheritance and composition
base_player.tscn provides a
CharacterBody2D, animated sprite, nickname label,
animation controller, and circle collider.
BasePlayer
|- AnimatedSprite2D
|- PlayerName
|- AnimationController
`- CollisionShape2D
The local and remote player scenes inherit it:
LocalPlayer adds RemotePlayer adds
|- MovementInput `- PositionInterpolationController
|- MovementController
|- ReconciliationController
|- NetworkInputSender
|- PositionInterpolationController
|- Camera2D + CameraController
`- EatSound
BasePlayer owns replicated identity, skin, position
initialization, mass-driven scale/collision, and the
mass_changed signal. Subclasses implement
_apply_server_position():
-
RemotePlayeralways updates an interpolation target. -
LocalPlayerupdates either an interpolation target or a reconciliation target, depending onNetConfig.RECONCILIATION_ENABLED.
7. Application lifecycle
7.1 Startup
- Godot creates the autoloads.
-
NetworkManagercreates aColyseus.ClientforNetConfig.COLYSEUS_URL. -
SettingsManagerloadsuser://settings.cfgif it exists and applies Master, Music, and SFX values. -
GlobalEffectscreates its overlay canvas at runtime. -
GlobalUiinitializes the global settings/mute/cursor controls. -
The main menu scene starts the menu music and displays version
1.0.0.
The current configured environment is DEVELOPMENT, so
the endpoint is currently http://172.22.111.106:8080.
The production branch in NetConfig.gd uses
https://chickensmustdie.com.
7.2 Join lifecycle
JoinScreen.join()
-> validate nickname and DISCONNECTED state
-> NetworkManager.join_game(nickname, character_key)
-> state = CONNECTING
-> client.join_or_create("my_room", options)
-> configure reconnection and room signals
-> room.joined
state = CONNECTED
callbacks = Colyseus.Callbacks.of(room)
emit joined_room
-> JoinScreen loads game.tscn
If join_or_create() returns null, or the
room emits error/left while connecting,
the current code clears the room and returns to
DISCONNECTED before emitting
connection_error. A new join attempt is therefore
allowed.
7.3 Gameplay state lifecycle
The gameplay scene consumes both collection callbacks and complete state snapshots:
Colyseus room state
|- callbacks.on_add("players") ------> PlayerManager creates local/remote scene
|- callbacks.on_remove("players") ---> PlayerManager frees scene
`- room.state_changed ---------------> Game gets full state
|- PlayerManager.apply_server_state()
`- SeedManager.reconcile()
The full snapshot pass is also a safety net: it creates missing players and removes stale ones even if collection callbacks did not produce the expected local dictionary state.
7.4 Leave and disconnect lifecycle
The settings menu calls
NetworkManager.leave_game() while connected or
reconnecting. The manager changes to LEAVING, disables
reconnect, invokes room.leave(), and waits for
left. A 1.5 second verification timer handles missing
completion:
- if the room is no longer connected, it completes local cleanup;
-
if the room still reports connected, it sends a critical log
report, retains ownership, restores
CONNECTEDand reconnection options, and emitsconnection_error. The user can retry LEAVE; the client does not claim the native transport closed.
Completion disconnects the old room's manager signals, clears
callbacks and room, changes to
DISCONNECTED, emits game_session_ended,
and causes SceneManager to load the main menu.
Scene-owned callback handles and state subscriptions are removed on
tree exit.
An unexpected transport drop changes the state to
RECONNECTING; an SDK reconnection changes it back to
CONNECTED. The current gameplay scene remains loaded.
No reconnect overlay, input freeze, countdown, or terminal failure
screen is implemented.
8. State ownership
State is split by lifetime and authority:
| State | Owner | Authority/lifetime |
|---|---|---|
| Connection state and room handle | NetworkManager |
Process lifetime; driven by Colyseus lifecycle. |
| Players and seeds | Backend room state, mirrored by managers | Server-authoritative per room session. |
| Local input direction and input sequence | Local player components | Frame/component lifetime; sequence is sent but not acknowledged by the client. |
| Interpolation/reconciliation targets | Player network components | Per player instance. |
| Nickname, skin, mass | BasePlayer mirror of room state |
Server state after join. |
| Current scene | Godot scene tree via SceneManager |
Process lifetime. |
| Audio volumes |
SettingsManager and AudioServer
|
Persisted in user://settings.cfg when the
settings menu closes.
|
| Mute toggle | MuteButton/AudioServer |
Runtime only; not persisted by SettingsManager.
|
| Music track | MusicManager |
Process lifetime across scene changes. |
| Log history | GameLogger |
Development-mode process memory, capped at 100 entries. |
There is no central Redux-style game state. The room state is read at the gameplay boundary and distributed to specialized nodes.
9. Networking boundary
NetworkManager is the only class that owns the Colyseus
Client and Room. Other classes use its
public signals and send_message() method. The exception
is Game, which reads
NetworkManager.room and its callback object after a
successful join.
Outgoing application messages currently used:
movefromNetworkInputSender;chat_sendfromChatController.
Incoming application messages routed to signals:
game_config— routed, no consumer;tick_sync— routed, no consumer;chat_message— displayed by chat;chat_error— displayed by chat;-
player_eaten— may play the local predator's eating sound; __playground_message_types— debug log only.
Unknown message types produce a warning.
10. Map architecture
The checked-in world uses a compile-then-load pipeline:
Tiled JSON (map.json)
-> compile-map-client.ts
-> compact client schema (map.client.json)
-> MapLoader at game-scene startup
-> runtime TileSet + TileMapLayer nodes + StaticBody2D collisions
The current map is finite and orthogonal: 50 x 38 tiles
at 16 x 16 pixels, producing an
800 x 608 world. It contains 20 atlas tilesets, three
rendered layers (Ground, Objects,
Buildings), 2,112 non-empty cells, and nine collision
rectangles. The loader also creates four 64-pixel-thick boundary
walls outside the map.
The map is built every time world.tscn enters the tree.
There is no runtime map selection, cached generated Godot scene, or
server-provided map identifier.
11. Implementation status
Implemented and active
- Main menu, optional splash sequence, join screen, and direct scene transitions.
- Four selectable chicken skins with walk, stand, and idle animations.
- A single Colyseus room type named
my_room. - Join error cleanup, normal leave, SDK reconnection configuration, and lifecycle signals.
- Server-driven player/seed creation, update, and removal.
- Input messages at change time plus a 20 Hz heartbeat.
- Default local and remote position interpolation.
- Free eight-direction input with diagonal normalization in the optional local simulation path.
- Mass-based sprite/collider sizing, nickname display, camera smoothing, chat, settings, music, UI sound, cursor, and parallax.
- Runtime construction of the one checked-in map.
- Structured logging and critical HTTP reports.
Partial, disabled, or unused
- Client prediction/reconciliation exists but is disabled by default. It corrects only while idle and does not replay unacknowledged inputs.
- Grid movement is implemented behind a config enum, disabled by default, and marked with an explicit TODO to verify it.
- Reconnect UX is absent even though SDK reconnect is configured and signals are emitted.
- Leave timeout recovery permits another attempt when still connected; the wrapper exposes no force-close API.
-
game_configandtick_syncare routed but have no consumers. -
Global swipe transitions are implemented but no
current screen uses
load_scene_with_swipe(). - Mute persistence is separate from stored Master volume and lasts only for the process.
- SFX routing is incomplete: the UI click uses the SFX bus, while the eating sound and splash audio use the default Master bus.
- Matchmaking cancellation is not exposed by the SDK wrapper; BACK is disabled until the join request resolves.
-
game/managers/seed_manager.tscnis an empty, unused placeholder;game.tscnattachesseed_manager.gddirectly to a node.
Not implemented in the current client
- Leaderboard and credits behavior, despite visible main-menu buttons.
- Matchmaking, room selection, authentication, or session restoration after application restart.
- A reconnect/failure screen or defeat screen.
- Automated tests or CI configuration.
- Multiple runtime-selectable maps.
- Mobile controls; the input map contains keyboard controls only.
Explicit source TODOs identify server-provided camera/gameplay configuration and verification of grid movement as future work. They must not be treated as current functionality.