Recording and CI budgets
npx myaku record plays your game in Chrome or Edge with myaku injected, then prints frame-time percentiles and the worst hitches, explained. Set a budget and it fails when the game goes over, so a frame-time regression breaks the build like a failing test.
npm run build
npx myaku record dist --seconds 20 --cpu 4 --p95 20 --hitches 6frames 1190 in 20.0 s · 60 fps · budget 25.0 ms
frame p50 16.7 ms · p95 17.1 ms · p99 33.2 ms · max 41.0 ms
code p50 3.1 ms · p95 6.4 ms
hitches 2 (6.0/min) · upload 1, script 1
worst hitches
upload · high Frame 812 took 41 ms (budget 25 ms). 3 uploads sent 12 MB to the GPU this frame.
Create and upload textures in the load step, or spread them over several frames.
budgets
✔ p95 frame time (ms): 17.1 (limit 20)
✔ hitches per minute: 6 (limit 6)It needs no changes to your game. Myaku is injected into the page as it loads, before the game's own scripts, so it works on production builds that don't include myaku.
What it records
- A folder (default
dist), served locally: your production build. - A URL: your dev server, a preview deploy or staging.
Without a play script, myaku records whatever the game does on its own: a title screen, an attract mode, a benchmark scene. To profile real play, add one.
Playing the game: --play
A play script is a module whose default export receives Playwright's page. Press keys, click buttons, wait:
// play.mjs
export default async function play(page) {
await page.mouse.click(400, 300); // press Play
for (let i = 0; i < 20; i++) {
await page.keyboard.press("Space");
await page.waitForTimeout(250);
}
}npx myaku record dist --seconds 10 --play play.mjsOptions
| Option | |
|---|---|
--seconds <n> | Seconds to record (default 10) |
--warmup <n> | Seconds to wait after load before recording, so start-up isn't counted (default 1) |
--cpu <n> | Slow the CPU down n times. 4 is roughly a mid-range phone |
--viewport <WxH> | Window size (default 1280x720), e.g. 390x844 for a portrait phone |
--play <file> | A play script (above) |
--headed | Show the browser window |
--p95 <ms>, --p99 <ms> | Fail when that percentile of frame time is over the limit |
--hitches <n> | Fail when there are more hitches per minute than this |
--json, --out <file> | The full report and budget results as JSON |
Exit codes: 0 within budget, 1 over budget, 2 error (no build, server not running, no browser).
In CI
# .github/workflows/perf.yml
- run: npm ci && npm run build
- run: npx myaku record dist --seconds 20 --cpu 4 --p95 22 --hitches 10 --out myaku.json
- uses: actions/upload-artifact@v4
if: always()
with: { name: myaku, path: myaku.json }Frame times depend on the machine. Run myaku a few times on the same CI runner, set budgets a little above what you see, and tighten them as the game gets faster. Hosted runners are noisy, so --hitches is a better tripwire than a tight --p99.
Myaku uses the Chrome or Edge installed on the machine (GitHub's Ubuntu runners have Chrome). Set MYAKU_BROWSER to a browser executable to choose one.