Skip to content
godot-modernize-gdscript logo

Godot GDScript 2.0 Modernizer

godot-modernize-gdscript

Modernizes GDScript 1.0 (Godot 3.x) code to GDScript 2.0 (Godot 4.x) syntax. Converts yield to await, onready to @onready, export to @export, setget to property syntax, and adds optional static typing. Essential for Godot 3.x to 4.x migration projects.

SKILL.md

Full skill instructions

Godot GDScript 2.0 Modernizer

Converts GDScript 1.0 (Godot 3.x) patterns to GDScript 2.0 (Godot 4.x) syntax.

Core Conversions

This skill performs five key modernizations:

GDScript 1.0GDScript 2.0Pattern
yield(object, "signal")await object.signalAsync operations
onready var@onready varNode references
export var@export varInspector variables
var x setget set_x, get_xProperty syntaxGetters/​setters
var health = 100var health: int = 100Static typing

UPON INVOCATION - START HERE

When this skill is invoked, IMMEDIATELY execute:

1. Verify Godot Project (5 seconds)

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
  • STOP here

If IS a Godot project:

  • Proceed to step 2

2. Detect GDScript Version (10 seconds)

# Check for Godot 3.x patterns
echo "=== Detecting GDScript 1.0 Patterns ==="
echo "yield statements:"
grep -rn "yield(" --include="*.gd" . | wc -l

echo "onready declarations:"
grep -rn "^onready var" --include="*.gd" . | wc -l

echo "export declarations:"
grep -rn "^export var\|^export(int)\|^export(float)" --include="*.gd" . | wc -l

echo "setget properties:"
grep -rn "setget" --include="*.gd" . | wc -l

echo "untyped variables:"
grep -rn "^var [a-z]" --include="*.gd" . | grep -v ":" | wc -l

3. Present Findings

Show the user:

=== GDScript 2.0 Modernization Analysis ===

Project: [project name]
Current: GDScript 1.0 (Godot 3.x style)

Patterns to modernize:
- yield statements: X
- onready variables: X
- export variables: X
- setget properties: X
- untyped variables: X

Total: X modernizations needed

Modernization includes:
✓ yield → await conversion
✓ onready → @onready
✓ export → @export
✓ setget → property syntax
✓ Optional static typing
✓ Git commit per file
✓ Backup before changes

Would you like me to:
1. Modernize all files (recommended)
2. Show detailed breakdown first
3. Select specific conversions
4. Cancel

4. Wait for User Choice

  • If 1 (Proceed): Start Phase 2 immediately
  • If 2 (Details): Show file-by-file breakdown, then offer to proceed
  • If 3 (Selective): Ask which conversions to apply
  • If 4 (Cancel): Exit skill

Phase 1: Analysis & Inventory

1.1 Create File Inventory

# Find all .gd files
find . -name "*.gd" -type f | sort > /​tmp/​gdscript_files.txt
wc -l /​tmp/​gdscript_files.txt
echo "files found"

1.2 Analyze Each File

For each .gd file, detect patterns:

# Analyze patterns per file
for file in $(cat /​tmp/​gdscript_files.txt); do
    echo "=== $file ==="
    grep -c "yield(" "$file" 2>/​dev/​null || echo 0
    grep -c "^onready var" "$file" 2>/​dev/​null || echo 0
    grep -c "^export" "$file" 2>/​dev/​null || echo 0
    grep -c "setget" "$file" 2>/​dev/​null || echo 0
done

1.3 Create Modernization Plan

Modernization Plan:
===================

1. yield → await conversions (X files)
2. onready → @onready (X files)
3. export → @export (X files)
4. setget → properties (X files)
5. Static typing (X files)

Total files to modify: X
Estimated time: Auto (user doesn't wait)
Backup created: YES (git tag)
Rollback available: YES

Phase 2: Modernization Operations

Conversion A: yield → await

Detection:

grep -rn "yield(" --include="*.gd" .

Common Patterns:

Old PatternNew Pattern
yield(get_tree().create_timer(1.0), "timeout")await get_tree().create_timer(1.0).timeout
yield(timer, "timeout")await timer.timeout
yield(animation_player, "animation_finished")await animation_player.animation_finished
yield(get_tree(), "idle_frame")await get_tree().process_frame

Transformation Process:

  1. Extract yield statement

    # Before
    yield(get_tree().create_timer(2.0), "timeout")
    
  2. Convert to await

    # After
    await get_tree().create_timer(2.0).timeout
    
  3. Handle variable assignment

    # Before
    var result = yield(async_function(), "completed")
    
    # After
    var result = await async_function()
    

Implementation:

# Pseudo-code for replacement
def convert_yield_to_await(line):
    # Pattern: yield(object, "signal_name")
    # Convert to: await object.signal_name
    
    import re
    pattern = r'yield\(([^,]+),\s*"([^"]+)"\)'
    replacement = r'await \1.\2'
    return re.sub(pattern, replacement, line)

Conversion B: onready → @onready

Detection:

grep -rn "^onready var" --include="*.gd" .

Transformation:

# Before
onready var player = $Player
onready var health_bar = $UI/​HealthBar

# After
@onready var player: Node = $Player
@onready var health_bar: ProgressBar = $UI/​HealthBar

Process:

  1. Replace onready with @onready
  2. Add type hints where detectable
  3. Keep variable name and initialization

Type Inference (Optional):

# If $Player is CharacterBody2D in scene
@onready var player: CharacterBody2D = $Player

# If $Timer is Timer node
@onready var _timer: Timer = $Timer

Conversion C: export → @export

Detection:

grep -rn "^export" --include="*.gd" .

Transformation:

# Before
export var speed = 200
export(int) var max_health = 100
export(float) var jump_force = 500.0
export(String) var character_name = "Player"
export(NodePath) var target_path

# After
@export var speed: float = 200.0
@export var max_health: int = 100
@export var jump_force: float = 500.0
@export var character_name: String = "Player"
@export var target_path: NodePath

Export Types Mapping:

Old ExportNew ExportType
export(int)@export var x: intInteger
export(float)@export var x: floatFloat
export(String)@export var x: StringString
export(bool)@export var x: boolBoolean
export(Color)@export var x: ColorColor
export(Vector2)@export var x: Vector2Vector2
export(Vector3)@export var x: Vector3Vector3
export(NodePath)@export var x: NodePathNodePath
export var@export var x: TypeInferred

Conversion D: setget → Property Syntax

Detection:

grep -rn "setget" --include="*.gd" .

Transformation:

# Before (GDScript 1.0)
var health = 100 setget set_health, get_health

func set_health(value):
    health = clamp(value, 0, max_health)
    health_changed.emit(health)

func get_health():
    return health
# After (GDScript 2.0)
var health: int = 100:
    set(value):
        health = clamp(value, 0, max_health)
        health_changed.emit(health)
    get:
        return health

Process:

  1. Remove setget from variable declaration
  2. Add colon after type
  3. Inline setter and getter
  4. Use set(value): and get: syntax

Complex Example:

# Before
var score = 0 setget set_score

func set_score(value):
    score = max(0, value)
    update_ui()

# After
var score: int = 0:
    set(value):
        score = max(0, value)
        update_ui()

Conversion E: Static Typing (Optional)

Detection:

grep -rn "^var [a-z_]* = " --include="*.gd" . | grep -v ":"

Type Inference:

ValueInferred Type
= 100int
= 3.14float
= "text"String
= truebool
= Vector2(x, y)Vector2
= $NodeNode type from scene

Transformation:

# Before
var health = 100
var speed = 200.5
var name = "Player"
var active = true
var position = Vector2.ZERO

# After
var health: int = 100
var speed: float = 200.5
var name: String = "Player"
var active: bool = true
var position: Vector2 = Vector2.ZERO

Phase 3: Execution & Safety

3.1 Create Git Baseline

# Create backup tag
git tag gdscript1-baseline-$(date +%Y%m%d-%H%M%S)

# Stage any current changes
git add .
git commit -m "Baseline: Pre-GDScript 2.0 modernization" || echo "No changes to commit"

3.2 Process Files Sequentially

For each .gd file:

# Process file
python3 << 'EOF'
import re

def modernize_gdscript(content):
    # Conversion 1: yield → await
    content = re.sub(
        r'yield\(([^,]+),\s*"([^"]+)"\)',
        r'await \1.\2',
        content
    )
    
    # Conversion 2: onready → @onready
    content = re.sub(
        r'^onready var',
        '@onready var',
        content,
        flags=re.MULTILINE
    )
    
    # Conversion 3: export → @export (simple)
    content = re.sub(
        r'^export var',
        '@export var',
        content,
        flags=re.MULTILINE
    )
    
    return content

# Read, process, write
with open("script.gd", "r") as f:
    content = f.read()

new_content = modernize_gdscript(content)

with open("script.gd", "w") as f:
    f.write(new_content)
EOF

3.3 Commit Per File

# After each file modification
git add "$file"
git commit -m "Modernize: $file to GDScript 2.0

- Converted yield to await
- Updated onready to @onready  
- Migrated export to @export
- Applied static typing"

3.4 Validation After Each File

# Validate syntax
godot --headless --quit-after 2 project.godot 2>&1 | grep -i "error" && {
    echo "Syntax error detected in $file"
    git reset --hard HEAD~1
    echo "Reverted changes to $file"
}

Phase 4: Verification & Testing

4.1 Syntax Validation

# Check all modified files for syntax errors
for file in $(git diff --name-only HEAD~10..HEAD | grep "\.gd$"); do
    echo "Checking $file..."
    # Basic syntax check
    gdscript_tool --check "$file" 2>/​dev/​null || echo "Manual review needed: $file"
done

4.2 Pattern Verification

# Verify no old patterns remain
echo "Checking for remaining GDScript 1.0 patterns..."

echo "yield statements remaining:"
grep -rn "yield(" --include="*.gd" . | wc -l

echo "onready remaining:"
grep -rn "^onready var" --include="*.gd" . | wc -l

echo "export remaining:"
grep -rn "^export var\|^export(" --include="*.gd" . | wc -l

4.3 Godot Project Test

# Open project in Godot to verify
godot --editor project.godot &
sleep 5

# Check for errors
# (User should visually verify no red errors in Output panel)

Examples

Example 1: Complete Script Modernization

Before (GDScript 1.0):

extends CharacterBody2D

export var speed = 200
export(int) var health = 100

onready var sprite = $Sprite
onready var animation = $AnimationPlayer

var damage = 10 setget set_damage

func set_damage(value):
    damage = clamp(value, 0, 100)

func _ready():
    yield(get_tree().create_timer(1.0), "timeout")
    start_game()

func take_damage(amount):
    health -= amount
    if health <= 0:
        yield(play_death_animation(), "completed")
        queue_free()

func play_death_animation():
    animation.play("death")
    yield(animation, "animation_finished")

After (GDScript 2.0):

extends CharacterBody2D

@export var speed: float = 200.0
@export var health: int = 100

@onready var sprite: Sprite2D = $Sprite
@onready var animation: AnimationPlayer = $AnimationPlayer

var damage: int = 10:
    set(value):
        damage = clamp(value, 0, 100)

func _ready():
    await get_tree().create_timer(1.0).timeout
    start_game()

func take_damage(amount: int) -> void:
    health -= amount
    if health <= 0:
        await play_death_animation()
        queue_free()

func play_death_animation() -> void:
    animation.play("death")
    await animation.animation_finished

Example 2: Signal Connection Modernization

Before:

func _ready():
    button.connect("pressed", self, "_on_button_pressed")
    timer.connect("timeout", self, "_on_timeout")

func _on_button_pressed():
    pass

func _on_timeout():
    pass

After:

func _ready():
    button.pressed.connect(_on_button_pressed)
    timer.timeout.connect(_on_timeout)

func _on_button_pressed() -> void:
    pass

func _on_timeout() -> void:
    pass

Success Criteria

Modernization complete when:

  • ✓ Zero yield( statements remain (converted to await)
  • ✓ Zero onready var remain (converted to @onready)
  • ✓ Zero export var remain (converted to @export)
  • ✓ Zero setget remain (converted to property syntax)
  • ✓ All scripts compile without errors
  • ✓ No functional changes (behavior identical)
  • ✓ Git history shows clear modernization commits

Common Issues & Solutions

Issue 1: yield with function calls

Problem:

var result = yield(load_data(), "completed")

Solution:

var result = await load_data()

Issue 2: Coroutines with state

Problem:

func process():
    yield(do_step_1(), "completed")
    yield(do_step_2(), "completed")

Solution:

func process() -> void:
    await do_step_1()
    await do_step_2()

Issue 3: setget with only getter or setter

Problem:

var score = 0 setget , get_score  # Only getter

Solution:

var score: int = 0:
    get:
        return score

Rollback Procedure

If modernization causes issues:

# Find baseline tag
git tag | grep "gdscript1-baseline"

# Reset to pre-modernization state
git reset --hard <baseline-tag>

# Or revert specific commits
git revert <modernization-commit-hash>

Integration with Other Skills

Use before:

  • godot-refactor - Modernize syntax first, then refactor architecture
  • godot-migrate-tilemap - Update code before TileMap migration

Use after:

  • Project conversion from Godot 3.x to 4.x
  • godot-organize-project - Organize files first

This skill automates the tedious parts of GDScript 1.0 → 2.0 migration while preserving exact functionality.

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

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

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

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

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

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.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View