godot
Skill2 starsChanged 4 months agoMITView on GitHub
Use when working on any Godot 4.x development — writing or reviewing .gd files, designing scene trees, implementing game systems in GDScript, structuring Godot projects, or asking about nodes, signals, AutoLoads, Resources, or the Godot editor. Also trigger when implementing game patterns (Observer, State, Command, etc.) in a Godot project — this skill takes precedence over game-patterns for Godot-specific implementation. NOT for engine-agnostic pattern theory (see game-patterns). NOT for Love2D (see love2d). NOT for shaders or visual effects (see godot-shader).
12 other projects use a version of this.
Adopted by
Most recently taken up by
- n-n-code/n-n-code-skillstheir own version, first seen Nov 8, 2026
- AxlZero21/Skillstheir own version, first seen Nov 8, 2026
- jammyfu/open-game-skillstheir own version, first seen Oct 11, 2026
- jablonkai/skillstheir own version, first seen Oct 1, 2026
- saschb2b/skillstheir own version, first seen Aug 8, 2026
- muxammadmamajonov/dot-claudetheir own version, first seen Jul 6, 2026
Other versions12 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 12
- fetasty/godot-skills★ 29same name
- saschb2b/skills★ 22same name
- jammyfu/open-game-skills★ 12same name
- fernforestgames/agent-skill-godot★ 11same name
- n-n-code/n-n-code-skills★ 4same name
- jablonkai/skills★ 2same name
- jarrodmedrano/jarrod-claude-skills★ 2same name
- lucasbrandao4770/claude-code-gamedev★ 2same name
- shihabshahrier/Godot-Skill★ 2same name
- aleiby/claude-skills★ 1same name
2 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository67 other files it gives its agents.
- AGENTS.mdAGENTS.md
- agent-architectureSkill
- agent-evaluationSkill
- agent-memorySkill
- agent-post-trainingSkill
- agent-self-evolutionSkill
- agent-tool-designSkill
- api-designSkill
- application-architectureSkill
- brainstormSkill
- code-reviewerSkill
- coding-agent-designSkill
- concurrency-designSkill
- context-engineeringSkill
- dockerSkill
- game-audioSkill
- game-designSkill
- game-narrativeSkill
- game-patternsSkill
- game-performanceSkill
- game-renderingSkill
- game-visualsSkill
- git-commitSkill
- git-prSkill
- godot-shaderSkill
- gpu-rendering-architectureSkill
- grafanaSkill
- helmSkill
- homelab-monitoringSkill
- k3sSkill
- k8s-networkingSkill
- k8s-operationsSkill
- k8s-storageSkill
- k8s-workloadsSkill
- knowledge-baseSkill
- level-designSkill
- llm-inference-servingSkill
- loggingSkill
- logqlSkill
- love2d-fennelSkill
- love2dSkill
- ml-platform-architectureSkill
- ml-post-trainingSkill
- multi-agent-collaborationSkill
- nix-dendriticSkill
- nix-packagingSkill
- nixSkill
- odin-designSkill
- odin-gamedevSkill
- orchestratorSkill
- physical-ai-systemsSkill
- plannerSkill
- prd-to-storiesSkill
- prd-writingSkill
- promqlSkill
- pr-reviewerSkill
- python-designSkill
- rag-designSkill
- ray-data-pipelinesSkill
- ray-kubernetes-infrastructureSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
8 rules. 0 are common, 0 are distinctive, and 8 are very specific to this project.
0
Common
Most of the 11 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 69
Use preload for scenes known at compile time.
- Very specific: line 77
Follow this order in every .gd file:
- Very specific: line 124
Methods: don't repeat the class name in arguments — Inventory.add(item) not Inventory.add_item(item).
- Very specific: line 148
Always use type hints. Prefer := (type inference) when the right-hand side makes the type obvious.
- Very specific: line 178
Use class_name to make custom types available project-wide without preload.
- Very specific: line 265
Signal spaghetti: When every node connects to every other node, tracing behavior becomes impossible.
- Very specific: line 275
Returning mid-function: Use return only at the start (guard clause) or end of a function.
- Very specific: line 277
Using
nullwhen a typed default exists: Prefer Vector2.ZERO, "", [], or .new() over null.
“Common” is measured: kept by at least 6 in 10 of the 11 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Godot 4.x Development
Godot 4.x (baseline: 4.6) with GDScript. All code examples target GDScript — not C#. This skill is for a hobbyist developer; prefer engine-native features over custom implementations.
References
| Reference | When to read it |
references/scene-architecture.md | Node selection, scene splitting decisions, large project layout, composition patterns |
references/gdscript-patterns.md | Signal bus, state machine, resource config, coroutines, typed arrays, advanced GDScript |
references/godot-pattern-mappings.md | Full GDScript implementations of all 23 game patterns with Godot-idiomatic code |
Scene Architecture
The scene tree is a composition hierarchy, not an inheritance hierarchy. Each scene is a reusable unit. Prefer many small, focused scenes over one large scene.
Scene vs Node vs Resource — pick one:
- Scene (
.tscn): reusable entity with its own lifecycle — enemies, UI panels, projectiles, pickups. Instantiate withpreload().instantiate(). - Node (inline in parent scene): structural grouping with no independent reuse — a
HBoxContainerholding buttons, aMarker2Dfor spawn points. - Resource (
.tres/.res): pure data with no scene presence — item stats, weapon configs, level data. ExtendResourceand use@export.
Flat over deep. A node tree 4+ levels deep is a design smell. If you're writing get_node("../../Player/Stats"), the scene needs restructuring. Pass references via @export or signals instead.
File naming: snake_case for all directories, scenes, and scripts in Godot 4. Name scripts and scenes after the scene's root node (player.tscn + player.gd).
Split a scene when:
- It's reused in multiple parent scenes
- It has its own independent state and lifecycle
- It exceeds ~20 nodes
- Different team members (or future you) need to edit it independently
Composition pattern: Give complex entities capabilities via child nodes with scripts, not inheritance chains.
# Player scene tree — each child is a focused capability node
Player (CharacterBody2D)
├── HealthComponent (Node) # handles HP, death signal
├── HurtboxComponent (Area2D) # detects incoming damage
├── StateMachine (Node) # drives behavior states
├── AnimationPlayer
└── Sprite2DEach component script is self-contained. HealthComponent emits died — the parent doesn't need to know who's listening.
Scene instancing:
const BulletScene: PackedScene = preload("res://scenes/bullet.tscn")
func _shoot() -> void:
var bullet: Bullet = BulletScene.instantiate()
bullet.direction = aim_direction
get_tree().current_scene.add_child(bullet) # add to scene root, not selfUse preload for scenes known at compile time. Use load only for paths determined at runtime from a fixed, trusted list — never pass user-provided strings directly to load().
GDScript Idioms
Script File Ordering
Follow this order in every .gd file:
# 1. class_name / extends
# 2. ## docstring
# 3. signals
# 4. enums
# 5. constants
# 6. @export vars
# 7. public vars
# 8. private vars (_prefix)
# 9. @onready vars
# 10. _init / _ready / _enter_tree
# 11. _process / _physics_process / _unhandled_input
# 12. signal callbacks (_on_*)
# 13. public methods
# 14. private methods (_prefix)Signals
Signals decouple emitters from listeners. The emitter knows nothing about who's listening.
# Declaration — always type parameters
signal health_changed(new_health: int, max_health: int)
signal died
# Emit
health_changed.emit(current_health, max_health)
# Connect in _ready — prefer Callable syntax
func _ready() -> void:
$HealthComponent.health_changed.connect(_on_health_changed)
$HealthComponent.died.connect(_on_player_died)
func _on_health_changed(new_health: int, max_health: int) -> void:
$HUD.update_health_bar(new_health, max_health)Use signals when: a child needs to notify its parent, or two siblings need to communicate without direct references. Use direct calls when: a parent calls a method on a child it owns — that's normal control flow, not coupling.
Signal bus (EventBus AutoLoad): For truly global events (game over, scene transition, achievement unlocked), a signal bus AutoLoad is appropriate. See references/gdscript-patterns.md.
Naming conventions:
- Signals: past tense (
moved,died). Append_started/_finishedfor process signals (talk_started,talk_finished). - Booleans: prefix with
is_,can_, orhas_(is_active,can_jump,has_key). - Methods: don't repeat the class name in arguments —
Inventory.add(item)notInventory.add_item(item).
Exports and Resources
# Basic exports
@export var speed: float = 200.0
@export var max_health: int = 100
@export var projectile_scene: PackedScene
# Custom Resource for data — define once, reuse everywhere
class_name WeaponData extends Resource
@export var damage: int = 10
@export var fire_rate: float = 0.5
@export var projectile_scene: PackedScene
# Use it
@export var weapon: WeaponData # assign .tres in editorCustom Resources are the right tool for item databases, enemy stats, level configs — anything that's data, not behavior.
Static Typing
Always use type hints. Prefer := (type inference) when the right-hand side makes the type obvious. Use explicit annotation when the compiler can't infer.
# Inference — type is obvious from the right-hand side
var speed := 200.0
var direction := Vector2.ZERO
var timer := Timer.new()# Explicit — compiler can't infer (Variant returns, typed arrays, PackedScene.instantiate())
var text: String = array.pop_back()
var enemy: Enemy = EnemyScene.instantiate()
var enemies: Array[Enemy] = []
var damage_values: Array[int] = [10, 20, 30]# Bad — no types at all
var speed = 200
func take_damage(amount):
health -= amount
# Good — typed variable and typed parameters/return
var speed: float = 200.0
func take_damage(amount: int) -> void:
health -= amount
health_changed.emit(health, max_health)Use class_name to make custom types available project-wide without preload.
AutoLoads
AutoLoads are project-wide singletons. Use them sparingly.
Appropriate AutoLoad uses:
- Signal bus / EventBus (global events)
- SceneManager (scene transitions)
- AudioManager (global audio)
- SaveManager (save/load)
Avoid AutoLoad for: anything a scene can own and pass down. If only two scenes need to share data, pass it via @export or a signal — not a global.
# EventBus.gd — AutoLoad
signal game_over(winner: String)
signal score_changed(new_score: int)Groups
Groups are lightweight tags for cross-cutting concerns. Avoid get_node path gymnastics.
# Tag nodes in editor or via code
add_to_group("enemies")
# Query from anywhere
func _on_explosion() -> void:
for enemy in get_tree().get_nodes_in_group("enemies"):
(enemy as Enemy).stun()Coroutines and await
# Wait for signal
await get_tree().create_timer(2.0).timeout
# Wait for animation
$AnimationPlayer.play("death")
await $AnimationPlayer.animation_finished
# Sequence with await
func _die() -> void:
died.emit()
$AnimationPlayer.play("death")
await $AnimationPlayer.animation_finished
queue_free()Pattern Mapping (Quick Reference)
This skill takes precedence over game-patterns for Godot implementation. When both fire, use the Godot-native approach below. For full GDScript implementations, see references/godot-pattern-mappings.md.
| Pattern | Godot Approach | Note |
| Observer | Signals | Built-in; always prefer over manual observer lists |
| Singleton | AutoLoad | Register in Project Settings → AutoLoad |
| State | Custom state nodes + StateMachine node | Child nodes per state; AnimationTree for animation states |
| Command | Callable + Array buffer | Store Callable objects; call .call() to execute |
| Factory | PackedScene.instantiate() | preload the scene; factory node manages spawning |
| Strategy | Swappable Resource or script | @export var strategy: Resource; duck-typed or typed |
| Decorator | Child node wrapping behavior | Add/remove child nodes at runtime |
| Service Locator | AutoLoad with fallback | AutoLoad provides service; swap implementation at runtime |
| Event Queue | Array + _process drain | Buffer events in Array; drain one per frame or in batch |
| Component | Child nodes with scripts | Each child = one capability; communicate via signals |
| Prototype | resource.duplicate() | Resource.duplicate(true) for deep copy |
| Flyweight | Shared Resource | Multiple nodes share one Resource instance |
| Object Pool | Node pool with visible = false | Disable/re-enable nodes instead of queue_free/instantiate |
| Double Buffer | Two arrays, swap each frame | Manual; rarely needed — Godot's rendering handles most cases |
| Game Loop | Built-in (_process, _physics_process) | Override _process(delta) — engine owns the loop |
| Update Method | _process(delta) / _physics_process(delta) | Use _physics_process for physics; _process for visuals |
| Spatial Partition | Area2D/Area3D + physics layers | Use collision layers/masks before writing custom grids |
| Dirty Flag | @export setter with dirty bool | set(value): _dirty = true; _data = value |
| Data Locality | TileMapLayer, MultiMeshInstance3D | Engine handles; use these nodes for large uniform sets |
| Bytecode | GDScript itself / Expression class | Expression.parse() for runtime-evaluated expressions |
| Subclass Sandbox | Base script + class_name | Extend base class; override _execute() hook |
| Type Object | Custom Resource subclass | Each "type" is a .tres file; behavior via exported data |
Common Pitfalls
Signal spaghetti: When every node connects to every other node, tracing behavior becomes impossible. Keep signal connections local — a node connects to its own children's signals in _ready. For cross-scene events, route through an EventBus AutoLoad, not direct cross-scene connections.
AutoLoad abuse: AutoLoads are globals. Globals make code hard to test and reason about. Before adding an AutoLoad, ask: can this data live in a scene and be passed down? If yes, do that.
Deep node path coupling: get_node("../../HUD/HealthBar") breaks whenever the tree changes. Instead: pass references via @export, use signals to communicate upward, or use groups for cross-cutting queries.
Skipping static types: Untyped GDScript loses editor autocompletion, misses type errors until runtime, and makes refactoring painful. Type everything — variables, parameters, return types.
Overusing _process: _process runs every frame. For things that only change on events (health bar, score display), connect to a signal instead. For timers, use Timer nodes or get_tree().create_timer(). Reserve _process for things that genuinely need per-frame updates (movement, continuous animation).
Returning mid-function: Use return only at the start (guard clause) or end of a function. Mid-function returns hide control flow and make methods harder to trace.
Using null when a typed default exists: Prefer Vector2.ZERO, "", [], or .new() over null. Null checks proliferate and mask missing initialization. Use null only when the engine API forces it.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

