Example project
Ripple Pond — adopting Gododin in an existing game
examples/ripple_pond/README.md
A tiny complete Godot game that teaches one full incremental adoption: a working GDScript game keeps its scene, its rendering, and its optimized GDScript baseline, and moves its one substantial batch operation — the per-frame wave-equation step over the pond grid — into a pure Odin package behind one small native class.
The example directory is the adopted game. game/ beside it is the same
game as it existed before adoption, kept runnable so every delta adoption
made is visible and diffable.
The game
Click the water to splash it; waves reflect, interfere, and settle. In the
adopted version, keys 1 and 2 switch which arm steps the water each
frame:
- GDScript — the preserved baseline (
gd_ripples.gd, byte-identical ingame/and here): the same fixed-step wave equation on two packed f64 buffers with one integer write per cell. - Odin (native) — the same arithmetic in
subsystem/pond.odin, reached through the scene'sRipplePondnode: onestepcall and one coarseframe_bytescall per frame, no per-cell foreign calls.
Both arms run the identical f64 expression sequence, so the water is
byte-for-byte identical — tests/oracle.gd proves it — and the example
makes no performance claim. The on-screen per-step milliseconds are a
host-local observation; measured, fair language comparisons are their own
workload (see the repository's comparison plans), not a claim this example
makes.
Requirements
One extracted immutable Gododin SDK, the exact locked Odin compiler, and the
exact pinned Godot executable named by the SDK's gododin.lock — the same
prerequisites as the other examples (examples/setup.sh wires every example
at once, including this one). No machine-local sibling folders, no private
environment variables, no copied manifests.
Run and test
The five-chapter usage guide teaches adoption, authoring, iteration and export; setup covers installation. This README owns the example's controls, modes, source map and retained journey evidence.
Use shared example setup to connect this configured project to its matching SDK, compiler and engine, then run:
cd examples/ripple_pond
./test.sh # pure kernel, before/after game discipline, pipeline, oracle
./test.sh play # public launcher, interactive windowed game
./test.sh oracle # public launcher, headless byte/signal oracleModes are all (default), subsystem, game, pipeline, oracle and play.
The oracle requires GODODIN_RIPPLE_ORACLE_PASS (600 frames, six byte
checkpoints and six signal deliveries), GODODIN_RUN_PASS and zero Host
owners. Its exit status is the application test result; it measures no speed.
GODODIN_PROFILE=release ./test.sh selects a release pipeline build. Currently
oracle and play invoke public run without --profile, so those two modes
still launch debug even if that environment variable is set. To test/run
release, use the public profile-aware commands
with this example as project. Do not infer the launch profile from the shell
variable; inspect GODODIN_RUN_IDENTITY.
To replay adoption, the guide starts from a copy of game/. To inspect the
change here, compare game/main.tscn and game/main.gd with the root versions:
one native RipplePond child and the native arm/signal wiring are added;
project.godot and the GDScript baseline remain byte-identical.
File responsibilities
| File | Owns |
|---|---|
game/ |
the before state — never touched by adoption, kept for the diff |
project.godot, main.tscn, main.gd, gd_ripples.gd |
the game: scene, input, HUD, rendering, GDScript baseline |
tests/oracle.gd |
the application test: native vs GDScript byte oracle |
declarations/ripple_pond.odin |
the authored class — the single source for the native surface |
subsystem/pond.odin (+ _test) |
the pure kernel and its ownership/determinism tests |
generated/ |
the generated catalog, bridge and docs; generate publishes the current bundle, and its output is never hand-edited |
gododin.toml, gododin.lock |
portable intent; exact accepted identities |
Journey record
Executed end to end on Windows x86-64 (development-host evidence under the
desktop workstream; the installed attach flow itself carries the recording
host's evidence): checkout authority over an adopted copy of game/,
gododin init reporting mode=adopted with the game's three files
byte-identical, doctor/generate/check green (one class, 11 operations,
one property, one signal), accepted debug and release builds, the oracle
passing through the public launcher (frames=600 checkpoints=6 signals=6,
zero owners), both profiles exported and the exported applications executed
with their identity environment and zero-owner shutdowns, and one native
editor reload cycle observed clean end to end. Friction found and recorded:
gododin init's template still hardcodes .dylib library names and a
macOS target row on every host (a Windows/Linux consumer renames them —
this example's committed files use the suite's recording-host shape), and
the gododin generate/check lifecycle path needed two Windows fixes that
landed with this example (mixed-separator managed-Odin paths and the
generate stage's symbol-tool resolution); both are recorded in the platform
migration record pending the next SDK reseat. The committed generated/
starts as the init skeleton: one gododin generate on a host with the
selected SDK publishes the bundle this directory's committed toml binds.