Reading verdicts
A frame is a hitch when its interval, the time until the next frame, is over budget. The budget defaults to 1.5× the display's frame interval: 25 ms at 60 Hz, 12.5 ms at 120 Hz, 9.1 ms at 165 Hz. Myaku measures the display from the first frames, and ignores throttled stretches while it does.
Each hitch gets a verdict:
{
"frame": 1204,
"intervalMs": 79,
"budgetMs": 9.1,
"cause": "script",
"confidence": "high",
"summary": "Frame 1204 took 79 ms (budget 9.1 ms). 80 ms was script: `spawnWave` in src/enemies.ts:88.",
"hint": "This ran inside the game loop. Profile the function in the Performance panel, or spread the work over several frames.",
"where": { "source": "http://localhost:5173/src/enemies.ts", "fn": "spawnWave", "line": 88, "char": -1 }
}confidence is high when direct evidence names the cause, medium when it's strongly suggested, and low when it's a lead to check, not an answer. Each verdict also carries its evidence: frame code time, draws, uploads and bytes, compiles, heap drop, layout time, scripts and spans.
Myaku checks the causes in this order and stops at the first that fits.
hidden
The tab went to the background during the frame. Not a problem with the game. If the game shouldn't keep running after a long gap, pause it on visibilitychange.
throttled
A run of slow frames in which the game did almost nothing and the browser reported no long work. The browser was slowing frames down because the window was covered, minimised or in power-saving mode. Bring it to the front to measure.
compile
Shaders compiled or programs linked during play. The first use of a material or effect often does this. Warm shaders up while loading.
upload
A megabyte or more sent to the GPU in one frame: new textures, canvas textures (text is a common culprit) or large buffers. Upload in the load step, spread uploads over frames, and reuse textures.
script
The game's code ran long. In Chromium, Long Animation Frames entries name the function and file. When the slow code is a frame callback, myaku points at where the game registered it.
When an engine owns the loop, the slow callback is the engine's step function, so the verdict names the engine's file. Myaku's engine spans then say whether update or render took the time, and in Phaser which scene.
Without attribution (other browsers), a frame whose code took most of the budget is still a script verdict, with the spans that took longest.
layout
Style recalculation and layout took a large share of the frame. Look for DOM updates over the canvas every frame, or code that reads layout (offsetWidth, getBoundingClientRect) right after changing styles.
gc
The heap shrank by a megabyte or more while the game's code was mostly idle: garbage collection. Allocate less per frame. Reuse vectors and arrays (pools), and avoid closures and map/filter in hot loops. Chromium only, and only while the browser reports the heap finely enough. Myaku checks this, and when it can't see GC, unknown verdicts say so.
unknown
The game's code was quick and nothing else explains the time. It's often GPU work, the compositor or another app. With many draw calls (over 2,000), the hint suggests batching. One-off unknown frames are usually outside the game's control.
Frames within budget
Clicking or explaining a frame that wasn't slow gives ok, with its time and the budget.