Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate a new Godot game project with standardized ECS structure and tooling. Use when starting a new game: "create a project", "set up a new game", "scaffold", "initialize", "new project", "start building", "let's make it". Triggers after game-planner produces a confirmed plan, or when the user provides a game name + genre directly. Even for simple requests like "make me a new Godot project", use this skill to ensure proper ECS structure. Creates directory structure, project.godot, CLAUDE.md,
.claude/skills/randallliuxin-project-scaffold/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-18 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 1% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 38% | 0% |
| case-03 | ✗→✓ | ▲ Improved | -7% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 73% | 0% |
$ARGUMENTS
Generate a new Godot game project with GodotMaker's ECS architecture. Read templates from this skill's templates/ directory, fill {{placeholders}} with values from the game plan or user input, and write results to the target.
If a confirmed Game Plan exists in the conversation (from game-planner), extract variables from it. Otherwise, ask the user for game name and genre at minimum — use genre defaults for everything else.
| Variable | Source | Default | |----------|--------|---------| | {{game_name}} | user input, snake_case, used as directory name | required | | {{game_title}} | user input or Title Case of game_name | required | | {{genre}} | Game Plan "Genre" or user | "platformer" | | {{perspective}} | Fixed framework target | "2D" | | {{viewport_width}} | genre defaults table | 1280 | | {{viewport_height}} | genre defaults table | 720 | | {{rendering_method}} | fixed 2D renderer | "gl_compatibility" | | {{root_node_type}} | fixed 2D root | "Node2D" | | {{camera_type}} | fixed 2D camera | "Camera2D" | | {{game_description}} | Game Plan summary or one-line from user | genre name + " game" |
Genre defaults:
| Genre | Viewport | Gravity | Input Actions | |-------|----------|---------|---------------| | Platformer | 1280x720 | 980.0 | move_left, move_right, jump | | Top-down | 1280x720 | none | move_up, move_down, move_left, move_right | | Puzzle | 1280x720 | none | select, confirm, cancel | | Endless runner | 720x1280 | 980.0 | jump |
Create the project root and all subdirectories:
{{game_name}}/
├── project.godot
├── CLAUDE.md
├── .gitignore
├── src/
│ ├── components/ # C_ prefixed component scripts
│ ├── systems/ # NameSystem scripts
│ ├── entities/ # Entity scene definitions
│ └── ui/ # UI scenes and scripts
├── scenes/
│ ├── main.tscn # Entry point scene
│ └── game_world.tscn # Gameplay scene with camera
├── test/
│ └── test_example.gd # gdUnit4 test template
├── e2e/
│ └── conftest.py # E2E test config (GODOT_PROJECT = "..")
├── assets/
│ ├── sprites/
│ ├── audio/
│ ├── fonts/
│ └── ui/
├── references/ # Scene reference images (generated by /gm-asset)
└── addons/ # gecs + gdUnit4 + godot_e2e installed hereWhen writing .tscn files (from templates or manually), follow these rules strictly:
res://path/to/script.gd paths, never uid://xxx. UID references fail in headless/CI environments because uid_cache.bin cannot be rebuilt.load_steps = ext_resource_count + sub_resource_count + 1. Count carefully; mismatch causes parse errors.[node] omits parent. Every other node MUST have parent="." (direct child of root) or parent="path/to/parent".system_nodes_root = NodePath(".") and entity_nodes_root = NodePath(".") when using SystemGroups.Read each template from templates/, replace all {{placeholders}}, write output. Remove any template comments (lines starting with ; TEMPLATE:) from the output.
| Template | Output Path | Notes | |----------|------------|-------| | project.godot.tmpl | project.godot | Must be valid Godot ConfigFile | | claude.md.tmpl | CLAUDE.md | Fill game info + ECS reference | | gitignore.tmpl | .gitignore | Use as-is, no placeholders | | main_scene.tmpl | scenes/main.tscn | Use a 2D root node | | world_scene.tmpl | scenes/game_world.tscn | Use 2D node + camera types; gameplay scene gets a World child node added during /gm-build | | test_example.tmpl | test/test_example.gd | Replace {{GameNamePascal}} | | component.tmpl | src/components/c_example.gd | Example stub | | system.tmpl | src/systems/example_system.gd | Example stub |
gecs v7.1.0 ships class_name World in addons/gecs/ecs/world.gd. The canonical scene-node pattern:
Node child to your gameplay scene withscript = res://addons/gecs/ecs/world.gd, named World, with system_nodes_root = NodePath("Systems") and entity_nodes_root = NodePath("Entities").
@onready var world: World = $World then ECS.world = world in _ready().
world.process(delta, "gameplay") /world.process(delta, "physics") from _process / _physics_process.
Scaffold leaves the World node out — gameplay scene structure is filled in during /gm-build. See the gecs skill for the full World API.
If the Game Plan includes an ECS Architecture section with components and systems:
C_Velocity), create a file insrc/components/ based on component.tmpl. Fill the class name and add @export vars from the plan.
MovementSystem), create a file insrc/systems/ based on system.tmpl. Fill the class name and query() with the required components.
scene's World node — see "gecs World setup" above for the full pattern.
After writing base template files, apply genre-specific modifications to project.godot:
Platformer / Endless runner (gravity games):
[physics] section: 2d/default_gravity=980.0[input] section with move + jump actionsTop-down:
[physics] section[input] section with 4-directional movementFor input action serialization format, read references/project_settings.md — it has the exact Object() syntax and key code table.
After all files are written, tell the user what to do next:
bash bash <godotmaker_repo>/shell/publish.sh {{game_name}}/ This copies skills to .claude/skills/, creates godotmaker.yaml (prompts for Godot executable path on first run), and creates .godotmaker/config.yaml with default project settings.
active runtime's config/addon_versions.json (the source of truth for repo, tag, and install path), then install addon-only directories:
addons/gecs/addons/gdUnit4/addons/godot_e2e/tools/check_project.py --e2e and the gm- skills expect those exact paths (note gdUnit4/ is capital U — matches the upstream repo layout). See references/addons.md for the step-by-step installation contract.
bash claude mcp add godot -e GODOT_PATH="<godot_path>" -- npx @coding-solo/godot-mcp
godot --headless --quit 2>&1After scaffold completes, output:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-18 | fail→pass | 13,479 | 1,887 | -86% | 1 | 1 | 0% | 2,246 | 2,446 | +9% | 0 | 0 | — |
case-01 | fail→pass | 24,185 | 13,653 | -44% | 1 | 1 | 0% | 4,735 | 4,806 | +1% | 0 | 0 | — |
case-02 | fail→pass | 22,410 | 19,800 | -12% | 1 | 1 | 0% | 4,611 | 6,356 | +38% | 0 | 0 | — |
case-03 | fail→pass | 27,722 | 15,493 | -44% | 1 | 1 | 0% | 6,101 | 5,647 | -7% | 0 | 0 | — |
case-04 | fail→pass | 14,244 | 11,616 | -18% | 1 | 1 | 0% | 2,901 | 5,015 | +73% | 0 | 0 | — |
case-05 | pass→pass | 16,558 | 12,910 | -22% | 1 | 1 | 0% | 3,634 | 5,021 | +38% | 0 | 0 | — |
case-06 | pass→pass | 5,256 | 2,404 | -54% | 1 | 1 | 0% | 898 | 2,592 | +189% | 0 | 0 | — |
case-07 | pass→pass | 6,954 | 2,101 | -70% | 1 | 1 | 0% | 1,141 | 2,499 | +119% | 0 | 0 | — |
case-08 | fail→pass | 13,095 | 4,485 | -66% | 1 | 1 | 0% | 2,065 | 2,872 | +39% | 0 | 0 | — |
case-09 | fail→pass | 9,625 | 3,133 | -67% | 1 | 1 | 0% | 1,673 | 2,764 | +65% | 0 | 0 | — |
case-19 | fail→pass | 8,697 | 3,731 | -57% | 1 | 1 | 0% | 1,363 | 2,733 | +101% | 0 | 0 | — |
case-10 | fail→fail | 6,280 | 2,187 | -65% | 1 | 1 | 0% | 978 | 2,585 | +164% | 0 | 0 | — |
case-11 | fail→pass | 15,266 | 2,385 | -84% | 1 | 1 | 0% | 2,398 | 2,560 | +7% | 0 | 0 | — |
case-12 | fail→pass | 6,271 | 2,366 | -62% | 1 | 1 | 0% | 951 | 2,541 | +167% | 0 | 0 | — |
case-13 | fail→pass | 7,194 | 1,803 | -75% | 1 | 1 | 0% | 1,181 | 2,475 | +110% | 0 | 0 | — |
case-14 | pass→pass | 8,592 | 3,241 | -62% | 1 | 1 | 0% | 1,256 | 2,660 | +112% | 0 | 0 | — |
case-15 | pass→pass | 6,222 | 2,859 | -54% | 1 | 1 | 0% | 1,092 | 2,684 | +146% | 0 | 0 | — |
case-16 | fail→pass | 6,990 | 2,314 | -67% | 1 | 1 | 0% | 1,148 | 2,606 | +127% | 0 | 0 | — |
case-17 | fail→pass | 7,845 | 2,040 | -74% | 1 | 1 | 0% | 1,365 | 2,519 | +85% | 0 | 0 | — |
case-20 | fail→pass | 4,947 | 2,075 | -58% | 1 | 1 | 0% | 721 | 2,501 | +247% | 0 | 0 | — |
case-21 | fail→fail | 12,285 | 17,073 | +39% | 1 | 1 | 0% | 2,331 | 5,238 | +125% | 0 | 0 | — |
case-22 | fail→fail | 44,946 | 41,698 | -7% | 1 | 1 | 0% | 6,175 | 8,064 | +31% | 0 | 0 | — |
case-23 | pass→pass | 6,089 | 7,796 | +28% | 1 | 1 | 0% | 1,043 | 3,551 | +240% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +61 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.