godot-gdscript-mastery

$npx mdskill add thedivergentai/GD-Agentic-Skills/godot-gdscript-mastery

Provides expert GDScript guidance for performance, safety, and maintainability.

  • Prevents common pitfalls like @onready/@export conflicts and unsafe Dictionary iteration.
  • Depends on Godot 4.x engine APIs and GDScript static typing features.
  • Recommends based on static typing, signal architecture, and lifecycle best practices.
  • Delivers actionable code review and refactoring advice for hot paths and project standards.

SKILL.md

.github/skills/godot-gdscript-masteryView on GitHub ↗
---
name: godot-gdscript-mastery
description: "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, signal_architecture, unique_nodes, @onready, class_name, signal_up_call_down, Callable.bind, typed_collections, await_sequence."
---

# 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 3→4 migration checklists — those live in Official Documentation.
- 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.

---

## Godot 4.7: GDScript

- Typed override methods **inherit return type** — overrides require explicit `return` (add `return null` if needed).
- Setting packed array elements no longer invokes the whole-array property setter.

## 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-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 this skill.
- [godot-ability-system](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-ability-system/SKILL.md) — Abilities need typed signal payloads and await-safe cooldowns grounded in these language patterns.
- [godot-combat-system](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-combat-system/SKILL.md) — Damage/death fan-out depends on typed emits and safe casts taught here.

#### Master
- [godot-master](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-master/SKILL.md) — Library router and mirrored module entry; open when discovering which Domain Skill owns a cross-cutting scripting concern.

More from thedivergentai/GD-Agentic-Skills

SkillDescription
godot-2d-animationExpert patterns for 2D animation in Godot using AnimatedSprite2D and skeletal cutout rigs. Use when implementing sprite frame animations, procedural animation (squash/stretch), cutout bone hierarchies, or frame-perfect timing systems. Trigger keywords: AnimatedSprite2D, SpriteFrames, animation_finished, animation_looped, frame_changed, frame_progress, set_frame_and_progress, cutout animation, skeletal 2D, Bone2D, procedural animation, animation state machine, advance(0).
godot-2d-physicsExpert patterns for Godot 2D physics including collision layers/masks, Area2D triggers, raycasting, and PhysicsDirectSpaceState2D queries. Use when implementing collision detection, trigger zones, line-of-sight systems, or manual physics queries. Trigger keywords: CollisionShape2D, CollisionPolygon2D, collision_layer, collision_mask, set_collision_layer_value, set_collision_mask_value, Area2D, body_entered, body_exited, RayCast2D, force_raycast_update, PhysicsPointQueryParameters2D, PhysicsShapeQueryParameters2D, direct_space_state, move_and_collide, move_and_slide.
godot-3d-lightingExpert patterns for Godot 3D lighting including DirectionalLight3D shadow cascades, OmniLight3D attenuation, SpotLight3D projectors, VoxelGI vs SDFGI, and LightmapGI baking. Use when implementing realistic 3D lighting, shadow optimization, global illumination, or light probes. Trigger keywords: DirectionalLight3D, OmniLight3D, SpotLight3D, shadow_enabled, directional_shadow_mode, directional_shadow_split, omni_range, omni_attenuation, spot_range, spot_angle, VoxelGI, SDFGI, LightmapGI, ReflectionProbe, Environment, WorldEnvironment.
godot-3d-materialsExpert patterns for Godot 3D PBR materials using StandardMaterial3D including albedo, metallic/roughness workflows, normal maps, ORM texture packing, transparency modes, and shader conversion. Use when creating realistic 3D surfaces, PBR workflows, or material optimization. Trigger keywords: StandardMaterial3D, BaseMaterial3D, albedo_texture, metallic, metallic_texture, roughness, roughness_texture, normal_texture, normal_enabled, orm_texture, transparency, alpha_scissor, alpha_hash, cull_mode, ShaderMaterial, shader parameters.
godot-3d-world-buildingExpert patterns for 3D level design using GridMap with MeshLibrary, CSG constructive solid geometry, occlusion, and runtime GridMap builders. Use when building 3D levels, modular tilesets, or BSP-style geometry. For sky/fog/Environment recipes, route to godot-3d-lighting. Trigger keywords: GridMap, MeshLibrary, set_cell_item, get_cell_item, map_to_local, local_to_map, CSGCombiner3D, CSGBox3D, CSGSphere3D, CSGPolygon3D, OccluderInstance3D, bake CSG.
godot-ability-systemExpert patterns for RPG/action ability systems including cooldown strategies, combo systems, ability chaining, skill trees with prerequisites, upgrade paths, and resource management. Use when implementing unlockable abilities, character progression, or complex skill systems. Trigger keywords: PlayerAbility, AbilityManager, cooldown, SkillTree, SkillNode, prerequisites, can_use, execute, ComboSystem, ability_chain, global_cooldown, charge_system, upgrade_path.
godot-adapt-2d-to-3dExpert patterns for migrating 2D games to 3D including node type conversions, camera systems (third-person, first-person, orbit), physics layer migration, sprite-to-model art pipeline, and control scheme adaptations. Use when porting 2D projects to 3D or adding 3D elements. Trigger keywords: CharacterBody2D to CharacterBody3D, Area2D to Area3D, Camera2D to Camera3D, Vector2 to Vector3, collision_layer migration, sprite to MeshInstance3D, 2D to 3D conversion.
godot-adapt-3d-to-2dExpert patterns for simplifying 3D games to 2D including dimension reduction strategies, 2.5D fake-depth, isometric ports, camera flattening, physics conversion, 3D-to-sprite art pipeline, and control simplification. Use when porting 3D to 2D, building 2.5D / isometric / fake-depth gameplay, creating 2D versions for mobile, or prototyping. Trigger keywords: CharacterBody3D to CharacterBody2D, Camera3D to Camera2D, Vector3 to Vector2, flatten Z-axis, 2.5D, isometric, fake depth, Y-sort, simulated Z, orthogonal projection, 3D to sprite conversion, performance optimization.
godot-adapt-desktop-to-mobileExpert patterns for porting desktop games to mobile including touch control schemes (virtual joystick, gesture detection), UI scaling for small screens, performance optimization for mobile GPUs, battery life management, and platform-specific features. Use when creating mobile ports or cross-platform mobile builds. Trigger keywords: TouchScreenButton, virtual_joystick, gesture_detector, InputEventScreenTouch, InputEventScreenDrag, mobile_optimization, battery_saving, adaptive_performance, MOBILE_ENABLED.
godot-adapt-mobile-to-desktopExpert patterns for scaling mobile games to desktop including mouse/keyboard controls, increased resolution and graphical fidelity, expanded UI layouts, settings menus, window management, and platform-specific features. Use when creating desktop ports or cross-platform releases. Trigger keywords: mouse_controls, keyboard_shortcuts, resolution_scaling, graphics_settings, fullscreen_toggle, window_modes, Steam_integration, desktop_optimization.