Rebuilds my entire Godot development environment from a single clone.
git clone git@github.com:<you>/games-toolkit.git ~/games/toolkit
~/games/toolkit/bootstrap.shThat installs the engines, restores every game repo, wires up the commands, and creates the directory tree. Re-running is a fast no-op, so it is also the upgrade path.
Engines supported: Godot (installed automatically) and Unreal (a guided manual install — Epic do not permit scripted downloads).
~/games/
├── toolkit/ this repo -- the only thing you need to clone
├── engine/ one dir per engine, then per version: engine/godot/4.7.1/
├── projects/ one git repo per game (small: no caches, no authoring files)
├── library/ shared asset warehouse -- NOT in git
├── source/ .blend/.psd/.aseprite/masters, per game -- NOT in git
├── exports/ builds -- NOT in git
└── sandbox/ throwaway prototypes, no repo
Repos stay light because the three heavy categories live outside them:
.godot/ (regenerable, often GBs), authoring files (a 40 MB .psd becomes a
200 KB .png in the project), and builds.
library/ is the unimported warehouse. Copy what a game needs into that
game's assets/ — do not symlink, because Godot's importer follows the link
and writes .import metadata that then disagrees across projects.
toolkit/
├── bootstrap.sh START HERE -- builds or updates this machine
├── doctor.sh report drift, change nothing
├── snapshot.sh rewrite config/projects.tsv from what is on disk
├── sync.sh move library/ and source/ to and from a remote
├── bin/ the commands you type day to day (this dir is on PATH)
├── lib/ code the commands call -- one subdirectory per runtime
│ ├── sh/ bash libraries, sourced not executed
│ │ └── engines/ one file per engine: install, verify, launch, scaffold
│ ├── blender/ python run *by* Blender, headless
│ ├── godot/ gdscript run *by* Godot, headless
│ └── mixamo/ the Mixamo API client
├── config/ settings you edit, plus the project list
│ └── engines/ one file per engine: versions, checksums, paths
├── templates/ what gets copied when something new is created
│ ├── godot/ starter Godot project, dotfiles, per-character scripts
│ └── unreal/ starter Unreal project (C++ only, no binary assets)
├── devblog/ one entry per feature -- why, not what
└── docs/ the long-form guides
Two rules explain the split, and everything follows them:
- Root
*.shacts on the machine — installing engines, restoring repos, moving the asset warehouse. You run these by path, from a clone. bin/*acts on one project or one asset. No extension, on your PATH, named<subject>-<action>so related commands sit together inls.
This machine
./bootstrap.sh |
build or update this machine |
./bootstrap.sh --check / ./doctor.sh |
report drift, change nothing |
./bootstrap.sh --no-templates |
skip the ~1 GB export templates |
./snapshot.sh |
regenerate config/projects.tsv from disk |
./sync.sh {pull,push} |
move library/ and source/ to/from a remote |
Games
game-new NAME [--engine godot|unreal] |
scaffold a project, git repo, and config entry |
gd |
open the current Godot project with its pinned version |
gd --version-list |
installed Godot versions |
ue build / ue run / ue |
build, play, or open the editor on an Unreal project |
ue info |
which engine and paths a project resolves to |
devblog-new "title" |
start a devblog entry |
Characters — char-<TAB> lists the whole family
char-pipeline NAME --from FILE --project GAME |
model → rigged, animated Godot character |
char-pipeline NAME --status |
which pipeline stages are done |
char-prep NAME --from FILE |
clean a model for Mixamo's auto-rigger |
char-clips NAME --pack locomotion |
download animation clips (--manual to do it by hand) |
char-pack NAME |
merge rig + clips into one .glb |
char-import NAME GAME |
import it and generate the character scene |
char-pipeline takes a downloaded 3D model and produces a Godot scene with a
working AnimationTree. Four of its five stages are automatic; stage 2 is
Mixamo's browser-only auto-rigger, where the pipeline stops, tells you what to
click, and resumes when the rigged file appears.
char-pipeline knight --from ~/Downloads/knight.glb --project survival-poc
# ... stops, you rig it on mixamo.com, save the download into 20-rig/ ...
char-pipeline knight --project survival-pocWorking files live in library/models/<name>/ in numbered stage folders, so
ls shows how far a character got. Only the final .glb enters a game repo.
Full walkthrough, glossary and troubleshooting: docs/rigging-pipeline.md.
Every feature that lands gets an entry in devblog/ —
why it is shaped the way it is, what was rejected, and what is known to be
shaky. Git history covers what changed; that folder covers what the diff cannot
say. Start one with devblog-new "title".
An engine is two files: config/engines/<name>.conf for its settings and
lib/sh/engines/<name>.sh for how to install, verify, launch and scaffold it.
Nothing else in the toolkit knows one engine from another — bootstrap.sh,
snapshot.sh and game-new all go through the dispatcher in
lib/sh/engine.sh. Adding a third engine is those two files plus a line in
ENGINES.
Each project records what it needs in a .engine file (godot 4.7.1), which is
what gd and ue read to pick the right engine and version. Godot projects
also keep .godot-version for backwards compatibility.
ENGINES_AUTO_INSTALL in config/engines.conf controls what bootstrap fetches
unprompted. Unreal is deliberately not in it: the Linux build is a ~25 GB
download behind an Epic account login, so bootstrap.sh reports whether it is
present and prints instructions rather than pretending it can fetch it.
Everything in config/ is either settings you edit or a list the toolkit
keeps. Both are plain text and both belong in git.
config/engines.conf— which engines this machine wants.config/engines/godot.conf— Godot versions + sha512 checksums. To upgrade, add the version, setGODOT_DEFAULT, record its sum from the release'sSHA512-SUMS.txt, commit, then pull and re-run bootstrap everywhere.config/projects.tsv—name, git remote, engine, version. Regenerate with./snapshot.sh; never hand-edit except to add a repo not yet cloned. Rows written before multi-engine support had three columns and are read as Godot.config/engines/unreal.conf— Unreal version and install path. PointUNREAL_ROOT_<version>at an existing install inmachine.local.shrather than moving it.config/structure.conf— directories to guarantee.config/rigging.conf— character pipeline settings: Blender location, target height, clip packs, blend-space speeds.config/clipmap.tsv— canonical clip names ↔ Mixamo animation names, and whether each one loops.machine.local.sh— gitignored per-machine overrides. Seemachine.local.sh.example.
The failure mode for a repo like this is creating a game, forgetting to record
it, and finding out six months later on a new machine. Two guards:
bootstrap.sh warns about any project on disk that is missing from
config/projects.tsv, and snapshot.sh rewrites that list from reality.
game-new handles it automatically.
library/ and source/ are excluded from git on purpose — they are the
reason the repos stay small — so a fresh machine gets the tree and no content.
Set SYNC_REMOTE in machine.local.sh and use ./sync.sh pull. Bootstrap
prints a reminder when those directories are empty.
exports/ does not matter; rebuild it.
Each project holds a .godot-version. gd reads it and launches that exact
engine, so opening a 4.7 project with 4.8 — which rewrites files
irreversibly — cannot happen by accident.
Engines run in Godot's self-contained mode (a ._sc_ file beside the binary),
so editor settings and export templates live in engine/<version>/editor_data/
rather than ~/.local/share/godot/. Versions are fully isolated; uninstalling
is rm -rf.