Odin + Raylib starter with hot reload, save-triggered rebuilds, and an in-game debug overlay. Ships as native desktop (macOS, Windows) and web (itch.io) at 1280×720.
Built on top of karl-zylinski/odin-raylib-hot-reload-game-template (MIT). See LICENSE.
- Odin compiler on
PATH. - macOS: fswatch for
watch.sh—brew install fswatch. - Windows: nothing extra —
watch.batuses built-in PowerShell. - Web build: Emscripten SDK.
./build_hot_reload.sh run # build and launch
./watch.sh # in a second terminal: rebuild on savebuild_hot_reload.bat run
watch.bat- Install emsdk. The scripts look in
$HOME/repos/emsdk(macOS) andc:\SDK\emsdk(Windows) by default. If yours lives elsewhere, either editEMSCRIPTEN_SDK_DIRat the top ofbuild_web.sh/.bat, or just putemccon yourPATH. ./build_web.shorbuild_web.bat.cd build/web && python3 -m http.serverand open http://localhost:8000.
You can't open build/web/index.html directly — browser CORS rules block wasm loading from file://.
| Key | Action |
|---|---|
| WASD / arrows | move |
| F3 | toggle debug overlay |
| F4 | pause simulation (overlay stays live) |
| F5 | force hot reload |
| F6 | force full restart (re-runs game_init) |
| Esc | quit |
game_hot_reload.bin / .exe is a host that stays running. source/game.odin compiles to a shared library (game.dylib / .dll) in build/hot_reload/, and the host reloads it whenever the file changes on disk. Game_Memory is preserved across reloads — tweak proc bodies, constants, or add new procs without losing game state.
If you change the size of Game_Memory, the host detects it and calls game_init from scratch. One-time state-reset per struct change.
watch.sh / watch.bat re-runs the build script on every .odin save so the full loop is: save in your editor → game updates in ~1 second.
source/
game.odin reloadable game logic
main_hot_reload/ dev host
main_release/ desktop release entry
main_web/ emscripten entry + JS glue
assets/ sprites, sounds, music (empty; add yours here)
vendor/raylib/wasm/ prebuilt wasm libs for web build
build_hot_reload.{sh,bat} dev build
build_release.{sh,bat} optimized desktop build
build_web.{sh,bat} wasm build
watch.{sh,bat} save-triggered rebuild
ols.json OLS config (portable, shared)
project.sublime-project Sublime Text build system
.zed/launch.json Zed debug config (gitignored, per-machine)
Install the ols language server. ols.json is auto-picked-up; ols discovers its core / vendor collections by running odin root. Debug via .zed/launch.json (LLDB targeting the hot-reload binary).
Install LSP + LSP-odin via Package Control. Open project.sublime-project. Ctrl/Cmd+B triggers build_hot_reload. Compile errors are click-navigable.
Attach to game_hot_reload.exe for native debugging with hot reload. The build script outputs a fresh PDB per reload, so the debugger stays in sync across swaps.
draw_debug_overlay in source/game.odin uses raygui (already part of vendor:raylib). Values live inside Debug_State which is nested in Game_Memory, so tunings survive hot reload. Add more controls by extending the struct:
rl.GuiCheckBox({16, 180, 16, 16}, "god mode", &g.debug.god_mode)
rl.GuiSlider({70, 200, 120, 16}, "spawn rate",
fmt.ctprintf("%.1fs", g.debug.spawn_rate),
&g.debug.spawn_rate, 0.1, 5)See raygui.odin in Odin's vendor:raylib for the full control list.
1280×720 on both desktop and web.
- Desktop:
rl.InitWindow(1280, 720, ...)ingame_init_window. - Web: canvas is locked at 1280×720 in
source/main_web/index_template.htmlwithimage-rendering: pixelatedand CSSmax-width/height: 100vw/vhfor letterboxed scaling inside itch's iframe.
PIXEL_WINDOW_HEIGHT :: 180 sets the camera zoom — the game renders as if the viewport were 180 units tall (a 4× upscale at 720p). Tweak this to change the pixel-art feel.
- Desktop build:
./build_release.sh/build_release.bat→build/release/(optimized, no hot-reload host, assets folder copied alongside the binary). - Web build:
./build_web.sh/build_web.bat→build/web/. Zip the contents and upload as an HTML5 build on itch.io.
vendor/raylib/wasm/libraylib.a and libraygui.a are committed to this repo because Homebrew's Odin package ships an empty vendor/raylib/wasm/ directory, and other Odin distributions are inconsistent. If the Odin toolchain updates and the raylib ABI shifts, re-fetch from upstream:
curl -L https://raw.githubusercontent.com/odin-lang/Odin/master/vendor/raylib/wasm/libraylib.a -o vendor/raylib/wasm/libraylib.a
curl -L https://raw.githubusercontent.com/odin-lang/Odin/master/vendor/raylib/wasm/libraygui.a -o vendor/raylib/wasm/libraygui.aTemplate foundation: karl-zylinski/odin-raylib-hot-reload-game-template. Hot-reload design walkthrough: http://zylinski.se/posts/hot-reload-gameplay-code/