Claude-skill-registry godot-refactor

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/godot-refactor" ~/.claude/skills/majiayu000-claude-skill-registry-godot-refactor && rm -rf "$T"
manifest: skills/data/godot-refactor/SKILL.md
source content

Godot Refactor Orchestrator

This orchestrator runs 5 code quality mini-skills in sequence. For individual operations, invoke mini-skills directly.

Core Principle: Scene-First, Signal-Based, Component Composition

Iron Law: NO functional or visual changes during refactoring. Period.

This skill automatically refactors Godot projects to cleaner, more modular architecture while preserving exact behavior. Every operation creates a git commit. Rollback is always available.


UPON INVOCATION - START HERE

When this skill is invoked, IMMEDIATELY execute the following sequence:

1. Verify Godot Project (5 seconds)

# Check if this is a Godot project
ls project.godot 2>/dev/null && echo "✓ Godot project detected" || echo "✗ Not a Godot project"

If NOT a Godot project:

  • Inform user this skill only works on Godot projects
  • Ask if they want to navigate to the correct directory
  • STOP here

If IS a Godot project:

  • Proceed to step 2

2. Begin Phase 1: Analysis & Baseline (AUTOMATIC)

Do NOT ask "What would you like me to do?" - Start analyzing immediately.

Execute these commands in parallel:

# Detect code-created objects
grep -rn "\.new()" --include="*.gd" . | grep -E "(Node|Timer|Area|Sprite|Control|Collision)" | wc -l

# Detect monolithic scripts
find . -name "*.gd" -exec wc -l {} + | awk '$1 > 150' | wc -l

# Detect tight coupling
grep -rn "get_node\|has_method" --include="*.gd" . | wc -l

# Detect inline data
grep -rn "^[[:space:]]*const.*\[" --include="*.gd" . | wc -l

3. Present Findings (30 seconds)

Show the user:

=== Godot Refactoring Analysis ===

Project: [project name from project.godot]

Anti-patterns detected:
- Code-created objects: X
- Monolithic scripts: X
- Tight coupling: X
- Inline data: X
- Conflicting operations: (will be detected after refactoring)

Total: X anti-patterns found

Refactoring includes:
✓ Automatic testing after each operation
✓ Auto-rollback on test failure
✓ Git commit per operation
✓ Push to remote on demand

Would you like me to:
1. Proceed with automatic refactoring (recommended)
2. Show detailed breakdown first
3. Cancel

4. Wait for User Choice

  • If 1 (Proceed): Start Phase 2 immediately
  • If 2 (Details): Show detailed file-by-file breakdown, then offer to proceed
  • If 3 (Cancel): Exit skill

CRITICAL: Do NOT stop after loading the skill. Do NOT ask "What would you like me to do?" Start with step 1 immediately.


When to Use This Skill

Use this skill when you detect ANY of these symptoms:

Code-Created Objects:

  • .new()
    calls in
    _ready()
    ,
    _process()
    , or other lifecycle methods
  • add_child()
    with programmatically created nodes
  • Timers, Areas, Sprites created in code

Monolithic Scripts:

  • Scripts >150 lines
  • Multiple unrelated responsibilities in one file
  • God objects that do everything

Tight Coupling:

  • get_node()
    chains to access other nodes
  • has_method()
    checks before calling
  • Direct property access across nodes
  • Parent-child dependencies for behavior

Inline Data:

  • const
    arrays with game data
  • Hardcoded configuration in scripts
  • Data that should be resources

Deep Inheritance:

  • More than 2 levels of script inheritance
  • Inheritance used for code reuse instead of composition

Decision Flowchart

User mentions Godot project
    ↓
Does it have ANY of the above symptoms?
    ↓ YES                    ↓ NO
Use this skill              Regular development
    ↓
Run Phase 1: Analysis
    ↓
Anti-patterns found?
    ↓ YES                    ↓ NO
Run Phases 2-4              Document clean state

The Four Phases

Phase 1: Analysis & Baseline (Automatic)

Purpose: Detect all anti-patterns and create safety baseline.

Steps:

  1. Scan Project Files
# Find all Godot script files
find . -name "*.gd" -type f

# Find all scene files
find . -name "*.tscn" -type f
  1. Detect Anti-Patterns

Use detection patterns from

anti-patterns-detection.md
:

# Code-created objects
grep -rn "\.new()" --include="*.gd" .

# Monolithic scripts (>150 lines)
find . -name "*.gd" -exec wc -l {} + | awk '$1 > 150 {print $2 " (" $1 " lines)"}'

# Tight coupling
grep -rn "get_node\|get_parent\|has_method" --include="*.gd" .

# Inline data
grep -rn "^[[:space:]]*const.*\[" --include="*.gd" .
  1. Create Git Baseline
# Save current branch
current_branch=$(git branch --show-current)

# Create baseline tag
git tag baseline-$(date +%Y%m%d-%H%M%S)

# Initial commit if there are uncommitted changes
git add .
git commit -m "Baseline: Pre-refactoring state (on $current_branch)"
  1. Generate Refactoring Manifest

Create a priority-ordered list:

PriorityAnti-PatternFileLinesOperation
1Inline dataenemy_data.gd45-78Extract to .tres
2Code-created Timerlaser_beam.gd38-45Extract to .tscn
3Tight couplingbase_station.gd92Signal decoupling
4Monolithic scriptplayer_movement.gd287 linesSplit script

Phase 1 Output:

  • ✓ Baseline git commit/tag created
  • ✓ Anti-patterns detected and prioritized
  • ✓ Manifest table generated
  • ✓ Ready for automatic refactoring

Phase 2: Automatic Refactoring (Five Operations)

Process anti-patterns in priority order: Data → Scenes → Signals → Scripts → Conflicts

CRITICAL - After Each Operation:

  1. Git commit the changes
  2. Run automatic validation test
  3. If test fails: Auto-revert and report error
  4. If test passes: Continue automatically to next operation
  5. No user prompt unless test fails or user confirmation needed

Automatic Testing Procedure:

# Quick validation test (runs after each git commit)
echo "Running validation test..."
godot --headless --quit-after 5 project.godot 2>&1 | tee test_output.log

# Check for errors
if grep -q "ERROR\|SCRIPT ERROR\|Parse Error" test_output.log; then
    echo "⚠️  Tests failed - reverting operation"
    git reset --hard HEAD~1
    echo "❌ Operation reverted. Error details:"
    grep "ERROR\|SCRIPT ERROR\|Parse Error" test_output.log
    # STOP and report to user
else
    echo "✓ Tests passed - continuing"
    rm test_output.log
    # CONTINUE to next operation automatically
fi

Note: If test fails, STOP workflow and report to user. Otherwise, continue automatically through all operations.

Operation A: Extract Code-Created Objects to Modular Components

Target: Any

.new()
calls that create nodes

Enhanced Process:

  1. Detect and Analyze

    • Find
      .new()
      calls for node types
    • Extract 30 lines of context (properties, methods, signals)
    • Analyze variable names, properties, methods
    • Consult
      node-selection-guide.md
      decision trees
    • Calculate confidence score for node type
    • Select optimal node from
      godot-node-reference.md
  2. Check Component Library

    • Does
      components/{category}/
      exist? (e.g.,
      components/timers/
      )
    • If YES: Reuse base component, skip to Step 4
    • If NO: Generate full component structure (Steps 2-3)
  3. Generate Component (First Time Only)

    • Create
      {type}_config.gd
      (Resource class with @export properties)
    • Create
      configurable_{type}.gd
      (Script that extends node, applies config)
    • Create
      configurable_{type}.tscn
      (Base scene with script)
    • Creates modular, reusable foundation
  4. Generate Preset Resource

    • Extract properties from analyzed code
    • Create
      presets/{preset_name}.tres
      (specific configuration)
    • Each detected instance gets unique preset
    • Presets reference the base component
  5. Update Parent Scene

    • Add ext_resource entries for base scene and preset
    • Instance base component with preset resource
    • Same scene reused, different presets = ZERO duplication
  6. Update Parent Script

    • Add @onready reference to component instance
    • Keep signal connections
    • Remove .new(), add_child(), static property assignments
    • Configuration now comes from preset resource
  7. Git Commit & Validate

    • Commit all component files and parent changes
    • Run validation test
    • Ensure behavior unchanged

Example Transformation:

Before (Code-Created):

func _ready():
    _damage_timer = Timer.new()
    _damage_timer.wait_time = 0.5
    _damage_timer.one_shot = false
    add_child(_damage_timer)
    _damage_timer.timeout.connect(_on_damage)

    _cooldown_timer = Timer.new()
    _cooldown_timer.wait_time = 2.0
    _cooldown_timer.one_shot = true
    add_child(_cooldown_timer)
    _cooldown_timer.timeout.connect(_on_cooldown)

After (First Timer - Full Component Created):

Files created:
✓ components/timers/timer_config.gd (resource class)
✓ components/timers/configurable_timer.gd (reusable script)
✓ components/timers/configurable_timer.tscn (reusable base scene)
✓ components/timers/presets/damage_timer.tres (configuration preset)

parent.gd:
@onready var _damage_timer: ConfigurableTimer = $DamageTimer

func _ready():
    _damage_timer.timeout.connect(_on_damage)

After (Second Timer - Reuses Base):

Files created:
✓ components/timers/presets/cooldown_timer.tres (NEW preset only!)

parent.gd:
@onready var _damage_timer: ConfigurableTimer = $DamageTimer
@onready var _cooldown_timer: ConfigurableTimer = $CooldownTimer

func _ready():
    _damage_timer.timeout.connect(_on_damage)
    _cooldown_timer.timeout.connect(_on_cooldown)

Key Benefits:

  • ✅ Intelligent node selection (no arbitrary choices)
  • ✅ Modular components (reusable across project)
  • ✅ Zero duplication (same base, different presets)
  • ✅ Inspector-configurable (edit presets in editor)
  • ✅ Automatic library building (grows organically)
  • ✅ Signal connections preserved
  • ✅ Behavior unchanged (Iron Law maintained)

Success Criteria:

  • Component structure created (if first of type)
  • Preset resource created with extracted values
  • Parent scene instances component with preset
  • Parent script has @onready reference
  • Signal connections work
  • Old code removed
  • Behavior unchanged

Operation B: Split Monolithic Scripts

Target: Scripts >150 lines with multiple responsibilities

Detection:

find . -name "*.gd" -exec wc -l {} + | awk '$1 > 150'

For each detected script:

  1. Analyze script structure

    • Identify logical sections (look for comment headers, function groups)
    • Find responsibilities (input, physics, abilities, UI, etc.)
    • Determine dependencies between sections
  2. Plan split

    • Main script keeps core responsibility
    • Extract secondary responsibilities to components
    • Define signal interface between components
  3. Create component scripts

    Example: Split

    player_movement.gd
    (287 lines)

    Extract to

    player_abilities.gd
    :

    extends Node
    class_name PlayerAbilities
    
    signal ability_used(ability_name: String)
    signal cooldown_started(duration: float)
    
    # Ability-related functions moved here
    
  4. Update main script

    @onready var abilities: PlayerAbilities = $Abilities
    
    func _ready():
        abilities.ability_used.connect(_on_ability_used)
    
  5. Implement signal communication

    • Replace direct function calls with signals
    • Connect signals in _ready()
    • Remove tight coupling
  6. Git commit

    git add player_movement.gd player_abilities.gd
    git commit -m "Refactor: Split abilities from player_movement.gd"
    
  7. Run automatic test (see Phase 2 header for test procedure)

Success criteria:

  • Main script <150 lines
  • Component scripts focused (80-120 lines optimal)
  • Signal-based communication
  • No direct dependencies
  • Behavior unchanged

Operation C: Implement Signal-Based Decoupling

Target: Direct coupling via get_node(), has_method(), direct calls

Detection:

grep -rn "get_node\|has_method" --include="*.gd" .

For each detected coupling:

  1. Identify the relationship

    • What is being accessed?
    • What information is being exchanged?
    • Is this event-based or state query?
  2. Create/use Events autoload

    If not exists, create

    events.gd
    :

    extends Node
    # Global event bus
    
    signal player_entered_safe_zone(zone: Node2D)
    signal enemy_spawned(enemy: Node2D)
    signal score_changed(new_score: int)
    

    Add to project settings: Project → Project Settings → Autoload

  3. Replace direct coupling with signals

    Before:

    func _on_body_entered(body):
        if body.has_method("set_beam_enabled"):
            body.set_beam_enabled(false)
    

    After (emitter):

    func _on_body_entered(body):
        if body.is_in_group("player"):
            Events.player_entered_safe_zone.emit(self)
    

    After (receiver):

    func _ready():
        Events.player_entered_safe_zone.connect(_on_safe_zone)
    
    func _on_safe_zone(zone):
        set_beam_enabled(false)
    
  4. Remove coupling code

    • Delete get_node() calls
    • Delete has_method() checks
    • Delete direct property access
  5. Git commit

    git add events.gd base_station.gd player_movement.gd
    git commit -m "Refactor: Decouple base_station from player via signals"
    
  6. Run automatic test (see Phase 2 header for test procedure)

Success criteria:

  • No get_node() for behavior access
  • No has_method() checks
  • Events.gd exists and is used
  • Signal connections established
  • Behavior unchanged

Operation D: Extract Data to .tres Resources

Target:

const
declarations with game data

Detection:

grep -rn "^[[:space:]]*const.*\[" --include="*.gd" .

For each detected data constant:

  1. Analyze data structure

    const ENEMY_TYPES = [
        {"type": "basic", "health": 100, "speed": 200},
        {"type": "fast", "health": 50, "speed": 400}
    ]
    
  2. Create Resource class

    Create

    enemy_type_data.gd
    :

    extends Resource
    class_name EnemyTypeData
    
    @export var type_name: String
    @export var health: int
    @export var speed: float
    
  3. Generate .tres files

    Create

    enemy_types/basic.tres
    :

    [gd_resource type="EnemyTypeData" load_steps=2 format=3]
    
    [ext_resource type="Script" path="res://enemy_type_data.gd" id="1"]
    
    [resource]
    script = ExtResource("1")
    type_name = "basic"
    health = 100
    speed = 200.0
    
  4. Update script to use resources

    @export var enemy_types: Array[EnemyTypeData]
    
    # In scene, assign resources via inspector
    
  5. Remove const declaration

  6. Git commit

    git add enemy_type_data.gd enemy_types/*.tres enemy_spawner.gd
    git commit -m "Refactor: Extract enemy data to .tres resources"
    
  7. Run automatic test (see Phase 2 header for test procedure)

Success criteria:

  • Resource class created
  • .tres files generated with correct data
  • Script updated to use resources
  • Const declaration removed
  • Behavior unchanged

Operation E: Clean Conflicting/Ineffective Operations

Target: Code that runs without errors but has no effect or conflicts with other code

IMPORTANT: This operation runs after Operations A-D are complete, as refactoring may introduce or remove conflicts.

Detection:

# Run comprehensive conflict detection
bash << 'EOF'
echo "=== Detecting Conflicting Operations ==="

# Self-assignments
echo "Self-assignments:"
grep -rn "position\s*=\s*position\|scale\s*=\s*scale\|rotation\s*=\s*rotation" --include="*.gd" .

# Redundant defaults
echo "Redundant defaults:"
grep -rn "modulate\s*=\s*Color\.WHITE\|scale\s*=\s*Vector2\.ONE" --include="*.gd" .

# Duplicate property assignments (common properties)
echo "Checking for duplicate assignments..."
for prop in "scale" "position" "rotation" "modulate" "visible"; do
    grep -rn "\.$prop\s*=" --include="*.gd" . | \
    awk -F: -v prop="$prop" '{
        file=$1; line=$2;
        if (file==prev_file && line-prev_line<20) {
            print file":"prev_line" and "line" - Duplicate "prop
        }
        prev_file=file; prev_line=line
    }'
done

# Conflicting tweens
echo "Conflicting tweens:"
grep -n "tween_property" --include="*.gd" -r . | \
awk -F: '{
    file=$1; line=$2;
    if (match($0, /tween_property.*"([^"]+)"/, arr)) {
        prop=arr[1];
        key=file":"prop;
        if (key in seen && line-seen[key]<15) {
            print file":"seen[key]" and "line" - Conflicting tweens on "prop
        }
        seen[key]=line
    }
}'

# Code after queue_free
echo "Code after queue_free:"
grep -A2 "queue_free()" --include="*.gd" . | grep -v "^--$"

EOF

For each detected conflict:

  1. Auto-fix (no user input):

    • Self-assignments: Remove entirely
    • Code after
      queue_free()
      : Move code before queue_free
    • Obvious redundant defaults: Remove
  2. User confirmation (ask user):

    • Duplicate assignments: Which value to keep?
    • Conflicting tweens: Which to keep or chain?
    • Multiple process calls: Final intended state?
  3. Example fixes:

    Self-assignment:

    # Before
    position = position
    
    # After (remove line)
    

    Duplicate assignment:

    # Before
    sprite.scale = Vector2(2, 2)  # Line 45
    sprite.scale = Vector2(1, 1)  # Line 52
    
    # After (keep last)
    sprite.scale = Vector2(1, 1)  # Line 52
    

    Conflicting tweens (user chose "chain"):

    # Before
    var tween1 = create_tween()
    tween1.tween_property(self, "scale", Vector2(2,2), 1.0)
    var tween2 = create_tween()
    tween2.tween_property(self, "scale", Vector2(0.5,0.5), 1.0)
    
    # After
    var tween = create_tween()
    tween.tween_property(self, "scale", Vector2(2,2), 1.0)
    tween.tween_property(self, "scale", Vector2(0.5,0.5), 1.0)
    
  4. Git commit

    git add <modified files>
    git commit -m "Refactor: Clean conflicting/ineffective operations
    
    - Removed self-assignments
    - Fixed duplicate property assignments
    - Resolved conflicting tweens
    - Cleaned up redundant operations
    
    No functional changes - code cleanup only"
    
  5. Run automatic test (see Phase 2 header for test procedure)

Success criteria:

  • No self-assignments remain
  • No obvious duplicate assignments
  • Conflicting tweens resolved
  • Code after queue_free() moved
  • Behavior unchanged

Note: See

conflicting-operations-detection.md
for comprehensive detection patterns and
refactoring-operations.md
Operation E for detailed procedures.


Phase 3: Git Commits (Automatic)

After each operation, commit with clear message:

# Template
git add <files>
git commit -m "Refactor: <Operation> in <file> - <specific change>"

# Examples
git commit -m "Refactor: Extract Timer to scene in laser_beam.gd"
git commit -m "Refactor: Split abilities from player_movement.gd (287→142 lines)"
git commit -m "Refactor: Decouple base_station from player via signals"
git commit -m "Refactor: Extract enemy data to .tres resources"
git commit -m "Refactor: Clean conflicting/ineffective operations"

After all operations:

git tag refactor-complete-$(date +%Y%m%d)

Commit history should show:

  • Baseline commit
  • One commit per refactoring operation (A, B, C, D, E)
  • Clear, descriptive messages
  • Easy to review
  • Easy to rollback individual changes

Push on Demand:

After all operations complete, ask user:

=== Refactoring Complete ===

All operations completed successfully!
5 operations performed, X commits created on current branch.

Would you like to push to remote?
1. Yes, push now
2. No, I'll push manually later
3. Show me the commit log first

Choice [1-3]:

If user chooses 1 (push now):

# Push to current branch's remote
git push origin $(git branch --show-current)

If user chooses 3 (show log first):

git log --oneline --graph baseline-*..HEAD
# Then ask again: Push now? [y/n]

If user says "push" or "push et" at ANY time during the workflow:

# Immediately push current branch
git push origin $(git branch --show-current)
echo "✓ Pushed to remote"

Phase 4: Final Verification (Minimal, Automatic)

Purpose: Ensure no functional or visual regressions.

Steps:

  1. Open project in Godot

    godot --editor path/to/project.godot
    
  2. Check for errors

    • No red errors in console
    • No yellow warnings about missing nodes
    • All scenes load successfully
  3. Visual verification

    • Run main scene
    • Quick visual check (30 seconds)
    • Compare against expected behavior
  4. Play test checklist (from

    verification-checklist.md
    ):

    • Player movement works
    • Abilities trigger correctly
    • Enemies spawn and behave normally
    • UI updates properly
    • No crashes or errors
  5. Performance baseline (optional):

    # Compare FPS before/after
    # Should be identical ±2 FPS
    

If verification fails:

# Rollback procedure
git reset --hard baseline-YYYYMMDD-HHMMSS
git tag refactor-failed-$(date +%Y%m%d-%H%M%S)

# Report what broke
# Debug with systematic-debugging skill

If verification succeeds:

Report summary:

✓ Refactoring complete
✓ 8 operations performed
✓ 287 lines reduced to 142 across 3 files
✓ 4 .tscn scenes created
✓ 2 .tres resources created
✓ Signal-based architecture established
✓ No functional changes
✓ All tests passing

Supporting Files

This skill uses modular reference files:

  • anti-patterns-detection.md: All grep/find patterns for detection
  • refactoring-operations.md: Detailed step-by-step procedures
  • godot-best-practices.md: Clean patterns reference
  • tscn-generation-guide.md: .tscn file format templates
  • verification-checklist.md: Testing procedures

Read these files for detailed implementation guidance.


Red Flags - STOP

These thoughts mean you're rationalizing away discipline:

RationalizationRealityFix
"While I'm here, let me add this feature"Feature creep breaks Iron LawRefactor only, no features
"This behavior is wrong, I'll fix it now"Bug fixes are separate workNote bug, refactor only
"I don't need to test this change"Untested = brokenAlways verify
"I'll commit after a few more changes"Loses granularityCommit per operation
"This .tscn format looks close enough"Invalid scenes crashUse exact format
"The user won't notice this visual change"Iron Law has no exceptionsRevert and fix
"Signals are overkill for this"Coupling creeps backUse signals anyway
"I'll manually test later"Later never comesTest now
"This script is fine at 160 lines"Arbitrary exceptions growSplit at 150
"I understand the pattern, no need to read"Assumptions create bugsRead the guide

Quick Reference: Anti-Pattern → Clean Pattern

Anti-PatternClean PatternTool
Timer.new()
in code
.tscn scene with TimerOperation A
get_node("../Player")
Signal via EventsOperation C
if has_method("take_damage"):
Signal listenerOperation C
287-line scriptSplit to 3 focused scriptsOperation B
const WEAPONS = [...]
.tres resourcesOperation D
add_child(sprite)
Scene compositionOperation A
Direct method callsSignal emit/connectOperation C
Deep inheritanceComponent compositionOperations A+B

File Operation Flow

1. Data Extraction
   .gd with const → Resource class .gd + .tres files

2. Scene Extraction
   .gd with .new() → .gd with @onready + new .tscn

3. Signal Decoupling
   .gd with get_node() → events.gd + updated .gd files

4. Script Splitting
   Large .gd → Multiple focused .gd files with signals

Godot Naming Conventions

Scenes (.tscn):

  • PascalCase for node names:
    DamageTimer
    ,
    AbilitySystem
  • snake_case for file names:
    damage_timer.tscn
    ,
    ability_system.tscn

Scripts (.gd):

  • snake_case for files:
    player_movement.gd
    ,
    enemy_spawner.gd
  • PascalCase for class_name:
    class_name PlayerMovement

Resources (.tres):

  • snake_case for files:
    enemy_types/basic.tres
  • PascalCase for Resource class:
    class_name EnemyTypeData

Signals:

  • snake_case:
    signal ability_used
    ,
    signal player_entered_safe_zone
  • Past tense for events:
    signal enemy_spawned
    (not
    enemy_spawn
    )

@onready variables:

  • snake_case with type hint:
    @onready var _damage_timer: Timer = $DamageTimer
  • Private with underscore:
    _damage_timer
    ,
    _ability_system

Common Mistakes

MistakeConsequenceFix
Invalid .tscn formatScene won't load in GodotUse exact template format
Missing node type in .tscnGodot can't parse sceneAlways specify
type="Timer"
Forgetting @onreadyNull reference at runtimeAdd @onready for all node refs
Wrong signal signatureConnection fails silentlyMatch parameter types exactly
Removing necessary .new()Some objects SHOULD be createdOnly refactor scene nodes
Not testing after each opCompounding errorsTest after every commit
Coupling through globalsDifferent coupling, same problemUse Events for decoupling only
Over-splitting scriptsToo many tiny files80-120 lines is optimal
Async signals without checksRace conditionsVerify node existence
Changing behavior "slightly"Iron Law violationRevert immediately

Signal Architecture Patterns

Event Bus (Events.gd):

# Use for global events
signal player_died
signal level_completed(level_num: int)
signal score_changed(new_score: int)

Direct Node Signals:

# Use for parent-child communication
signal health_depleted
signal ability_activated(ability_name: String)

When to use which:

  • Events.gd: Cross-tree communication, global state changes
  • Node signals: Parent-child, local behavior

Real-World Impact

Expected improvements after refactoring:

Code Quality:

  • 30-50% reduction in total lines of code
  • Scripts average 80-120 lines (down from 150-300)
  • Zero direct node dependencies
  • Signal-based architecture throughout

Maintainability:

  • Changes isolated to single files
  • Components reusable across scenes
  • Testing individual components possible
  • New developers onboard faster

Performance:

  • Identical to baseline (±2 FPS)
  • Scene loading slightly faster
  • Memory usage unchanged

Execution Strategy

This skill runs fully automatically:

  1. User invokes skill on Godot project
  2. Phase 1: Scan and report findings
  3. User approves refactoring
  4. Phases 2-3: Execute all operations with commits on current branch
  5. Phase 4: Verify and report results

User input required:

  • Initial invocation
  • Approval after Phase 1 analysis
  • Final verification check (30 seconds)

Everything else is automatic:

  • Anti-pattern detection
  • .tscn file generation
  • Script modifications
  • Git commits on current branch
  • Testing

Success Criteria

Refactoring is complete when:

  • ✓ Zero
    .new()
    calls for scene nodes
  • ✓ All scripts <150 lines
  • ✓ Signal-based architecture established
  • ✓ No
    get_node()
    for behavior access
  • ✓ Data in .tres resources
  • ✓ Clean git history with descriptive commits on current branch
  • ✓ All scenes load without errors
  • ✓ Behavior identical to baseline
  • ✓ Visual appearance unchanged
  • ✓ Performance within ±2 FPS

Post-Refactoring

After successful refactoring:

  1. Continue development

    • Changes are already on current branch
    • Push to remote if not already pushed
    • Continue normal development workflow
  2. Document architecture

    • Create architecture diagram
    • Document signal flows
    • List component responsibilities
  3. Establish standards

    • Use this clean architecture as template
    • Apply patterns to new code
    • Prevent anti-pattern regression
  4. Consider further improvements (separate tasks):

    • Add unit tests (use TDD skill)
    • Optimize performance (profile first)
    • Add new features (use brainstorming skill)

Remember: Refactoring changes HOW code works internally, not WHAT it does externally. The Iron Law is absolute.