Hot reload: keep playing while you edit
When you change a line and save, your game should keep running - score, position, and colors still where you left them. That is hot reload. New games from...
Written for blit386 1.8.0. The rest of blit386.dev documents the newest engine, so an API you find there may be missing from a game pinned to 1.8.0.
When you change a line and save, your game should keep running - score, position, and colors still where you left them.
That is hot reload. New games from create-blit386 already wire it up in vite.config.js. You do not have to write any
special code for the basic case.
What you get for free
With the blit386 Vite plugin in place (it ships in the starter vite.config.js):
- Edit
update()orrender()and save - the new code takes over; your game state stays put. - Edit a PNG, a sound, or a
.btfontunderpublic/- the running game swaps that asset in place. No reload. - A broken save that makes
init()fail leaves the previous game running, so you can fix the typo without losing the session.
Hot reload only works while npm run dev (or npx blit run) is running. A production build (npm run build) never
includes it.
The three kinds of save
Not every edit is the same:
- Method-only change - you edited
update(),render(), or a top-level constant those methods use. The running game keeps every field (this.score,this.pos, …). This is the common case. - Re-init - you edited
init(), the constructor, or a class field initializer. The engine builds a fresh instance and runsinit()again. Without extra code, fields reset to whateverinit()sets. OptionalonHotReloadlets you copy important values across (see below). - Full page reload - you changed something in
configure()that rebuilds the screen or audio graph (displaySize,backend,targetFPS,audioVoices, overlay flags, and friends). The page reloads because those settings cannot be swapped live.
Keep state across a re-init
Only needed when you edit init() a lot and care about values like score. Add an optional method on your game class:
onHotReload(context) {
// Only restore after a re-init (not after a method-only swap).
if (context.reason !== 'reinit' || !context.snapshot) {
return;
}
if (typeof context.snapshot.score === 'number') {
this.score = context.snapshot.score;
}
}context.snapshot holds the previous instance's own fields, captured just before the new init() ran. Skip fields you
want init() to reset on purpose.
Check that the plugin is there
Your vite.config.js should look like this:
import { defineConfig } from 'vite';
import { blit386 } from 'blit386/vite';
export default defineConfig({
plugins: [blit386()],
});New games from create-blit386 already ship with that. Older games can pick it up as a nice surprise:
npx blit upgrade # installs the latest engine, then offers migrate
npx blit migrate --write # also enables hot reload in vite.config when missingblit migrate / blit upgrade rewrite a standard Vite defineConfig({...}) to add the import and
plugins: [blit386()]. Restart the dev server once after that, then save a file - the game should keep playing. If your
vite.config is unusual, add the two lines by hand (this page) or ask your AI assistant (the use-hot-reload skill).
The plugin needs blit386 1.4.0 or newer.
What still forces a full reload
- Changing
configure()hardware settings (see above). - Rebuilding or upgrading the
blit386package itself. - Editing a file under
public/that the plugin does not recognize as an image, audio, or.btfont(by default that reloads the page).
Telling a dev build from a release build
Installing the plugin above also gets you BT.isDevMode (blit386 1.5.0+) - true while npm run dev is running the
game, false once you npm run build it. Use it to gate things you only want while developing:
update() {
if (BT.isDevMode) {
console.log('dev build - extra logging on');
}
}Read it inside update() or render(), not at the top of a file - the plugin marks the build as dev after the rest of
your entry file has already run, so a check outside those methods can see false even while developing.
See the use-dev-mode skill for cheat-key and debug-HUD examples.
Next: docs/basics.md for the game loop, docs/when-something-breaks.md if a save did something unexpected.