2.5 KiB
| description | globs | alwaysApply |
|---|---|---|
| Godot client — keep main.gd thin; split scripts by concern (Neon Sprawl). | client/**/*.gd | false |
Godot client script organization (Neon Sprawl)
Avoid a single monolithic main.gd. Treat the main scene root as a composer: wire nodes, @export references, and signals—not every subsystem.
Where logic lives
main.gd(scene root): Bootstrapping only—attach children, connect signals, optional high-level toggles. If a block grows past ~50 lines or a clear concern appears, extract it.- Avatar / props: Keep behavior on the node that owns it (e.g.
player.gdonCharacterBody3D). - Cross-cutting features: Prefer a child
Node(orNode3D) with its own script, e.g. server HTTP sync →position_authority_client.gd, interaction POST →interaction_request_client.gd. Use signals or small public methods somaindoes not call into deep implementation details.
class_name vs headless / CI
class_name registers global types only after Godot has imported the project (.godot/). That folder is gitignored here, so godot --headless --path client on a fresh clone fails if main.gd annotates types with class_name aliases. Prefer Node / Node3D + connect("signal", …) and call("method", …) for thin composition from the scene root unless the project guarantees a prior editor import.
Autoloads
Use sparingly (e.g. shared config many scenes need). Default to scene-local nodes until duplication proves an autoload.
Granularity
- One obvious concern per script (picking vs network vs locomotion)—not one file per tiny helper.
- New work: add
res://scripts/<feature>.gd(or a subfolder when a feature set grows) rather than extendingmain.gdby default.
Godot .uid companion files (Godot 4)
Godot writes a *.gd.uid next to each script (editor import / asset scan). Commit it with the .gd in the same change: do not leave new scripts with untracked .uid files, and do not add *.uid to .gitignore—this repo already tracks hundreds of them for stable uid:// references. Applies to client/scripts/ and client/test/ the same way.
Examples
✅ main.gd: _ready() → get_node, connect authority.authoritative_position_received to _on_snap
✅ position_authority_client.gd: HTTP + emit authoritative_position_received
❌ main.gd: 300 lines of HTTP + ray math + player tuning in one file
Aligns with GDScript style (small virtual overrides, extract _ helpers).