A game workshop with Claude living in it.
Three panes. On the left you ask for something. In the middle is the code, with every line that changed marked. On the right the game is already running it. The loop between having an idea and watching it move is about as short as it can be made.
One file. No build step. Nothing to install into your game.
Everything a game gets is a single object called G —
drawing, input, sound, saving, scenes, tweens, particles. It lives in one
readable file in your project, which means you can open it, and change it,
and it will still be there next year.
// the whole of a game that does something
G.watch('sparks', () => sparks.length)
function update(dt) {
const pull = G.tune('pull', 1.0, {min: 0, max: 3})
for (const s of sparks) s.a += s.s * dt * pull
}
function draw() {
G.clear('#08080b')
for (const s of sparks) {
G.circle(x, y, s.z, '#a78bfa')
}
}
| Runtime | One file, about 2,200 lines, plain JavaScript |
|---|---|
| Renderer | Canvas 2D |
| Build step | None. Save the file, the game reloads |
| Dependencies | None in the game. Nothing fetched at runtime |
| Input | Pointer events — mouse, pen and touch through one path |
| Export | One HTML file, or a folder with real assets |
| Desktop app | Windows. Built on Electron |
Most of the engine is about shortening the gap between a question and an answer.
Change a number while the game is playing
Any number a game passes to G.tune() becomes a slider in the
toolbar. Drag it and the running game changes under your hand — no reload,
no losing your place. Keep the value and it is written next to the project;
discard it and the code's own default stands. Nothing is ever rewritten
behind your back.
A profiler that names the fault
“It feels slow” is not something anyone can act on. perf
runs the real game for a few seconds and writes a report: frame times, how
many device pixels get shaded per frame against how many the canvas has, and
a ranked list of what to look at — blurred fills, gradients rebuilt every
frame, art scaled down from far larger sources. Mark up
draw() and it breaks the frame down by section.
The engine describes itself
state writes a snapshot of the running game:
frame rate typical and at the slow end, whether the engine has already
dropped render resolution to keep up, the save key by key, what is loaded,
how much is alive, and every error thrown with a plain-language read on what
it means. Games add their own numbers with G.watch(). It is also
captured the instant anything throws — so an error arrives with the state it
happened in, not with whatever the game looks like after two reloads.
Every turn is a checkpoint
The whole project is snapshotted before each change, and the diff view shows exactly which lines moved. If a turn went somewhere you did not want, one button puts it back. Nothing about that requires you to know what git is.
It plans for a machine that is not yours
A canvas costs roughly what it covers in device pixels, and that is the screen's density squared — a laptop at 150% is asking for 2.25× the work for a picture most people cannot tell apart in motion. So the engine watches its own frame times and quietly renders at a lower density rather than dropping frames. Saves survive their own schema changing, through declared migrations, because the moment a stranger has played your game the save on their machine is a contract.
Art and sound go in through the conversation
Drop a PNG or an MP3 into the chat and it lands in the project's assets, reachable by name. Generated images arrive the same way. The export packs them as real files beside the page rather than as base64 wedged into the HTML, which is smaller and starts decoding sooner.
The knob is the code.
G.tune('pull', 1.0) reads as an ordinary number to the game and
appears in the toolbar as a slider. There is no second copy of the value to
keep in sync, and no settings file to forget about.
Built in the open, not released yet.
The proof that it works is on the games page, playable in your browser, exported from this engine with one button.