xiaohongshu
xiaohongshu
godot-refactor
Use when Godot project has code-created objects, tight coupling via direct references, monolithic scripts over 150 lines, or needs scene-first architecture with signals and composition. Orchestrates all 5 code quality mini-skills: extract-to-scenes, split-scripts, add-signals, extract-resources, ...
Full skill instructions
This orchestrator runs 5 code quality mini-skills in sequence. For individual operations, invoke mini-skills directly.
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.
When this skill is invoked, IMMEDIATELY execute the following sequence:
# 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:
If IS a Godot project:
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
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
CRITICAL: Do NOT stop after loading the skill. Do NOT ask "What would you like me to do?" Start with step 1 immediately.
Use this skill when you detect ANY of these symptoms:
Code-Created Objects:
.new() calls in _ready(), _process(), or other lifecycle methodsadd_child() with programmatically created nodesMonolithic Scripts:
Tight Coupling:
get_node() chains to access other nodeshas_method() checks before callingInline Data:
const arrays with game dataDeep Inheritance:
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
Purpose: Detect all anti-patterns and create safety baseline.
Steps:
# Find all Godot script files
find . -name "*.gd" -type f
# Find all scene files
find . -name "*.tscn" -type f
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" .
# 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)"
Create a priority-ordered list:
| Priority | Anti-Pattern | File | Lines | Operation |
|---|---|---|---|---|
| 1 | Inline data | enemy_data.gd | 45-78 | Extract to .tres |
| 2 | Code-created Timer | laser_beam.gd | 38-45 | Extract to .tscn |
| 3 | Tight coupling | base_station.gd | 92 | Signal decoupling |
| 4 | Monolithic script | player_movement.gd | 287 lines | Split script |
Phase 1 Output:
Process anti-patterns in priority order: Data → Scenes → Signals → Scripts → Conflicts
CRITICAL - After Each Operation:
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.
Target: Any .new() calls that create nodes
Enhanced Process:
Detect and Analyze
.new() calls for node typesnode-selection-guide.md decision treesgodot-node-reference.mdCheck Component Library
components/{category}/ exist? (e.g., components/timers/)Generate Component (First Time Only)
{type}_config.gd (Resource class with @export properties)configurable_{type}.gd (Script that extends node, applies config)configurable_{type}.tscn (Base scene with script)Generate Preset Resource
presets/{preset_name}.tres (specific configuration)Update Parent Scene
Update Parent Script
Git Commit & Validate
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:
Success Criteria:
Target: Scripts >150 lines with multiple responsibilities
Detection:
find . -name "*.gd" -exec wc -l {} + | awk '$1 > 150'
For each detected script:
Analyze script structure
Plan split
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
Update main script
@onready var abilities: PlayerAbilities = $Abilities
func _ready():
abilities.ability_used.connect(_on_ability_used)
Implement signal communication
Git commit
git add player_movement.gd player_abilities.gd
git commit -m "Refactor: Split abilities from player_movement.gd"
Run automatic test (see Phase 2 header for test procedure)
Success criteria:
Target: Direct coupling via get_node(), has_method(), direct calls
Detection:
grep -rn "get_node\|has_method" --include="*.gd" .
For each detected coupling:
Identify the relationship
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
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)
Remove coupling code
Git commit
git add events.gd base_station.gd player_movement.gd
git commit -m "Refactor: Decouple base_station from player via signals"
Run automatic test (see Phase 2 header for test procedure)
Success criteria:
Target: const declarations with game data
Detection:
grep -rn "^[[:space:]]*const.*\[" --include="*.gd" .
For each detected data constant:
Analyze data structure
const ENEMY_TYPES = [
{"type": "basic", "health": 100, "speed": 200},
{"type": "fast", "health": 50, "speed": 400}
]
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
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
Update script to use resources
@export var enemy_types: Array[EnemyTypeData]
# In scene, assign resources via inspector
Remove const declaration
Git commit
git add enemy_type_data.gd enemy_types/*.tres enemy_spawner.gd
git commit -m "Refactor: Extract enemy data to .tres resources"
Run automatic test (see Phase 2 header for test procedure)
Success criteria:
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:
Auto-fix (no user input):
queue_free(): Move code before queue_freeUser confirmation (ask user):
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)
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"
Run automatic test (see Phase 2 header for test procedure)
Success criteria:
Note: See conflicting-operations-detection.md for comprehensive detection patterns and refactoring-operations.md Operation E for detailed procedures.
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:
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"
Purpose: Ensure no functional or visual regressions.
Steps:
Open project in Godot
godot --editor path/to/project.godot
Check for errors
Visual verification
Play test checklist (from verification-checklist.md):
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
This skill uses modular reference files:
Read these files for detailed implementation guidance.
These thoughts mean you're rationalizing away discipline:
| Rationalization | Reality | Fix |
|---|---|---|
| "While I'm here, let me add this feature" | Feature creep breaks Iron Law | Refactor only, no features |
| "This behavior is wrong, I'll fix it now" | Bug fixes are separate work | Note bug, refactor only |
| "I don't need to test this change" | Untested = broken | Always verify |
| "I'll commit after a few more changes" | Loses granularity | Commit per operation |
| "This .tscn format looks close enough" | Invalid scenes crash | Use exact format |
| "The user won't notice this visual change" | Iron Law has no exceptions | Revert and fix |
| "Signals are overkill for this" | Coupling creeps back | Use signals anyway |
| "I'll manually test later" | Later never comes | Test now |
| "This script is fine at 160 lines" | Arbitrary exceptions grow | Split at 150 |
| "I understand the pattern, no need to read" | Assumptions create bugs | Read the guide |
| Anti-Pattern | Clean Pattern | Tool |
|---|---|---|
Timer.new() in code | .tscn scene with Timer | Operation A |
get_node("../Player") | Signal via Events | Operation C |
if has_method("take_damage"): | Signal listener | Operation C |
| 287-line script | Split to 3 focused scripts | Operation B |
const WEAPONS = [...] | .tres resources | Operation D |
add_child(sprite) | Scene composition | Operation A |
| Direct method calls | Signal emit/connect | Operation C |
| Deep inheritance | Component composition | Operations A+B |
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
Scenes (.tscn):
DamageTimer, AbilitySystemdamage_timer.tscn, ability_system.tscnScripts (.gd):
player_movement.gd, enemy_spawner.gdclass_name PlayerMovementResources (.tres):
enemy_types/basic.tresclass_name EnemyTypeDataSignals:
signal ability_used, signal player_entered_safe_zonesignal enemy_spawned (not enemy_spawn)@onready variables:
@onready var _damage_timer: Timer = $DamageTimer_damage_timer, _ability_system| Mistake | Consequence | Fix |
|---|---|---|
| Invalid .tscn format | Scene won't load in Godot | Use exact template format |
| Missing node type in .tscn | Godot can't parse scene | Always specify type="Timer" |
| Forgetting @onready | Null reference at runtime | Add @onready for all node refs |
| Wrong signal signature | Connection fails silently | Match parameter types exactly |
| Removing necessary .new() | Some objects SHOULD be created | Only refactor scene nodes |
| Not testing after each op | Compounding errors | Test after every commit |
| Coupling through globals | Different coupling, same problem | Use Events for decoupling only |
| Over-splitting scripts | Too many tiny files | 80-120 lines is optimal |
| Async signals without checks | Race conditions | Verify node existence |
| Changing behavior "slightly" | Iron Law violation | Revert immediately |
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:
Expected improvements after refactoring:
Code Quality:
Maintainability:
Performance:
This skill runs fully automatically:
User input required:
Everything else is automatic:
Refactoring is complete when:
.new() calls for scene nodesget_node() for behavior accessAfter successful refactoring:
Continue development
Document architecture
Establish standards
Consider further improvements (separate tasks):
Remember: Refactoring changes HOW code works internally, not WHAT it does externally. The Iron Law is absolute.
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience