Claude-skill-registry godot-fix-positions

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-fix-positions" ~/.claude/skills/majiayu000-claude-skill-registry-godot-fix-positions && rm -rf "$T"
manifest: skills/data/godot-fix-positions/SKILL.md
source content

Godot 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:

  • position = Vector2(x, y)
    in
    _ready()
    or
    _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
  • position = camera.position
    patterns

Player-Relative Positioning:

  • Nodes positioned relative to player
  • position = player.position + offset
    patterns
  • 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:

  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 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" .
  1. Parse .tscn Files for Positions

Extract position properties from scenes:

# Find position declarations in .tscn files
grep -rn "^position\s*=\s*Vector2(" --include="*.tscn" .
  1. Intelligent Classification

For each detected position assignment, classify as:

  • CONFLICT: Static position in
    _ready()
    differs from .tscn
  • INTENTIONAL_DYNAMIC: Camera/player following (skip)
  • INTENTIONAL_ANIMATION: Tweens/animations (skip)
  • PROCESS_ASSIGNMENT: Every-frame in
    _process()
    (critical warning)

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"
  1. Create Conflict Manifest

Generate a priority-ordered list:

FileNodeEditor PositionCode PositionClassificationSync Strategy
background.gdBackground(0, 0)camera.positionDYNAMICDocument intent
enemy.gdEnemy(500, 300)(100, 150)CONFLICTCode → Editor
ui_label.gdLabel(10, 10)(50, 50)CONFLICTEditor → 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:

  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 conflict
  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

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
    _ready()
    and never changes

Process:

  1. 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
  1. 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)
  1. 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
  1. 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"
  1. 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:

  1. Keep Code Assignment

Code already correct:

func _ready():
    position = Vector2(100, 150)  # Correct position
  1. 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)
  1. 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)
  1. 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()"
  1. 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:

  1. Detect Camera-Following Pattern
# background.gd
func _process(delta):
    position = camera.position  # Follows camera
  1. 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)

  1. Update .tscn to Camera Start Position
[node name="Background" type="Sprite2D"]
position = Vector2(512, 300)  # Camera start position
  1. 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
  1. 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
  1. 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"
  1. 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:

  1. Open project in Godot
godot --editor project.godot
  1. Visual verification
  • Open synced scenes in editor
  • Compare editor positions with manifest
  • Verify positions match expected
  1. Runtime verification
# Run main scene for 10 seconds
godot --quit-after 10 project.godot
  1. Check for conflicts
# Re-run detection to verify all conflicts resolved
grep -rn "position\s*=\s*Vector2(" --include="*.gd" . | wc -l
  1. 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:

RationalizationRealityFix
"This dynamic position is a conflict"Misclassification breaks behaviorUse intelligent classifier
"I'll sync all positions"Over-sync breaks intentional dynamic positioningOnly sync true conflicts
"Camera-following is a conflict"Wrong - it's intentionalSkip dynamic patterns
"I don't need to test this change"Untested = brokenAlways verify
"Close enough in editor"Iron Law has no exceptionsExact positions only
"I'll manually fix .tscn"Manual edits create errorsParse programmatically

Quick Reference: Conflict → Strategy

Conflict TypeDetectionStrategy
Static in _ready()
position = Vector2()
in _ready
Code → Editor
Calculated position
position = calc_spawn()
Editor → Code
Camera-following
position = camera.position
Camera-aware
Parallax layerParallaxLayer + scrollCamera-aware
Player-relative
position = player.position + offset
Document dynamic
Animation/tween
tween_property("position")
SKIP (intentional)
Every frame (_process)position in _processCRITICAL 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:

  1. Detect Camera Start Position
# Find main camera or player spawn point
grep -rn "Camera2D\|player.*position" --include="*.tscn" .
  1. 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
  1. Update Background .tscn
[node name="Background" type="Sprite2D"]
position = Vector2(512, 300)  # Camera start (was 0, 0)
  1. 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
  1. 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:

  1. User invokes skill on Godot project
  2. Phase 1: Scan and report findings
  3. User approves synchronization
  4. Phase 2: Execute all sync operations with commits
  5. 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:

  1. Run godot-refactoring (if needed)
  2. Run editor-position-sync
  3. Run scene-hierarchy-cleaner (if needed)
  4. Continue development

Remember: Editor preview is your source of truth for visual design. Runtime must match what you see in the editor. No surprises.