1. Reading this reference
This is a file-by-file reference for the application-owned GDScript and TypeScript code. Vendored addon internals are intentionally summarized only where the application calls them. Paths are relative to the repository root.
Status labels have the same meaning as in CLIENT_ARCHITECTURE.md: Implemented, Partial, and Not implemented describe the current source, not a runtime test result.
2. Global configuration and services
core/globals/Config.gd
Process-wide constants:
| Symbol | Current value | Use |
|---|---|---|
VERSION |
"1.0.0" |
Main-menu version label and log reports. |
CLIENT_ENV |
DEVELOPMENT |
Selects endpoint, log behavior, and environment label. |
GRID_SIZE |
16 |
One grid step in the optional grid movement mode. |
PLAYER_BASE_SPEED |
100 |
Pixels per second for client-side simulation. |
MOVEMENT_TYPE |
FREE |
Chooses free or grid local simulation. |
LOG_API_URL |
https://chickensmustdie.com/api/client-logs
|
Destination for critical reports. |
ClientEnvEnum contains PRODUCTION and
DEVELOPMENT. MovementType contains
GRID and FREE.
core/globals/NetConfig.gd
Network and smoothing configuration:
| Symbol | Current value |
|---|---|
| Development endpoint | http://172.22.111.106:8080 |
| Production endpoint | https://chickensmustdie.com |
LOCAL_INTERPOLATION_SPEED |
18.0 |
REMOTE_INTERPOLATION_SPEED |
12.0 |
INPUT_SEND_INTERVAL |
0.05 seconds |
RECONCILIATION_ENABLED |
false |
RECONCILIATION_INTERVAL |
3.0 seconds |
RECONCILIATION_DURATION |
0.3 seconds |
RECONCILIATION_IDLE_DELAY |
0.15 seconds |
RECONCILIATION_MIN_DISTANCE |
0.5 pixels |
RECONCILIATION_HARD_SNAP_DISTANCE |
32.0 pixels |
Debug state/message logging is disabled by default and additionally
guarded by OS.is_debug_build(). State logging extracts
the players key through
should_log_state(); message logging uses
should_log_message().
core/globals/NetworkManager.gd
Owns the Colyseus connection.
Connection state
enum ConnectionState {
DISCONNECTED,
CONNECTING,
CONNECTED,
RECONNECTING,
LEAVING,
}
Read-only computed properties:
-
is_in_roomis true only inCONNECTED. -
is_reconnectingis true only inRECONNECTING.
Public signals
| Signal | Emitted when |
|---|---|
joined_room |
room.joined completes and callback adapter is
created.
|
reconnecting(code, reason) |
The room emits dropped, unless an intentional
leave is active.
|
reconnected |
The room emits reconnected. |
game_session_ended |
Room state is cleaned up after a completed/locally detected leave. |
connection_error(code, message) |
Join creation fails or the room reports a connection error/close during join. |
server_config_message_received(payload) |
game_config message arrives. No current
consumer.
|
server_tick_sync_message_received(payload)
|
tick_sync message arrives. No current consumer.
|
server_chat_message_received(payload) |
chat_message arrives. |
server_chat_error_received(payload) |
chat_error arrives. |
server_player_eaten_message_received(payload)
|
player_eaten arrives. |
Public methods
-
join_game(nickname, color)guards forDISCONNECTED, callsjoin_or_create("my_room", options), configures reconnection, and connects room signals. -
leave_game()acceptsCONNECTEDorRECONNECTING, disables SDK reconnection, callsroom.leave(), and starts a 1.5-second verification. If disconnected, timeout completes local cleanup. If still connected, it retains the room, restoresCONNECTEDand reconnection options, logs a critical error and permits another leave attempt. -
send_message(message_type, payload)sends only whileis_in_room. -
send_chat_message(message)wrapssend_message("chat_send", message)and is used by the chat controller.
Join options are exactly:
{
"nickname": nickname,
"playerColor": color,
}
Reconnection is configured for eight retries, 250 ms initial/minimum
delay, 3,000 ms maximum delay, and a ten-message SDK queue. The
application-level send guard does not submit messages while
RECONNECTING, so the SDK queue is not used by current
gameplay sends during that state.
On join-time room.error, the code invokes
_cleanup_room() before emitting
connection_error; retry is therefore possible. Cleanup
disconnects the manager's old room signals. Errors outside
CONNECTING are reported without changing the state.
Missing GDExtension or callback adapter produces an error instead of
entering gameplay with an unusable client.
core/globals/GameLogger.gd
Provides debug, info,
success, warn, error, and
critical methods. Every entry includes:
timestamp, level, message, version, environment, source, context
In development, entries are printed, emitted through
log_added, and retained in a maximum 100-entry history.
get_history() returns a deep duplicate;
clear_history() empties it.
Only critical() calls _enqueue_report().
Critical reports are POSTed as JSON through a runtime-created
HTTPRequest with a six-second timeout. The reporter
limits itself to five reports per 60 seconds, holds at most 20
queued entries, and replaces context when the serialized body
exceeds 8,192 characters. A failed report is logged in development
and discarded; there is no retry or disk spool.
network_state(callable) and
network_message(type, payload) implement interval/type
filtering from NetConfig.
core/globals/SceneManager.gd
Defines paths for the game, main menu, join, splash, local player, and remote player scenes.
-
load_scene(path)performs an immediatechange_scene_to_file, reports errors withpush_error, and returns theErrorcode. -
load_game()requires a room and callback adapter, loadsgame.tscn, and leaves the session if loading fails. The join screen schedules this method withcall_deferred(). -
load_scene_with_swipe(path, direction)guards re-entry withis_transitioning, animates the global swipe overlay, changes scene, waits one process frame, and removes the overlay. This method is implemented but unused. -
_on_game_sessions_ended()returns to the main menu.
core/globals/GlobalEffects.gd
Creates a CanvasLayer at layer 100 and two runtime
ColorRect overlays.
-
fade_out(duration)fades black to alpha 1 and blocks mouse input. -
fade_in(duration)fades to alpha 0, hides the overlay, and restores ignored mouse input. -
swipe_in(direction, duration)brings a dark panel from left or right and triggers a damped impact. -
swipe_out(direction, duration)sends it offscreen and resets offsets.
Fade is used by the splash-to-menu transition. Swipe is available
through SceneManager but currently unused. Effect waits
also finish when a tween is killed; an interrupted exit does not
hide a newer overlay. A newer direct scene request supersedes a
pending swipe scene change.
core/globals/SettingsManager.gd
Owns normalized master_volume,
music_volume, and sfx_volume, each
defaulting to 1.0.
At startup it reads user://settings.cfg, then applies
values to the Master, Music, and
SFX buses. Setters clamp to [0, 1]; values
at or below 0.001 mute the bus, while positive values
unmute it and apply linear_to_db(value).
save_settings() writes only the three volume values.
Mute remains runtime-only; set_master_muted(),
is_master_muted() and
master_mute_changed keep the button synchronized with
Master slider changes. Invalid/non-finite stored values fall back to
full volume.
core/globals/MusicManager.gd and .tscn
The track dictionary currently contains only:
&"menu": preload("res://assets/music/time_for_adventure.mp3")
Two AudioStreamPlayer nodes on the
Music bus enable crossfading.
play_track() prevents restarting the current playing
track, alternates players, starts the new track at
-40 dB, and fades both in parallel.
stop_music() fades and stops both players, including an
interrupted crossfade. A non-positive stop duration stops both
immediately.
No scene stops menu music when leaving the menu, so it continues through join and gameplay unless another caller changes it.
core/globals/UIAudioManager.gd and .tscn
Contains one AudioStreamPlayer with
click1.wav, -15 dB volume, and the
SFX bus. play_click(start_from) is used by
menu, join, settings, and character-selection buttons.
3. Screen controllers
core/screens/menu_screen/main_menu_screen.gd
On ready:
- starts the
menutrack; - centers pivots for the OPTIONS button and logo;
- displays
Version 1.0.0.
Handlers:
- START loads the join scene;
- OPTIONS plays a click, springs the button scale, and opens the menu-local settings panel;
- EXIT calls
get_tree().quit(); - logo hover springs its scale;
- left-clicking the logo loads the splash scene.
The LEADERBOARD and CREDITS buttons have no scene connections and no script handlers.
core/screens/join_screen/join_screen.gd
Coordinates nickname entry, selected skin, and network lifecycle.
join() trims the nickname, rejects empty input and
non-DISCONNECTED state, then calls
NetworkManager.join_game(). Nickname, selection, JOIN
and BACK are disabled during the request because the SDK wrapper
exposes no matchmaking cancellation API.
joined_room schedules gameplay loading.
connection_error restores the form only after the
manager returns to DISCONNECTED. BACK returns to the
menu when disconnected.
The nickname control has no client-side max_length in
its scene. Character, length, uniqueness, and moderation validation
are backend responsibilities.
core/screens/join_screen/character_preview.gd
(CharacterPreview)
Defines four selectable keys and display names:
| Key | Display name |
|---|---|
chicken_1 |
White Chicken |
chicken_2 |
Black Chicken |
chicken_3 |
Dark Brown Chicken |
chicken_4 |
Light Brown Chicken |
The preview starts at index 0 and cycles
STAND -> IDLE -> WALK -> STAND with default
durations of one, three, and three seconds respectively.
Previous/next selection wraps around. Animation names are assembled
as <key>_<walk|stand|idle> and checked
before playback.
The serialized scene initially contains a different animation/label,
but _ready() calls
show_current_character(), making White Chicken and
chicken_1_stand the effective initial state.
core/screens/splash_screen/splash_screen.gd
Plays the chickens-text
AnimationPlayer sequence. When it finishes, the
controller fades to black, loads the main menu, then fades in. The
explosion_sprite field is declared but not referenced
by the script; the scene animation itself triggers the explosion and
fireworks.
The animation lasts about 2.03 seconds and sequences four splash sounds plus three logo words, an explosion, and fireworks.
4. Gameplay composition and replicated entity managers
game/game.gd
Requires a room and callback adapter; otherwise it schedules a return to the menu. On ready it:
-
initializes
PlayerManagerwithNetworkManager.callbacksandroom.get_session_id(); - connects to
room.state_changed; - defers one initial
_on_state_changed()call.
Each state application reads a dictionary and dispatches collections with safe empty defaults:
player_manager.apply_server_state(state.get("players", {}))
seed_manager.reconcile(state.get("seeds", {}))
The scene holds its own room reference, ignores stale/disconnected state and non-dictionary collections, reapplies the snapshot on reconnect, and disconnects its subscriptions on exit.
game/managers/player_manager.gd
(PlayerManager)
Maintains players: Dictionary, keyed by session ID.
initialize() registers Colyseus on_add and
on_remove callbacks for players, retaining
their handles for removal on reinitialization or tree exit.
_on_player_add() instantiates the local scene when the
ID equals the room session ID, otherwise the remote scene, adds it
to the tree, stores it, and calls setup().
_on_player_remove() queues the node for deletion and
erases its dictionary entry.
apply_server_state() updates existing nodes, creates
any missing node, and removes local entries absent from the server
snapshot. This makes full state changes authoritative even if a
collection callback is missed or arrives in a different order.
game/managers/seed_manager.gd
(SeedManager)
Maintains seeds: Dictionary, keyed by seed ID.
reconcile() performs a complete diff:
- instantiate
actors/seed/seed.tscnfor new IDs; - call
apply_server_state()for existing IDs; - queue and erase IDs no longer present.
game/managers/seed_manager.tscn is an empty node
without the script and is not referenced. The active gameplay scene
attaches seed_manager.gd directly to its own
SeedManager node.
game/chat/chat_controller.gd
Bridges network signals and ChatPanel:
-
chat_message->display_message(payload); -
chat_error->display_error(payload); -
message_send_requested(text)->send_chat_message({"text": text}).
Reconnect signals control the panel's submission flag. Text entered while reconnecting is retained instead of being cleared without a send.
5. Player classes
actors/player/base_player.gd (BasePlayer)
Replicated fields:
nickname;session_id;player_color;current_mass.
setup(player_state, player_session_id) copies
nickname, playerColor, x, and
y, then applies skin, label, and mass once the node is
ready. Because PlayerManager calls
add_child() before setup(), the node is
ready in the normal path.
apply_server_state() applies mass then delegates
position handling to _apply_server_position(), which is
a no-op hook in the base class.
Mass changes use these exact formulas:
var radius := sqrt(mass) * 2.3
var scale_factor := sqrt(mass / 5.0)
player_sprite.scale = Vector2.ONE * (0.5 * scale_factor)
player_name.position.y = 7.5 * scale_factor - 4.1
The collision shape is a per-scene CircleShape2D, so
changing one player does not mutate all players.
Non-positive/non-finite mass is ignored before sqrt().
actors/player/local_player.gd
(LocalPlayer)
Owns input, optional local movement, input transmission, one of two server-position handling modes, the camera, and eating audio.
On every physics frame:
- read input unless text editing has focus;
- if reconciliation is enabled, simulate locally; otherwise interpolate toward the latest server target;
- update animation from the input direction;
- send changed input or heartbeat;
- if enabled, run reconciliation.
When player_eaten arrives, it reads
predatorSessionId; only the matching local predator
plays crunch.wav, with random pitch in
[0.8, 1.2].
mass_changed is connected to
CameraController.set_mass before
super.setup() applies the initial mass. Initial and
later mass changes use the same zoom calculation.
actors/player/remote_player.gd
(RemotePlayer)
Always uses PositionInterpolationController at
REMOTE_INTERPOLATION_SPEED. Each physics frame returns
the normalized visual movement direction and feeds it to the shared
animation controller.
actors/seed/seed.gd (Seed)
Sets absolute z-index 100 and applies x/y
from a dictionary, defaulting absent coordinates to zero. It has no
collision, pickup, animation, or local game logic.
6. Player components
actors/components/movement/movement_input.gd
(MovementInput)
Returns zero while a LineEdit or
TextEdit owns GUI focus. Otherwise it calls
Input.get_vector() for
move_left/right/up/down, then reduces each component to
its sign. Keyboard input supports WASD and arrow keys. Analog
magnitude is intentionally discarded if another input device is
later mapped.
actors/components/movement/movement_controller.gd
(MovementController)
Clamps direction components to -1, 0, or
1 and selects movement mode from Config.
Free movement normalizes diagonals, multiplies by 100 px/s and
non-negative delta, then calls move_and_collide on X
followed by Y. Axis separation provides sliding against rectangular
obstacles.
Grid movement advances toward a persistent target one 16-pixel step
at a time. It uses test_move() before beginning a step
and directly updates global_position while advancing.
Diagonal starts additionally require both horizontal and vertical
cardinal traversals to be clear. This path is disabled and
explicitly marked for verification.
actors/components/network/network_input_sender.gd
(NetworkInputSender)
Tracks a monotonically increasing per-instance
input_seq. It sends immediately when direction changes
or when the 0.05-second heartbeat expires.
Current payload:
{
"seq": input_seq,
"clientTime": Time.get_ticks_msec(),
"input": {
"left": direction.x < 0,
"right": direction.x > 0,
"up": direction.y < 0,
"down": direction.y > 0,
}
}
clientTime is monotonic process time in milliseconds,
not Unix time. The client never receives or processes an
acknowledged sequence number.
actors/components/network/position_interpolation_controller.gd
(PositionInterpolationController)
Stores a target, interpolation speed, and snap distance (default 100
px). update():
- snaps at or beyond the threshold;
-
otherwise uses frame-rate-independent exponential smoothing:
1 - exp(-speed * delta); -
snaps the final tiny residual when movement squared is at most
0.000001; - returns a normalized movement direction for animation.
It assigns global_position and does not perform
collision checks.
actors/components/network/reconciliation_controller.gd
(ReconciliationController)
Stores the most recent server position. When enabled, it:
- cancels correction whenever input is non-zero;
- waits for the three-second reconciliation interval and 0.15 seconds of idle time;
- ignores error up to 0.5 px;
- hard-snaps at or beyond 32 px;
-
otherwise distributes correction over 0.3 seconds using
axis-separated
move_and_collide().
This is a simple idle correction, not input-history reconciliation. It has no server tick mapping, sequence acknowledgement, rewind, or replay.
actors/components/animation/animation_controller.gd
(PlayerAnimationController)
Builds animation names from skin_key plus
walk, stand, or idle.
Horizontal direction flips the sprite: right sets
flip_h = true, left sets it false. Zero direction shows
stand for three seconds, then idle. Missing animations generate a
warning without changing to a fallback.
actors/components/camera/camera_controller.gd
(CameraController)
Attached directly to the local Camera2D.
set_mass() maps mass 5 -> 200 to zoom
3 -> 2, clamped at both ends.
_process() exponentially smooths to the target with
speed 2.
The camera scene also has bounds 0,0 to
800,608, position smoothing enabled at speed 3, and an
initial position of (-3, 0). Camera mass constants are
local exports and marked in source to come from the server in the
future.
7. UI scripts
ui/chat/chat_panel.gd (ChatPanel)
Emits message_send_requested(message) after trimming
and rejecting empty input. The scene limits the
LineEdit to 200 characters. Successful local submission
clears and unfocuses the input; it does not optimistically add a
message.
Incoming dictionary messages instantiate
chat_message.tscn, use defaults for absent fields, and
coalesce scrolling into one request per frame. Errors display
payload.code for three seconds using a restarted child
timer, so an earlier error cannot hide a newer one. Non-dictionary
payloads are ignored.
The panel starts at alpha 0.3, becomes fully opaque on focus/send/message/error, waits eight seconds, then fades back over 0.4 seconds. Escape releases chat focus. A left click outside a focused message input also releases it.
ui/chat/chat_message.gd (ChatMessage)
Displays [HH:MM], nickname, and message.
sentAt is interpreted as Unix milliseconds, divided by
1,000, offset by the current system time-zone bias, and formatted
with Godot's Unix-time converter.
ui/settings/settings_menu.gd
(SettingsMenu)
Synchronizes three 0–100 sliders with
SettingsManager on ready and every open().
Slider changes apply audio immediately. close() saves
the three values and hides the overlay. BACK plays a click then
closes.
LEAVE accepts connected or reconnecting sessions; it clicks,
saves/closes, and calls NetworkManager.leave_game().
Session end also closes an open settings overlay.
ui/buttons/leave_button/leave_button.gd
Shows the button only while the client is connected. It reacts to
joined_room and game_session_ended. Click
behavior is owned by the parent SettingsMenu, which
connects the button's pressed signal in code.
ui/buttons/mute_button/mute_button.gd
Reads Master mute through SettingsManager, mirrors it
into a toggle button, and swaps icon/tooltip. Changes from the
slider or toggle are synchronized through
master_mute_changed. Toggling does not update or save
master_volume.
ui/buttons/settings_button/settings_button.gd
Fetches the settings panel specifically from the
GlobalUi autoload and opens it on the scene-connected
pressed signal.
ui/cursor/mouse_cursor.gd
Installs the normal custom cursor at startup and swaps to a pressed
texture while the left mouse button is down. The configured hotspot
is (0, 0).
ui/effects/parallax_background.gd
(Parallax)
Expands a TextureRect by 30 pixels on all sides, waits
one layout frame, then moves it opposite to normalized mouse
position. Default maximum movement is (16, 10) px and
exponential follow speed is 4.
8. Map code
world/map/map_loader.gd
Loads res://world/map/map.client.json synchronously in
_ready().
The loader:
- checks file existence, readability, non-empty text, valid JSON, and dictionary root;
- validates top-level tile dimensions and tileset presence;
-
creates a runtime
TileSetand oneTileSetAtlasSourceper compiled tileset; -
creates every atlas tile from
0totileCount - 1; -
creates one
TileMapLayerper compiled layer with visibility, opacity, and order/z-index; -
inserts cells and translates
flipH,flipV, andtransposeflags to Godot alternatives; -
creates a
StaticBody2Dcontaining compiled rectangular collisions; -
creates four boundary walls from
worldWidthandworldHeight.
Critical early-stage failures stop _ready() before
dependent stages. Missing layer/collision/boundary fields report
errors inside their stage but do not roll back nodes created by
previous stages. The loader does not validate the compiled schema's
version field.
world/map/compile-map-client.ts
Standalone TypeScript compiler for Tiled JSON. It exports
compileClientMap(map) and runs CLI
main() only when invoked directly. Importing it
performs no CLI file operations. Tilesets are sorted once per
compilation while preserving original source IDs.
Validation supports only:
type: "map";- orthogonal, finite maps;
- atlas tilesets (
columns > 0); - complete finite tile-layer arrays;
-
non-rotated rectangular collision objects on object layers named
collisioncase-insensitively.
It removes empty GIDs, decodes Tiled H/V/diagonal transform flags,
resolves the applicable tileset by firstgid, converts
GIDs to atlas coordinates, retains layer visibility/opacity/order,
and emits world dimensions. Texture paths are rewritten to
res://assets/sprites/village/<image filename>.
The compiler rejects ellipses, points, polygons, polylines, rotated rectangles, invalid rectangle dimensions, unresolved GIDs, and out-of-range local tile IDs. It does not validate collision rectangles against world bounds.
9. Scene catalog
| Scene | Root / role | Used by |
|---|---|---|
core/screens/menu_screen/main_menu_screen.tscn
|
Control; configured main scene. |
Project startup. |
core/screens/join_screen/join_screen.tscn
|
Control; nickname and skin selection. |
Main menu START. |
core/screens/splash_screen/splash_screen.tscn
|
Node2D; animated logo intro. |
Main-menu logo click. |
game/game.tscn |
Node2D; gameplay composition. |
Successful join. |
world/world.tscn |
Node2D; map-loader host. |
game.tscn. |
actors/player/base_player.tscn |
CharacterBody2D; shared player
visuals/collider.
|
Inherited by local/remote scenes. |
actors/player/local_player.tscn |
Inherited local player with controls/camera/audio. | PlayerManager. |
actors/player/remote_player.tscn |
Inherited remote interpolated player. | PlayerManager. |
actors/seed/seed.tscn |
Node2D; one seed sprite. |
SeedManager. |
game/managers/seed_manager.tscn |
Empty Node2D placeholder. |
Unused. |
ui/chat/chat_panel.tscn |
CanvasLayer; chat input/history. |
game.tscn. |
ui/chat/chat_message.tscn |
One formatted chat row. | ChatPanel. |
ui/settings/settings_menu.tscn |
Full-screen audio/leave overlay. | Main menu and GlobalUi. |
ui/globals/global_ui.tscn |
Process-wide CanvasLayer. |
Autoload. |
ui/buttons/settings_button/settings_button.tscn
|
Global settings icon. | GlobalUi. |
ui/buttons/mute_button/mute_button.tscn |
Global mute toggle. | GlobalUi. |
ui/buttons/leave_button/leave_button.tscn
|
Conditional leave button. | Settings menu. |
ui/cursor/mouse_cursor.tscn |
Cursor texture controller. | GlobalUi. |
core/globals/MusicManager.tscn |
Two music players. | Autoload. |
core/globals/UIAudioManager.tscn |
Shared click player. | Autoload. |
Three temporary remote-player scene files are present in
actors/player/ with .tmp suffixes. They
are not referenced by current application scenes and are not part of
the scene catalog.
10. Audio bus reference
default_bus_layout.tres adds two buses under Godot's
implicit Master bus:
| Bus | Current users |
|---|---|
Music |
Both MusicManager players. |
SFX |
UiAudioManager/ClickSound. |
Master |
Splash AudioPlayer, local
EatSound, and any stream without an explicit
bus.
|
This routing means the SFX slider does not currently affect the eating or splash sounds.