---
name: godot-new-game
description: >
  Scaffold a new Godot 4.6 game project that boots green on the first probe —
  a pinned engine binary, the Android export fix nobody remembers until it's
  too late, a bounded-kill headless test harness, and a clean gitignore. Use
  when starting or bootstrapping a new Godot game project, or /godot-new-game.
user_invocable: true
---

> **Public / shared version** — trimmed from a private Claude Code setup and
> posted at smereski.com as a reusable pattern. Paths, package-id conventions,
> and references to internal tooling are genericized; the two Godot traps and
> the probe-harness pattern are the real value and are left intact.

# godot-new-game — scaffold a Godot project that boots green

Scaffold a new Godot 4.6 game so the *first* headless probe run exits clean —
not the fifth, after you've re-derived the same setup and re-discovered the
same two traps that eat a day each time: a broken engine shim, and a missing
Android compression flag that produces a blank wall of "config errors" with
no useful stack trace.

## Steps

1. **Lock the basics.** Game name, 2D or 3D, and ship target (mobile store,
   Steam, your own app catalog, or a smart-glasses/other niche platform). Pick
   a package-id slug once — `com.yourstudio.<slug>` or whatever your own
   reverse-domain convention is — and don't rename it later; save data and
   store listings key off it. Ask only for what's genuinely unset; infer the
   rest from context.

2. **Bind the engine to an explicit binary, not a shim.** Point an env var
   (e.g. `$GODOT`) at the actual **console-subsystem** executable —
   `Godot_v4.6-stable_win64_console.exe` on Windows, or the equivalent on your
   platform — not a package-manager-installed launcher link. This matters for
   two reasons:
   - A GUI-subsystem binary (or a shim that resolves to one) detaches on
     direct invocation — no stdout, no real exit code — which makes headless
     scripting silently useless.
   - Package-manager shims (Windows `winget`, some Linux packages) drift
     version on every upgrade and have shipped as broken stubs before. A
     pinned, explicit path is deterministic; a moving shim is not.

3. **Create the project** with a `project.godot`. In the `[rendering]` block,
   make sure
   ```ini
   textures/vram_compression/import_etc2_astc=true
   ```
   is set. Its *absence* is the cause of a blank "config errors" wall on
   Android export with no actionable message — this one flag has cost more
   debugging time than anything else in a fresh Godot project. If you're
   targeting mobile GL-compatibility rendering, also set
   `renderer/rendering_method.mobile="gl_compatibility"`.

4. **Drop in a probe harness.** Write a small script (`tools/probe.ps1` or
   `tools/probe.sh`) that invokes:
   ```bash
   godot --headless --path <project-dir> --script res://tests/probe_smoke.gd
   ```
   and **bounded-kills** the process (e.g. after 300s). This is not optional:
   a GDScript runtime error mid-probe prints to stderr but never reaches
   `quit()`, so an unbounded wait wedges your whole CI/verification gate on
   that one crash. Pair it with a minimal `tests/probe_smoke.gd` that loads
   the main scene and calls `quit(0)`.

5. **Reach for existing art before hand-rolling.** Check whatever free/
   commercially-safe asset catalog you maintain (Kenney assets, the Godot
   Asset Library, store.godotengine.org) before building a custom prop from
   scratch. Reserve custom asset generation (parametric or hand-modeled) for
   things that genuinely aren't in a catalog.

6. **Init git** with a `.gitignore` covering at minimum:
   ```
   .godot/
   .import/
   export/
   *.translation
   ```
   `.translation` files are regenerated by the editor and churn the tree if
   tracked. Keep the project root clean — source under the project directory,
   tests in `tests/`, scripts in `tools/`.

7. **Verify before calling it done.** Run the probe against
   `probe_smoke.gd`. The scaffold is finished when the probe exits 0 *and*
   the project opens headless with zero config errors — not before either
   condition is met.

8. **Record the decisions.** Slug, package id, and ship target are exactly
   the kind of thing you'll forget by the next session — write them down
   somewhere durable (a project README, a canon/design doc, whatever your
   own note-keeping system is). A full product/design doc is a good next
   step, but that's a separate, deliberate decision — don't auto-generate one
   as a side effect of scaffolding.

## Reference

- **Engine binary**: pin an explicit, console-subsystem path. Don't depend on
  a package-manager shim/launcher link — it's GUI-subsystem (breaks headless
  invocation) and version-drifts on every upgrade.
- **Android blank "config errors"** ⇒ almost always
  `import_etc2_astc=true` missing from `project.godot`'s `[rendering]` block.
  Check this first before chasing anything else.
- **Package-id convention**: pick your reverse-domain slug once; persisted
  ids are effectively permanent once you have save data or a store listing
  attached to them.
- **Shipping is a separate step.** This skill produces a project that boots
  green — packaging and store submission (Play, Steam, your own catalog, a
  niche hardware platform) is a distinct workflow with its own gates
  (signing, store policy, privacy scrub) and shouldn't be conflated with
  scaffolding.
