authoring-godot-prompt…
Use when writing or editing a SKILL.md, a skill's references/*.md, or an agent definition in this repo — required frontmatter,…
Use when implementing signals in C# — [Signal] delegates, EmitSignal patterns, and async signal awaiting. Triggers on declaring, emitting, connecting, or awaiting a signal from a C# script, and on a signal crossing between C# and GDScript in either direction.
Claude Code
$ npx -y skills add jame581/GodotPrompter --skill csharp-signals --agent claude-code
Codex
$ npx skills add jame581/GodotPrompter --skill csharp-signals -a codex -y
Cursor
$ npx skills add jame581/GodotPrompter --skill csharp-signals -a cursor -y
Gemini CLI
$ npx skills add jame581/GodotPrompter --skill csharp-signals -a gemini-cli -y
GitHub Copilot
$ npx skills add jame581/GodotPrompter --skill csharp-signals -a github-copilot -y
OpenCode
$ npx skills add jame581/GodotPrompter --skill csharp-signals -a opencode -y
Windsurf
$ npx skills add jame581/GodotPrompter --skill csharp-signals -a windsurf -y
name: csharp-signals description: Use when implementing signals in C# — [Signal] delegates, EmitSignal patterns, and async signal awaiting. Triggers on declaring, emitting, connecting, or awaiting a signal from a C# script, and on a signal crossing between C# and GDScript in either direction.
This skill is **C# only**. For general C# conventions and project setup, see the **csharp-godot** skill. Godot signals in C# require a different mental model from GDScript: delegates declared with `[Signal]`, strongly-typed `+=`/`-=` connections, and mandatory disconnection in `_ExitTree()`. All examples target Godot 4.x with no deprecated APIs.
> **Related skills:** **csharp-godot** for C# conventions and project setup, **event-bus** for global signal hub architecture, **component-system** for signal-based component communication.
---
Signals are declared as `public delegate void` with the `[Signal]` attribute inside a `partial class` that extends a Godot type. The delegate name **must** end with `EventHandler` — Godot strips that suffix to produce the signal name exposed to the engine.
using Godot;
public partial class Player : CharacterBody2D
{
// Signal name in engine: "HealthChanged"
[Signal] public delegate void HealthChangedEventHandler(int current, int maximum);
// Signal name in engine: "Died"
[Signal] public delegate void DiedEventHandler();
// Signal name in engine: "ItemCollected"
[Signal] public delegate void ItemCollectedEventHandler(string itemName);
}**Naming rules:**
| Delegate name | Engine signal name | |---------------------------------|---------------------| | `HealthChangedEventHandler` | `HealthChanged` | | `DiedEventHandler` | `Died` | | `ItemCollectedEventHandler` | `ItemCollected` | | `PlayerSpawnedEventHandler` | `PlayerSpawned` |
Omitting the `EventHandler` suffix is a compile error: the source generator reports GD0201, "The name of the delegate must end with 'EventHandler'".
**Parameter type constraints:** Signal parameters must be `Variant`-compatible: numeric types, `bool`, `string`, enums, Godot structs (`Vector2`, `Color`, …), `StringName`, `NodePath`, `GodotObject` subclasses, `Godot.Collections.Array`/`Dictionary` (including the generic `Array<T>`/`Dictionary<TKey, TValue>`) and packed-array equivalents such as `int[]`. Other C# classes and structs fail the build with GD0202.
---
Use `EmitSignal(SignalName.SignalName, args...)`. The `SignalName` nested class is auto-generated by the Godot source generators at build time — one cached `StringName` per declared signal.
using Godot;
public partial class Player : CharacterBody2D
{
[Signal] public delegate void HealthChangedEventHandler(int current, int maximum);
[Signal] public delegate void DiedEventHandler();
[Signal] public delegate void ItemCollectedEventHandler(string itemName);
[Export] public int MaxHealth { get; set; } = 100;
private int _currentHealth;
public override void _Ready()
{
_currentHealth = MaxHealth;
}
public void TakeDamage(int amount)
{
_currentHealth = Mathf.Clamp(_currentHealth - amount, 0, MaxHealth);
// Type-safe emission — SignalName.HealthChanged is a generated constant.
EmitSignal(SignalName.HealthChanged, _currentHealth, MaxHealth);
if (_currentHealth == 0)
EmitSignal(SignalName.Died);
}
public void CollectItem(string itemName)
{
EmitSignal(SignalName.ItemCollected, itemName);
}
}`EmitSignal` does not check its arguments against the delegate. With the wrong argument count, `+=` handlers on a custom `[Signal]` are skipped without an error, and `Connect`/GDScript receivers log `Error calling from signal … Method expected N argument(s), but called with M`. With a wrong type, C# handlers get the value converted or defaulted (`0`, `null`); a typed GDScript receiver logs `Cannot convert argument N from X to Y` and is not called.
---
using Godot;
public partial class HudLayer : CanvasLayer
{
private Player _player;
public override void _Ready()
{
_player = GetNode<Player>("../Player");
// Connect with += — mirrors C# event syntax.
_player.HealthChanged += OnHealthChanged;
_player.Died += OnDied;
_player.ItemCollected += OnItemCollected;
}
private void OnHealthChanged(int current, int maximum)
{
GetNode<ProgressBar>("HealthBar").Value = (double)current / maximum * 100.0;
GetNode<Label>("HealthLabel").Text = $"{current} / {maximum}";
}
private void OnDied()
{
GetNode<Control>("DeathScreen").Show();
}
private void OnItemCollected(string itemName)
{
GetNode<Label>("PickupLabel").Text = $"Picked up: {itemName}";
}
}Use lambdas for one-off, short-lived responses. Store the lambda in a field if you need to disconnect it later.
// Anonymous lambda — cannot be disconnected by reference later.
_player.Died += () => GetNode<AudioStreamPlayer>("DeathSound").Play();
// Stored lambda — can be disconnected.
private Action<string> _onItemCollected;
public override void _Ready()
{
_onItemCollected = (itemName) =>
{
_collectCount++;
UpdateCollectDisplay();
};
_player.ItemCollected += _onItemCollected;
}
public override void _ExitTree()
{
_player.ItemCollected -= _onItemCollected;
}Connect inside `_Ready()` — or `_EnterTree()` for a node that is removed and re-added, since `_Ready()` runs only once. The node's references are resolved and the scene tree is available at that point. Connecting in the constructor or field initializers may fail because Godo
Agentic skills framework for Godot 4.x game development. Gives AI coding agents domain-specific expertise for GDScript and C# projects.
Use when writing or editing a SKILL.md, a skill's references/*.md, or an agent definition in this repo — required frontmatter,…
Use when cutting a GodotPrompter release or bumping its version — the version-bump sequence, tag-triggered workflow, and the…
Use when working with 2D-specific systems — TileMaps, parallax scrolling, 2D lights and shadows, canvas layers, particles 2D,…
Use when working with 3D-specific systems — materials, lighting, shadows, environment, global illumination, fog, LOD, occlusion…
Use when building or replacing an ability system — abilities with cost/cooldown, buffs/debuffs, stat modifiers, and gameplay…
Use when creating Godot editor plugins — EditorPlugin, @tool scripts, custom inspectors, and dock panels
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.