Expert patterns for migrating 2D games to 3D including node type conversions, camera systems (third-person, first-person, orbit), physics layer migration, sprite-to-model art pipeline, and control scheme adaptations. Use when porting 2D projects to 3D or adding 3D elements. Trigger keywords: CharacterBody2D to CharacterBody3D, Area2D to Area3D, Camera2D to Camera3D, Vector2 to Vector3, collision_layer migration, sprite to MeshInstance3D, 2D to 3D conversion.
npx skills add https://github.com/thedivergentai/GD-Agentic-Skills --skill godot-adapt-2d-to-3d
Expert guidance for migrating 2D games into the third dimension.
Quaternion for 3D rotation interpolation or the Basis matrix for directional vectors._process to follow a body moving in _physics_process causes jitter. Use Node3D.get_global_transform_interpolated() for smooth transforms.> MANDATORY: Load migration scripts before pasting camera/movement recipes.
MANDATORY third-person SpringArm3D + Camera3D. Do not parent Camera3D bare to the body.
MANDATORY camera-relative CharacterBody3D movement for 2D→3D ports.
MANDATORY checklist: 3D Physics layer names are separate from 2D — mirror names, then apply bits.
Sprite3D billboard configuration and world-to-screen projection for placing 2D UI over 3D objects.
Vector2↔Vector3 mapping helpers (Y-up vs Z-forward pitfalls).
Diegetic / projected UI sharpness patterns.
Billboards, mouse→3D rays, CanvasLayer overlay helpers.
Projects NavigationServer3D paths to 2D screen/gameplay plane for 2.5D sprite actors.
MultiMesh + billboard shader crowd (GPU orientation; not per-node Sprite3D).
> Do NOT Load lighting deep-dives here — route to godot-3d-lighting. Add a DirectionalLight3D + ambient only; GI/cascades live there.
| 2D Node | 3D Equivalent | Notes |
|---------|---------------|-------|
| CharacterBody2D | CharacterBody3D | MANDATORY characterbody3d_migration_movement.gd |
| RigidBody2D | RigidBody3D | Gravity Vector3(0, -9.8, 0) |
| StaticBody2D | StaticBody3D | Shape3D resources (no auto-convert) |
| Area2D | Area3D | Same trigger idea; new layers |
| Sprite2D | MeshInstance3D / Sprite3D | Billboard vs mesh art choice |
| Camera2D | Camera3D | MANDATORY spring_arm_camera_setup.gd |
| CollisionShape2D | CollisionShape3D | Re-author shapes |
| RayCast2D | RayCast3D | target_position is Vector3 |
physics_layer_migration_checklist.gd. Project Settings → Layer Names → 3D Physics.spring_arm_camera_setup.gd. Never copy Camera2D follow onto Camera3D.characterbody3d_migration_movement.gd. Camera-relative XZ; jump on Y.# Use Sprite3D for quick conversion
extends Sprite3D
func _ready() -> void:
texture = load("res://sprites/character.png")
billboard = BaseMaterial3D.BILLBOARD_ENABLED # Always face camera
pixel_size = 0.01 # Scale sprite in 3D space
# Create textured quads
var mesh_instance := MeshInstance3D.new()
var quad := QuadMesh.new()
quad.size = Vector2(1, 1)
mesh_instance.mesh = quad
var material := StandardMaterial3D.new()
material.albedo_texture = load("res://sprites/character.png")
material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
material.cull_mode = BaseMaterial3D.CULL_DISABLED # Show both sides
mesh_instance.material_override = material
# Import .glb, .fbx models
var character := load("res://models/character.glb").instantiate()
add_child(character)
# Access animations
var anim_player := character.get_node("AnimationPlayer")
anim_player.play("idle")
Minimum: one DirectionalLight3D + WorldEnvironment ambient so the scene is not black. Do NOT Load cascade/GI/bake tutorials in this skill — godot-3d-lighting.
# ✅ GOOD: Keep 2D UI overlay
# Scene structure:
# Main (Node3D)
# ├─ WorldEnvironment
# ├─ DirectionalLight3D
# ├─ Player (CharacterBody3D)
# └─ CanvasLayer # 2D UI on top of 3D world
# └─ Control (HUD)
# UI remains 2D (Control nodes, Sprite2D for HUD elements)
Speculative "2D vs 3D budget" tables lie. Gate on measured data:
directional_shadow_max_distance and shadowed Omni/Spot count until frame time recovers (tune in godot-3d-lighting).visibility_range_* on distant GeometryInstance3D; unlit/simplified materials past the near band.# 2D: left/right for horizontal movement
Input.get_axis("left", "right")
# 3D: Add forward/back, use get_vector()
var input := Input.get_vector("left", "right", "forward", "back")
# Returns Vector2(horizontal, vertical) for 3D movement
# Configure in Project Settings → Input Map:
# forward: W, Up Arrow
# back: S, Down Arrow
# left: A, Left Arrow
# right: D, Right Arrow
# Mouse look (lock cursor)
func _ready() -> void:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _input(event: InputEvent) -> void:
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
rotate_camera(event.relative)
# Problem: Forgot to set collision layers for 3D
# Solution: Reconfigure layers
var body := CharacterBody3D.new()
body.collision_layer = 0b0001 # What AM I?
body.collision_mask = 0b0110 # What do I DETECT?
Use MANDATORY spring_arm_camera_setup.gd — set spring_arm.collision_mask to the World layer so the boom retracts instead of clipping.
# Problem: StaticBody3D floor has no CollisionShape3D
# Solution: Add collision
var floor_collision := CollisionShape3D.new()
var box_shape := BoxShape3D.new()
box_shape.size = Vector3(100, 1, 100)
floor_collision.shape = box_shape
floor.add_child(floor_collision)
| Factor | Stay 2D | Go 3D |
|--------|---------|-------|
| Gameplay | Platformer, top-down, no depth needed | Exploration, first-person, 3D space combat |
| Art budget | Pixel art, limited resources | 3D models available or necessary |
| Performance target | Mobile, web, low-end | Desktop, console, high-end mobile |
| Development time | Limited | Have time for 3D learning curve |
| Team skills | 2D artists only | 3D artists or asset library |
When moving a 3D character, rely heavily on Transform3D basis vectors rather than calculating trigonometric angles. To move forward locally, extract the negative Z-axis of your transform's basis: velocity = transform.basis.z * speed.
In 2D, the Y-axis points down. In 3D, Godot uses a right-handed system where Y-axis points UP, and forward is -Z. Translating 2D jumps to 3D requires inverting the Y velocity logic (e.g., velocity.y = JUMP_SPEED instead of -JUMP_SPEED).
For 2.5D games where actors move on a 3D floor but are displayed as 2D sprites, query the NavigationServer3D directly and project the resulting PackedVector3Array into 2D screen space (or a flattened gameplay plane) using Camera3D.unproject_position.
class_name NavigationBridge2D5D extends Node
## Projects 3D NavigationServer paths to 2D screenspace for 2.5D movement.
static func query_2_5d_path(camera: Camera3D, map_rid: RID, start_2d: Vector2, target_2d: Vector2) -> PackedVector2Array:
# 1. Project 2D screen points to the 3D ground plane (Y=0).
var start_3d := camera.project_position(start_2d, 0.0)
var target_3d := camera.project_position(target_2d, 0.0)
# 2. Query optimized 3D path.
var path_3d := NavigationServer3D.map_get_path(map_rid, start_3d, target_3d, true)
# 3. Project 3D world points back to 2D screenspace coordinates for the sprite.
var path_2d := PackedVector2Array()
for point in path_3d:
path_2d.append(camera.unproject_position(point))
return path_2d
To render millions of instances, use MultiMeshInstance3D paired with a custom Visual Shader. Use VisualShaderNodeBillboard with BILLBOARD_TYPE_FIXED_Y to ensure sprites stay upright on flat terrain.
class_name MassiveCrowdManager extends MultiMeshInstance3D
## Efficiently manages millions of camera-facing instances via GPU hardware.
func _ready() -> void:
# 1. Configure the MultiMesh for 3D transforms.
multimesh = MultiMesh.new()
multimesh.transform_format = MultiMesh.TRANSFORM_3D
multimesh.instance_count = 10000
# 2. Build a ShaderMaterial using VisualShaderNodeBillboard.
var material := ShaderMaterial.new()
# Note: Logic assumes billboard_type=BILLBOARD_TYPE_FIXED_Y and keep_scale=true.
multimesh.mesh = QuadMesh.new()
multimesh.mesh.surface_set_material(0, material)
# 3. Populate transforms. The GPU handles orientation.
for i in range(multimesh.instance_count):
var pos := Vector3(randf() * 100, 0, randf() * 100)
multimesh.set_instance_transform(i, Transform3D(Basis(), pos))
PointLight2D→OmniLight3D conversion is one-shot editor work — keep a project tool if needed. Ongoing lighting quality belongs in godot-3d-lighting.
| Topic | Reference / script |
|-------|-------------------|
| Step-by-step migration / perf gates | migration-recipes.md |
| 2.5D nav bridge / crowd billboards | inline Expert Techniques + bundled scripts |
> Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing to a peer domain — do not preload the whole lattice.
Basis/Transform3D/Quaternion patterns that replace Euler-angle Camera2D follow and 2D rotation habits.move_and_slide API after CharacterBody2D → CharacterBody3D conversion (no dedicated 3D tutorial page)._process needs interpolated transforms after physics-step movement.Input.get_vector plus mouse-capture look so 2D left/right maps become camera-relative XZ.PhysicsRayQueryParameters3D picks used by point-and-click 3D ports.A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).
Extracts and analyzes competitors' ads from ad libraries (Facebook, LinkedIn, etc.) to understand what messaging, problems, and creative approaches are working. Helps inspire and improve your own ad campaigns.
Identifies high-quality leads for your product or service by analyzing your business, searching for target companies, and providing actionable contact strategies. Perfect for sales, business development, and marketing professionals.
Analyzes your recent Claude Code chat history to identify coding patterns, development gaps, and areas for improvement, curates relevant learning resources from HackerNews, and automatically sends a personalized growth report to your Slack DMs.
Complete App Store Optimization (ASO) toolkit for researching, optimizing, and tracking mobile app performance on Apple App Store and Google Play Store
NGS analysis toolkit. BAM to bigWig conversion, QC (correlation, PCA, fingerprints), heatmaps/profiles (TSS, peaks), for ChIP-seq, RNA-seq, ATAC-seq visualization.
Materials science toolkit. Crystal structures (CIF, POSCAR), phase diagrams, band structure, DOS, Materials Project integration, format conversion, for computational materials science.
Transforms vague UI ideas into polished, Stitch-optimized prompts. Enhances specificity, adds UI/UX keywords, injects design system context, and structures output for better generation results.
Take thedivergentai/godot-adapt-2d-to-3d from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.