platform: Cx.perf_monitor — per-frame ring (240) of paint-to-paint gap +
per-channel CPU us. Built-in channels: event dispatch (outermost, minus
app-attributed time), script exec, GC, pass encode, nextDrawable wait.
Apps register custom channels: cx.perf_monitor.channel("physics", rgb).
Off until enabled; hooks in event dispatch, macos repaint, metal draw_pass.
widgets: PerfGraph — corner-pinned live panel (DrawVector strips): frame-gap
bars colored against 120/60Hz budgets with guide lines, stacked per-channel
CPU, legend with averages. Self-positions bottom-right (DrawVector geometry
+ deferred turtle alignment don't mix — no aligning parent).
gamemaker: PerfGraph hovers the game pane (F3 toggles), engine feeds script
+ physics channels (incl. hot-reload evals); engine text overlay moved to
F4; per-phase engine window kept for ag perf / AIGAME_PERF=1; new 'ag perf'
harness verb + template guidance (template CLAUDE.md force-added: runtime
resource, blanket CLAUDE.md gitignore had kept it untracked).
Measured on my-game-5: engine frame CPU ~0.3ms; the hiccup is frame pacing —
the 8ms NSTimer paint clock beats against the 120Hz display, the drawable
pool drifts full and nextDrawable blocks the main thread in a ~25-frame
sawtooth (avg 2-3.4ms, spikes 20-30ms). The graph shows it as red ramps.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2.9 KiB
PROJECT_NAME — a kid's game, live inside Makepad
A child asks for changes by voice through the Game Maker app; you make them by
editing game.splash — the whole game is that one file, a Makepad splash
script evaluated live. Every clean edit hot-reloads the world the kid is
watching, instantly, while you keep working. A broken edit never replaces the
running game — the last working world stays up and the error waits for you in
./tools/ag errors.
The complete game.* API reference is in your system prompt (the Splash
Game DSL Guide). Verbs not listed there do not exist. This file is the
project-local workflow.
Checking your work — ALWAYS
- After every edit run
./tools/ag errors. Empty = your edit is live in front of the kid. An error = the kid still sees the OLD world; fix it. (Broken edits and runtime crashes are also reported back to you automatically as a "⚠ game error" message — butag errorsafter each edit remains YOUR check; don't wait to be told.) - To playtest:
./tools/ag test 120 tools/tapes/selftest.jsonrestarts the game, replays the frame-numbered input tape, and writes.agent/sheet.png(a grid of frames over time) +.agent/probe.txt(pos/vel of probed tags every 15 frames). Read the image, and read the numbers — "the jump clears the step" should be a probe line you saw, not a hope. ./tools/ag peek= 4 screenshots of the live game + entity state, without interrupting the kid../tools/ag logstails the game log (yourgame.log()lines + eval reports).- If the game feels slow:
./tools/ag perf— per-phase frame profile (script, physics, draw). Keep script under ~2ms; ifwaitdominates, it's not your game's fault, leave it be.
Tapes are JSON: {"probe": ["player"], "events": [{"f":5,"press":"right"}, {"f":30,"press":"jump"},{"f":33,"release":"jump"}]} — actions are the input
names (left right up down jump shoot grab). Same tape, same frames: runs are
repeatable.
House style
- Everything is procedural: colored shapes and synthesized sound. No image, model, or audio files — no files besides game.splash.
- Give creatures a face (
game.parteyes) and a name (game.label), and give actions sounds (game.sfx) — without being asked. That's what makes it real. - Outdoor game?
game.sky({})+game.terrain({smooth: true, bands: [...]}). - Small, visible changes. Tune constants and add shapes; avoid big rewrites.
- Movers are ~0.8×1.6×0.8. Keep the playfield within the terrain you built.
Gotchas
- Hex colors containing the letter
eneed the#xprefix:#x2ecc71. letandfngo at the TOP of the file, before other statements.- The file re-runs from the top on each edit — don't accumulate state across
edits.
game.time()restarts at 0 on every reload. on_touchfires every overlapping tick — latch or remove, or you'll play 60 win jingles a second.