godot-composition-apps
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-composition-apps
Agent 安装分布
Skill 文档
Godot Composition & Architecture (Apps & UI)
This skill enforces the Single Responsibility Principle within Godot’s Node system. Whether building an RPG or a SaaS Dashboard, the rule remains: One Script = One Job.
The Core Philosophy
The Litmus Test
Before writing a script, ask: “If I attached this script to a literal rock, would it still function?”
- Pass: An
AuthComponenton a rock allows the rock to log in. (Context Agnostic) - Fail: A
LoginFormscript on a rock tries to grab text fields the rock doesn’t have. (Coupled)
The Backpack Model (Has-A > Is-A)
Stop extending base classes to add functionality. Treat the Root Node as an empty Backpack.
- Wrong (Inheritance):
SubmitButtonextendsAnimatedButtonextendsBaseButton. - Right (Composition):
SubmitButton(Root) HAS-AAnimationComponentand HAS-ANetworkRequestComponent.
The Hierarchy of Power (Communication Rules)
Strictly enforce this communication flow to prevent “Spaghetti Code”:
| Direction | Source â Target | Method | Reason |
|---|---|---|---|
| Downward | Orchestrator â Component | Function Call | Manager owns the workers; knows they exist. |
| Upward | Component â Orchestrator | Signals | Workers are blind; they just yell “I’m done!” |
| Sideways | Component A â Component B | FORBIDDEN | Siblings must never talk directly. |
The Sideways Fix: Component A signals the Orchestrator; Orchestrator calls function on Component B.
The Orchestrator Pattern
The Root Node script (e.g., LoginScreen.gd, UserProfile.gd) is now an Orchestrator.
- Math/Logic: 0%
- State Management: 100%
- Job: Wire components together. Listen to Component signals and trigger other Component functions.
Example: App/UI Context
| Concept | App/UI Example |
|---|---|
| Orchestrator | UserProfile.gd |
| Component 1 | AuthValidator (Logic) |
| Component 2 | FormListener (Input) |
| Component 3 | ThemeManager (Visual) |
Implementation Standards
1. Type Safety
Define components globally. Never use dynamic typing for core architecture.
# auth_component.gd
class_name AuthComponent extends Node
2. Dependency Injection
NEVER use get_node("Path/To/Child"). Paths are brittle.
ALWAYS use Typed Exports and drag-and-drop in the Inspector.
# Orchestrator script
@export var auth: AuthComponent
@export var form_ui: Control
3. Scene Unique Names
If internal referencing within a scene is strictly necessary for the Orchestrator, use the % Unique Name feature.
@onready var submit_btn = %SubmitButton
4. Stateless Components
Components should process the data given to them.
- Bad:
NetworkComponentfinds the username text field itself. - Good:
NetworkComponenthas a functionlogin(username, password). The Orchestrator passes the text field data into that function.
Anti-Patterns (NEVER DO THIS)
- The Monolith: A root script that handles UI events, HTTP requests, AND business logic.
- The Chain: Passing data through 4 layers of nodes to get to the destination. (Use Signals).
- Hard Dependency:
InputComponentcheckingget_parent().health. (The component must work on a rock; rocks don’t have health).
Code Structure Example (General App)
Component: clipboard_copier.gd
class_name ClipboardCopier extends Node
signal copy_success
signal copy_failed(reason)
func copy_text(text: String) -> void:
if text.is_empty():
copy_failed.emit("Text empty")
return
DisplayServer.clipboard_set(text)
copy_success.emit()
Orchestrator: share_menu.gd
extends Control
# Wired via Inspector
@export var copier: ClipboardCopier
@export var link_label: Label
func _ready():
# Downward communication
%CopyButton.pressed.connect(_on_copy_button_pressed)
# Upward communication listening
copier.copy_success.connect(_on_copy_success)
func _on_copy_button_pressed():
# Orchestrator delegation
copier.copy_text(link_label.text)
func _on_copy_success():
# Orchestrator managing UI state based on signal
%ToastNotification.show("Link Copied!")
Reference
- Master Skill: godot-master