Claude-skill-registry godot-fix-positions
git clone https://github.com/majiayu000/claude-skill-registry
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-fix-positions" ~/.claude/skills/majiayu000-claude-skill-registry-godot-fix-positions && rm -rf "$T"
skills/data/godot-fix-positions/SKILL.mdGodot Fix Positions Orchestrator
This orchestrator runs 3 position sync mini-skills in sequence. For individual operations, invoke mini-skills directly.
Core Principle: What You See Is What You Get (WYSIWYG)
Iron Law: Editor preview must match runtime behavior. No surprises.
This skill automatically detects and resolves position conflicts between editor-defined positions (.tscn files) and code-defined positions (.gd files). It handles static conflicts, camera-following backgrounds, parallax layers, and player-relative positioning.
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: Detection & Analysis (AUTOMATIC)
Do NOT ask "What would you like me to do?" - Start analyzing immediately.
Execute these commands in parallel:
# Detect static position conflicts find . -name "*.gd" -exec grep -l "position\s*=" {} \; | head -20 # Find camera-following patterns grep -rn "position\s*=.*camera\|position\s*=.*player" --include="*.gd" . | head -20 # Find parallax backgrounds find . -name "*parallax*.tscn" -o -name "*background*.tscn" | head -10 # Count potential conflicts find . -name "*.gd" -exec grep -c "^\s*position\s*=" {} + | awk '{s+=$1} END {print s}'
3. Present Findings (30 seconds)
Show the user:
=== Editor Position Sync Analysis === Project: [project name from project.godot] Conflicts detected: - Static position assignments: X - Camera-following elements: X - Parallax backgrounds: X - Player-relative positioning: X Total: X position conflicts found Sync includes: ✓ Detect editor vs code position conflicts ✓ Smart classification (intentional vs conflict) ✓ Camera-aware positioning ✓ Multiple sync strategies ✓ Git commit per operation ✓ Auto-rollback on test failure Would you like me to: 1. Proceed with automatic sync (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:
Static Position Conflicts:
inposition = Vector2(x, y)
or_ready()_init()- Editor shows one position, runtime shows different position
- Nodes appear in wrong locations when game starts
- Visual debugging reveals position mismatches
Camera-Following Elements:
- Backgrounds that follow camera position
- UI elements that track player
- Parallax layers with camera sync
patternsposition = camera.position
Player-Relative Positioning:
- Nodes positioned relative to player
patternsposition = player.position + offset- Elements that track player movement
- Camera-relative UI elements
Editor Preview Mismatch:
- "It looks right in the editor but wrong at runtime"
- "The background jumps when the game starts"
- "My UI elements are in the wrong place"
- "Camera-following nodes don't preview correctly"
Decision Flowchart
User mentions position issues ↓ Is it editor vs runtime mismatch? ↓ YES ↓ NO Use this skill Different issue ↓ Run Phase 1: Detection ↓ Conflicts found? ↓ YES ↓ NO Run Phases 2-3 Document clean state
The Three Phases
Phase 1: Detection & Analysis (Automatic)
Purpose: Detect position conflicts and classify them intelligently.
Steps:
- Scan Project Files
# Find all Godot script files find . -name "*.gd" -type f # Find all scene files find . -name "*.tscn" -type f
- Detect Position Assignments
Scan for position-setting patterns:
# Static position assignments grep -rn "position\s*=\s*Vector2(" --include="*.gd" . # Camera-following patterns grep -rn "position\s*=.*camera" --include="*.gd" . # Player-following patterns grep -rn "position\s*=.*player" --include="*.gd" . # Parallax patterns grep -rn "ParallaxBackground\|ParallaxLayer" --include="*.gd" .
- Parse .tscn Files for Positions
Extract position properties from scenes:
# Find position declarations in .tscn files grep -rn "^position\s*=\s*Vector2(" --include="*.tscn" .
- Intelligent Classification
For each detected position assignment, classify as:
- CONFLICT: Static position in
differs from .tscn_ready() - INTENTIONAL_DYNAMIC: Camera/player following (skip)
- INTENTIONAL_ANIMATION: Tweens/animations (skip)
- PROCESS_ASSIGNMENT: Every-frame in
(critical warning)_process()
Classification Logic:
def classify_position_assignment(context): # Context = 30 lines around assignment # SKIP: Animation/tween if "tween" in context or "create_tween" in context: return "INTENTIONAL_ANIMATION" # SKIP: Camera following if "camera.position" in context or "get_viewport().get_camera" in context: return "INTENTIONAL_DYNAMIC" # SKIP: Player following if "player.position" in context or "target.position" in context: return "INTENTIONAL_DYNAMIC" # CRITICAL: Every frame assignment if "_process(" in context: return "PROCESS_ASSIGNMENT" # CONFLICT: Static assignment in _ready if "_ready(" in context and "Vector2(" in line: return "CONFLICT" return "UNKNOWN"
- Create Conflict Manifest
Generate a priority-ordered list:
| File | Node | Editor Position | Code Position | Classification | Sync Strategy |
|---|---|---|---|---|---|
| background.gd | Background | (0, 0) | camera.position | DYNAMIC | Document intent |
| enemy.gd | Enemy | (500, 300) | (100, 150) | CONFLICT | Code → Editor |
| ui_label.gd | Label | (10, 10) | (50, 50) | CONFLICT | Editor → Code |
Phase 1 Output:
- ✓ All position assignments detected
- ✓ Conflicts classified intelligently
- ✓ Manifest table generated
- ✓ Ready for synchronization
Phase 2: Position Synchronization (Three Strategies)
Process conflicts in priority order: Critical → Conflicts → Dynamic
CRITICAL - After Each Operation:
- Git commit the changes
- Run automatic validation test
- If test fails: Auto-revert and report error
- If test passes: Continue automatically to next conflict
- 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
Strategy A: Code → Editor Sync
Target: Static position conflicts where code position should be editor position
When to use:
- Code position is intentional final position
- Editor preview should match runtime
- Position set once in
and never changes_ready()
Process:
- Detect Conflict
# Example: enemy.gd sets position in _ready() grep -A5 "_ready" enemy.gd
Example code:
# enemy.gd func _ready(): position = Vector2(100, 150) # Conflict with .tscn
Example .tscn:
[node name="Enemy" type="CharacterBody2D"] position = Vector2(500, 300) # Different from code
- Update .tscn File
Parse and update:
# Read .tscn file with open("enemy.tscn") as f: content = f.read() # Find and replace position line content = re.sub( r'position = Vector2\([^)]+\)', 'position = Vector2(100, 150)', content ) # Write back with open("enemy.tscn", "w") as f: f.write(content)
- Update .gd File
Remove static assignment, add comment:
# enemy.gd func _ready(): # Position moved to .tscn for editor visibility # Was: position = Vector2(100, 150) pass
- Git Commit
git add enemy.tscn enemy.gd git commit -m "Sync: Move enemy position from code to editor (.tscn) - Updated enemy.tscn position to Vector2(100, 150) - Removed static position assignment from enemy.gd - Editor now matches runtime position"
- Run automatic test (see Phase 2 header for test procedure)
Success criteria:
- .tscn position matches intended runtime position
- Code assignment removed
- Comment documents change
- Behavior unchanged
Strategy B: Editor → Code Sync
Target: Position should be set in code, remove .tscn position
When to use:
- Position is calculated/dynamic
- .tscn position is arbitrary/wrong
- Code position is source of truth
Process:
- Keep Code Assignment
Code already correct:
func _ready(): position = Vector2(100, 150) # Correct position
- Reset .tscn to Default
Update .tscn to neutral position:
[node name="Enemy" type="CharacterBody2D"] # position removed (defaults to Vector2(0, 0))
Or explicitly set to origin:
position = Vector2(0, 0)
- Add Documentation
Add comment explaining:
func _ready(): # Position set in code (not in .tscn) # Editor shows (0,0), runtime shows calculated position position = Vector2(100, 150)
- Git Commit
git commit -m "Sync: Keep enemy position in code, reset editor - Removed position from enemy.tscn (defaults to origin) - Kept code position assignment - Runtime position calculated in _ready()"
- Run automatic test
Strategy C: Camera-Aware Positioning (SPECIAL)
Target: Backgrounds, parallax layers, camera-following elements
When to use:
- Background follows camera
- Parallax layers
- Player-relative UI elements
- Dynamic camera positioning
Special Case - User's Background Issue:
Problem: Background positioned at (0, 0) in editor, but follows camera at runtime, causing confusion during level design.
Solution:
- Detect Camera-Following Pattern
# background.gd func _process(delta): position = camera.position # Follows camera
- Calculate Expected Editor Position
Find typical camera start position:
# Search for camera or player spawn position grep -rn "camera.*position\|player.*position" --include="*.tscn" .
Example: Camera starts at (512, 300)
- Update .tscn to Camera Start Position
[node name="Background" type="Sprite2D"] position = Vector2(512, 300) # Camera start position
- Document Camera-Relative Behavior
# background.gd func _process(delta): # EDITOR NOTE: Position in .tscn shows camera start position # for accurate level design preview. At runtime, follows camera. position = camera.position
- Create Editor Preview Tool (Optional)
Generate editor plugin to show camera bounds:
# addons/camera_preview/camera_preview.gd @tool extends EditorPlugin func _enter_tree(): # Draw camera bounds in editor pass
Result:
- Editor shows realistic preview
- Background appears at expected camera position
- Level design is accurate
- Runtime behavior unchanged
- Git Commit
git commit -m "Sync: Camera-aware background positioning - Updated background.tscn to camera start position - Added documentation for camera-following behavior - Editor now shows accurate runtime preview"
- Run automatic test
Success criteria:
- Editor preview shows realistic camera view
- Runtime behavior unchanged
- Level design is accurate
- Documentation explains dynamic behavior
Phase 3: Verification & Reporting
Purpose: Ensure synchronization succeeded without regressions.
Steps:
- Open project in Godot
godot --editor project.godot
- Visual verification
- Open synced scenes in editor
- Compare editor positions with manifest
- Verify positions match expected
- Runtime verification
# Run main scene for 10 seconds godot --quit-after 10 project.godot
- Check for conflicts
# Re-run detection to verify all conflicts resolved grep -rn "position\s*=\s*Vector2(" --include="*.gd" . | wc -l
- Generate Report
=== Position Sync Complete === Conflicts resolved: X - Code → Editor: X - Editor → Code: X - Camera-aware: X Files modified: - X .tscn files updated - X .gd files updated Git commits created: X All tests passing ✓ No regressions detected ✓ Editor preview matches runtime ✓
Supporting Files
This skill uses modular reference files:
- position-detection-patterns.md: All grep patterns for position detection
- sync-strategies.md: Detailed step-by-step procedures
- camera-aware-positioning.md: Camera/parallax handling
- validation-tests.md: Testing procedures
Read these files for detailed implementation guidance.
Red Flags - STOP
These thoughts mean you're rationalizing away discipline:
| Rationalization | Reality | Fix |
|---|---|---|
| "This dynamic position is a conflict" | Misclassification breaks behavior | Use intelligent classifier |
| "I'll sync all positions" | Over-sync breaks intentional dynamic positioning | Only sync true conflicts |
| "Camera-following is a conflict" | Wrong - it's intentional | Skip dynamic patterns |
| "I don't need to test this change" | Untested = broken | Always verify |
| "Close enough in editor" | Iron Law has no exceptions | Exact positions only |
| "I'll manually fix .tscn" | Manual edits create errors | Parse programmatically |
Quick Reference: Conflict → Strategy
| Conflict Type | Detection | Strategy |
|---|---|---|
| Static in _ready() | in _ready | Code → Editor |
| Calculated position | | Editor → Code |
| Camera-following | | Camera-aware |
| Parallax layer | ParallaxLayer + scroll | Camera-aware |
| Player-relative | | Document dynamic |
| Animation/tween | | SKIP (intentional) |
| Every frame (_process) | position in _process | CRITICAL warning |
Camera-Aware Positioning - Special Features
For User's Background Use Case
Problem Statement:
- Background layer positioned at (0, 0) in editor
- At runtime, background follows camera:
position = camera.position - Editor shows wrong position → confusing for level design
- Need: Show correct position in BOTH editor and runtime
Solution:
- Detect Camera Start Position
# Find main camera or player spawn point grep -rn "Camera2D\|player.*position" --include="*.tscn" .
- Calculate Editor Position
# Parse camera start position from main scene camera_start = Vector2(512, 300) # Example # Set background .tscn to camera start background_position = camera_start
- Update Background .tscn
[node name="Background" type="Sprite2D"] position = Vector2(512, 300) # Camera start (was 0, 0)
- Document Behavior
# background.gd # EDITOR PREVIEW: Position set to camera start for accurate level design # RUNTIME: Follows camera dynamically func _process(delta): position = camera.position
- Create Parallax Handler (If Needed)
For ParallaxBackground nodes:
# parallax_background.gd @export var camera_start_position := Vector2(512, 300) func _ready(): # Set initial scroll to camera start scroll_offset = camera_start_position
Result:
- Editor shows background at camera start position
- Level design is accurate
- Runtime follows camera as intended
- WYSIWYG achieved ✓
Execution Strategy
This skill runs fully automatically:
- User invokes skill on Godot project
- Phase 1: Scan and report findings
- User approves synchronization
- Phase 2: Execute all sync operations with commits
- Phase 3: Verify and report results
User input required:
- Initial invocation
- Approval after Phase 1 analysis
- Strategy selection (if ambiguous)
- Final verification check
Everything else is automatic:
- Position conflict detection
- Intelligent classification
- .tscn file updates
- Script modifications
- Git commits
- Testing
Success Criteria
Synchronization is complete when:
- ✓ All static position conflicts resolved
- ✓ Camera-following elements documented
- ✓ Editor preview matches runtime positions
- ✓ All scenes load without errors
- ✓ Behavior identical to baseline
- ✓ Visual appearance unchanged
- ✓ Clean git history with descriptive commits
Integration with Other Skills
Works well with:
- godot-refactoring: Refactor before position sync
- Scene Hierarchy Cleaner: Organize backgrounds into groups
- Scene Layout Organizer: Align after position sync
Best practice workflow:
- Run godot-refactoring (if needed)
- Run editor-position-sync
- Run scene-hierarchy-cleaner (if needed)
- Continue development
Remember: Editor preview is your source of truth for visual design. Runtime must match what you see in the editor. No surprises.