Claude-skill-registry godot-sync-camera-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-sync-camera-positions" ~/.claude/skills/majiayu000-claude-skill-registry-godot-sync-camera-positions && rm -rf "$T"
skills/data/godot-sync-camera-positions/SKILL.mdSync Camera-Following Positions
Core Principle
Editor preview should show realistic gameplay view. Camera-following elements need special handling.
What This Skill Does
Finds patterns like:
# background.gd extends Sprite2D func _process(delta): position = camera.position # Follows camera at runtime # background.tscn [node name="Background" type="Sprite2D"] position = Vector2(0, 0) # Editor shows at origin # RESULT: Editor shows background at (0,0) # But in game, background is at camera position (e.g., 500, 300) # Level designer sees wrong view!
Resolves to:
# background.gd (unchanged - runtime behavior same) func _process(delta): position = camera.position # background.tscn (updated to show typical camera position) [node name="Background" type="Sprite2D"] position = Vector2(500, 300) # Camera starting position # RESULT: Editor preview now shows realistic gameplay view
Detection Patterns
Identifies camera-following code:
Direct Camera Position Follow
func _process(delta): position = camera.position # CAMERA FOLLOW position = camera.global_position position = get_viewport().get_camera_2d().position
Player Position Follow (Indirect Camera)
func _process(delta): position = player.position # Player follows camera # Background follows player → effectively follows camera
Offset Camera Follow
func _process(delta): position = camera.position + offset # CAMERA FOLLOW with offset position = player.position + Vector2(0, -100)
Lerp Camera Follow
func _process(delta): position = position.lerp(camera.position, 0.1) # Smooth camera follow
When to Use
Background Layers
Backgrounds that follow camera for infinite scrolling effect.
UI Overlays
World-space UI that stays with camera.
Level Design
Want to see what area looks like during gameplay.
Camera-Relative Elements
Any element positioned relative to camera.
Process
- Scan - Find position assignments referencing camera/player
- Analyze - Determine if it's camera-following pattern
- Calculate - Determine typical camera position
- Update .tscn - Set editor position to calculated position
- Document - Add comments explaining runtime behavior
- Validate - Ensure editor preview looks correct
- Commit - Git commit per camera-follow sync
Sync Strategies
Strategy 1: Camera Start Position
Set editor position to where camera starts.
Best for: Most camera-following elements.
# background.gd func _process(delta): position = camera.position # Determine camera start position (from Level scene or project settings) # Update background.tscn to position = camera_start_position
Strategy 2: Player Start Position + Offset
Set editor position to player spawn + offset.
Best for: Elements following player with offset.
# cloud.gd func _process(delta): position = player.position + Vector2(0, -200) # Above player # Find player spawn point # Update cloud.tscn to position = player_spawn + Vector2(0, -200)
Strategy 3: Metadata Annotation
Add metadata to scene explaining runtime behavior.
Best for: Complex camera following logic.
# Metadata in .tscn [node name="Background"] metadata/_editor_note = "Runtime: follows camera at camera.position"
Smart Detection
Identifies camera-following patterns:
# CAMERA-FOLLOWING (syncs these) position = camera.position position = $"/root/Main/Camera".position position = player.position # If player has camera position.x = camera.position.x # Horizontal follow
Skips non-camera patterns:
# NOT CAMERA-FOLLOWING (skips these) position = target_position # Generic target position = waypoints[index] # Waypoint following position = mouse_position # Mouse following
Example Transformations
Example 1: Background Layer
Before:
# background.gd extends Sprite2D @onready var camera = $"/root/Main/Camera2D" func _process(delta): position = camera.position # background.tscn [node name="Background" type="Sprite2D"] position = Vector2(0, 0) texture = preload("res://assets/sky.png")
Editor view: Background at origin (0, 0) - wrong! Game view: Background at camera position (640, 360) - correct!
After Sync:
# background.gd (unchanged) extends Sprite2D @onready var camera = $"/root/Main/Camera2D" func _process(delta): # Runtime: follows camera position position = camera.position # background.tscn (updated) [node name="Background" type="Sprite2D"] position = Vector2(640, 360) # Camera start position texture = preload("res://assets/sky.png")
Editor view: Background at (640, 360) - matches gameplay! Game view: Background at camera position - same as before!
Example 2: Player-Relative Cloud
Before:
# cloud.gd extends Sprite2D func _process(delta): position = player.position + Vector2(0, -200) # cloud.tscn [node name="Cloud" type="Sprite2D"] position = Vector2(0, 0)
After Sync:
# cloud.gd (unchanged) func _process(delta): # Runtime: 200 pixels above player position = player.position + Vector2(0, -200) # cloud.tscn (updated to show above player spawn) [node name="Cloud" type="Sprite2D"] position = Vector2(320, -20) # Player spawns at (320, 180)
Camera Position Detection
Method 1: Find Camera2D in Scene
# Search for Camera2D nodes grep -r "type=\"Camera2D\"" scenes/ # Find position value in camera's parent scene
Method 2: Project Settings
# Check viewport size (camera typically starts at center) # Default: 1280x720 → camera at (640, 360)
Method 3: Ask User
If detection uncertain, ask: "Where does your camera start? (e.g., center of viewport, player position)"
What Gets Created
- Updated .tscn files with calculated positions
- Comments documenting runtime behavior
- Metadata annotations for complex patterns
- Validation ensuring editor preview looks correct
- Git commits per sync operation
Integration
Works with:
- godot-sync-static-positions - Static position conflicts
- godot-sync-parallax - Parallax-specific camera following
- godot-fix-positions (orchestrator) - All position sync operations
Safety
- Runtime behavior unchanged
- Only .tscn editor positions updated
- Code remains identical
- Rollback on validation failure
- Original positions in git history
When NOT to Use
Don't sync if:
- Camera-following is complex (multiple cameras, switching)
- Position varies significantly during gameplay
- Editor position has specific meaning (not just default)
- Camera start position unknown/uncertain
Benefits
- Realistic Preview - Editor shows gameplay view
- Better Level Design - See what players will see
- Debug Friendly - Obvious when positions are wrong
- Team Communication - Designers see accurate preview
- WYSIWYG - Preview matches gameplay
Common Camera Patterns
Infinite Scrolling Background
func _process(delta): position.x = camera.position.x # Vertical position fixed, horizontal follows camera
Sync: Set editor x to camera start x, keep y unchanged.
Smooth Camera Follow
func _process(delta): position = position.lerp(camera.position, smoothness)
Sync: Set editor position to camera start (eventual position).
Camera Bounds
func _process(delta): position = camera.position.clamp(min_bounds, max_bounds)
Sync: Set editor position to clamped camera start position.
Validation
After syncing, validates:
- Editor position looks reasonable (not at 0,0)
- .tscn file parses correctly
- Scene loads without errors
- Visual appearance makes sense
Documentation Pattern
# Runtime behavior: # - Follows camera.position in _process # - Editor position set to camera start: (640, 360) # - During gameplay, position will match camera exactly
Clear documentation prevents confusion when code and editor positions differ intentionally.
Camera Detection Hierarchy
- Search for Camera2D in current scene
- Search for Camera2D in parent scenes
- Check project viewport size (assume center)
- Ask user for camera start position
Intelligent detection minimizes user input needed.