godot-gdscript-mastery
Expert GDScript landmine guidance: static typing opcodes, signal-up/call-down, %UniqueName/@onready lifecycle, Callable bind/unbind, await sequences, typed collections, and safe Dictionary iteration. Use for code review, refactoring hot paths, or project standards. Trigger keywords: static_typing, s
By thedivergentai · 432 installs
npx skills add thedivergentai/gd-agentic-skills --skill godot-gdscript-mastery
Source repository · Upstream listing
GDScript Mastery
Expert guidance for writing performant, maintainable GDScript — Godot landmine decision trees, not a style guide reprint.
Do NOT Load
Do not load this skill for general prose style or Godot engine version upgrades (3→4 / 4.x hops) — those live in [godot version migration](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot version migration/SKILL.md) (plus official upgrading guides via that hub).
Do not preload every script below; open only the MANDATORY pointer for the Core Directive you are implementing.
Do not treat EditorScript utilities ( type checker , performance analyzer , signal architecture validator ) as runtime gameplay code.
NEVER Do in GDScript
NEVER use @onready and @export on the same variable — Initialization order will cause @onready to overwrite the Inspector value.
NEVER modify a Dictionary's size while iterating it — Use dict.keys().duplicate() or iterate a clone to safely erase elements.
NEVER use string based connect("signal", ...) — Always use the Signal object syntax ( button.pressed.connect(...) ) for compile time safety.
NEVER attempt to override non virtual native engine methods — Overriding queue free() or get class() is unsupported and will be ignored by engine callbacks.
NEVER use dynamic get node() or $ inside process() — Fetching paths every frame stalls the CPU. Cache and use @onready .
NEVER use Parent.method() calls — Violates "Signal Up, Call Down". Use signals to communicate with parents.
NEVER use is followed by a hard cast — If the type check passes but the object changes, it crashes. Use as and check for null.
NEVER use print() for production debugging — Use push error() , push warning() , or breakpoints.
NEVER pre load huge resources in ready() — Use ResourceLoader.load threaded request() for async loading.
NEVER use global variables in Autoloads when static var is sufficient — Static variables offer better encapsulation.
Core Directives (decision trees + MANDATORY scripts)
1. Strong Typing & Performance
Landmine Decision
Hot path still Variant ? Annotate vars/returns; prefer typed collections
Generic math in process ? Use typed helpers ( absf , ceili , clampf )
Green safe lines missing? Fix inference with := or explicit types
MANDATORY : [typed collections mastery.gd](scripts/typed collections mastery.gd), [array preallocation perf.gd](scripts/array preallocation perf.gd), [type checker.gd](scripts/type checker.gd) (EditorScript audit).
2. Signal Architecture
Landmine Decision
Child needs parent reaction? Emit signal up — never call parent methods
Cross script payload unsafe? Typed signal name(arg: Type)
Connect visibility? Prefer ready() connects over invisible editor only wiring
MANDATORY : [typed signal definitions.gd](scripts/typed signal definitions.gd), [signal architecture validator.gd](scripts/signal architecture validator.gd).
3. Node Access & Lifecycle Safety
Landmine Decision
Need child nodes? @onready / %UniqueName — never in init()
Scene instanced node with ctor args? Use @export injection — init(args) breaks PackedScene.instantiate()
Path lookup every frame? Cache once; never $ / get node in process
MANDATORY : [safe type casting.gd](scripts/safe type casting.gd).
4. Callable & Signal (First Class)
Landmine Decision
Extra context on callback? Callable.bind(...)
Discard unused signal args? Callable.unbind(n)
One off timeout logic? Inline lambda OK; keep refs if create callback style longevity matters
MANDATORY : [callable binding context.gd](scripts/callable binding context.gd), [unbind signal args.gd](scripts/unbind signal args.gd), [advanced lambdas.gd](scripts/advanced lambdas.gd), [functional lambda logic.gd](scripts/functional lambda logic.gd).
5. Async, Statics & Safe Collections
Landmine Decision
Sequence timers without threads? await chains — see await manager
Global state without Autoload bloat? static var (+ nullify large statics when done)
Erase while iterating Dictionary? Clone keys first
MANDATORY : [await sequence manager.gd](scripts/await sequence manager.gd), [static var singleton alt.gd](scripts/static var singleton alt.gd), [dictionary safe iteration.gd](scripts/dictionary safe iteration.gd), [performance analyzer.gd](scripts/performance analyzer.gd) (EditorScript).
Script Catalog (all files)
Script When to open
[typed collections mastery.gd](scripts/typed collections mastery.gd) Typed Array/Dictionary opcodes
[functional lambda logic.gd](scripts/functional lambda logic.gd) reduce / all / any
[advanced lambdas.gd](scripts/advanced lambdas.gd) Higher order Callables
[safe type casting.gd](scripts/safe type casting.gd) as + null checks
[typed signal definitions.gd](scripts/typed signal definitions.gd) Typed signal boundaries
[callable binding context.gd](scripts/callable binding context.gd) bind() context injection
[unbind signal args.gd](scripts/unbind signal args.gd) unbind() arity trim
[await sequence manager.gd](scripts/await sequence manager.gd) Non blocking await flows
[array preallocation perf.gd](scripts/array preallocation perf.gd) resize() pre alloc
[static var singleton alt.gd](scripts/static var singleton alt.gd) Lightweight global state
[dictionary safe iteration.gd](scripts/dictionary safe iteration.gd) Safe erase while iterate
[type checker.gd](scripts/type checker.gd) EditorScript typing audit
[performance analyzer.gd](scripts/performance analyzer.gd) EditorScript hot path scan
[signal architecture validator.gd](scripts/signal architecture validator.gd) EditorScript signal up checks
Quick Landmines
Prefer dict.get("key", default) over dict["key"] when presence is uncertain.
Toggle Access as Scene Unique Name and read via %Name for critical UI/nodes.
Script layout order: extends → class name → signals/enums/consts → exports/onready → lifecycle → public → private .
Expert knowledge (on demand)
LLM ignorance rule: If a general agent would not know it before reading, load the reference — never delete expert deltas.
[gdscript core directives.md](references/gdscript core directives.md) — restored baseline pedagogy (architecture, WHY, implementation depth)
Reference
Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing to a peer domain — do not preload the whole lattice.
Official Documentation
[GDScript basics](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript basics.html) — Language core for typed vars/funcs, signal declarations, await , and first class Callables this skill standardizes.
[GDScript style guide](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript styleguide.html) — Canonical script order ( extends → class name → signals → exports → lifecycle → methods) used in reviews and refactoring.
[Static typing in GDScript](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/static typing.html) — Why typed Arrays/Dictionaries and return types unlock optimized opcodes and editor safe lines.
[GDScript: An introduction to dynamic languages](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript advanced.html) — Lambdas, higher order Callables, and advanced patterns behind filter/map/reduce helpers.
[GDScript warning system](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/warning system.html) — Turn unsafe casts, unused signals, and untyped hot paths into CI visible warnings.
[Logic preferences](https://docs.godotengine.org/en/stable/tutorials/best practices/logic preferences.html) — When to prefer declarative signals vs imperative calls so scripts stay decoupled.
[Scene organization](https://docs.godotengine.org/en/stable/tutorials/best practices/scene organization.html) — Official “signal up, call down” ownership rules this skill enforces.
[Using signals](https://docs.godotengine.org/en/stable/getting started/step by step/signals.html) — Connect/emit model and why string based connect by name is avoided.
[Callable](https://docs.godotengine.org/en/stable/classes/class callable.html) — bind() / unbind() APIs for injecting or discarding callback arguments without wrapper nodes.
[Array](https://docs.godotengine.org/en/stable/classes/class array.html) — Typed arrays, resize() , and functional methods ( filter / map / reduce / all / any ) used in the scripts.
[Dictionary](https://docs.godotengine.org/en/stable/classes/class dictionary.html) — Safe .get() defaults and why size must not change while iterating keys.
[CPU optimization](https://docs.godotengine.org/en/stable/tutorials/performance/cpu optimization.html) — Cache @onready / %UniqueName instead of get node / $ inside process loops.
Related Skills
Prerequisites
[godot project foundations](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot project foundations/SKILL.md) — Project layout, Autoload registration, and scene ownership conventions that typed GDScript scripts plug into.
[godot composition](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot composition/SKILL.md) — Component boundaries clarify which scripts own signals vs call down APIs before style enforcement.
Complements
[godot version migration](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot version migration/SKILL.md) — Engine version upgrades (3→4 language breaks, 4.x hops); this skill stays on current GDScript 2.0 idioms.
[godot signal architecture](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot signal architecture/SKILL.md) — Deepens connect flags, buses, and sequencers after this skill’s typed signal/Callable basics.
[godot autoload architecture](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot autoload architecture/SKILL.md) — Contrasts heavy Autoloads with the static var singleton alternatives shown here.
[godot resource data patterns](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot resource data patterns/SKILL.md) — Prefer Resources for shared config; keep GDScript modules thin and typed around Resource payloads.
[godot scene management](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot scene management/SKILL.md) — @onready , unique names, and await sequences must stay valid across scene swaps and loaders.
[godot testing patterns](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot testing patterns/SKILL.md) — Typed signals and Callables make watch signals / spies reliable in unit tests.
[godot debugging profiling](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot debugging profiling/SKILL.md) — Pair style/perf smells from this skill with profiler and custom monitors when hot paths remain slow.
[godot state machine advanced](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot state machine advanced/SKILL.md) — FSM enter/exit handlers should follow the same typed signal and await sequencing conventions.
Downstream / consumers
[godot performance optimization](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot performance optimization/SKILL.md) — Escalate when typed GDScript alone is not enough; servers, pooling, and broader CPU/GPU tactics live there.
[godot auditor](https://github.com/thedivergentai/gd agentic skills/blob/main/skills/godot auditor/SKILL.md) — Project wide audits consume the typing, signal up, and hot path rules codified in th