Skip to content

Spans and engines ​

Myaku sees the game loop from the outside: the frame callbacks, the canvas context and what the browser reports. It doesn't know that your loop runs physics, then AI, then rendering. Spans tell it.

ts
import { myaku } from "myaku";

const profiler = myaku();

function update(dt: number) {
  profiler.span("physics", () => world.step(dt));
  profiler.span("ai", () => enemies.think(dt));
}

For work that crosses callbacks, use begin:

ts
const end = profiler.begin("pathfinding");
await findPath(start, goal);
end();

Spans show up in each frame (frame.spans), in verdicts ("Spans: physics 22 ms, ai 6.0 ms") and in the report, as average milliseconds per frame. Myaku keeps up to 16 span names.

Engine spans, automatically ​

Myaku already adds update and render spans for the engine's own loop, so a slow frame says whether game logic or drawing took the time:

EngineHowSpans
PixiJS 8Automatic, through Pixi's devtools hookupdate (your ticker listeners), render
three.jsAutomatic, through three's devtools hookrender
Phaser 3, or Phaser from a script tagAutomatic, through the global Phaserupdate, update:<scene key>, render
Phaser 4 (ES modules), or anything elseadapt(profiler, game)Same as above
debuffdebuff devupdate, render

Phaser 4's ES module build has no global, so hand it the game:

ts
import { adapt, myaku } from "myaku";

const game = new Phaser.Game(config);
adapt(myaku(), game);

Spans can nest: update:level is part of update. Turn engine spans off with myaku({ engines: false }).

Add your own spans inside them to go further.

Engine guides: Phaser · PixiJS · three.js

Your own spans in Phaser ​

Phaser owns the loop, so wrap your scenes' update:

ts
class Level extends Phaser.Scene {
  update(time: number, delta: number) {
    profiler.span("level", () => this.tick(delta));
  }
}

Your own spans in PixiJS ​

Wrap individual ticker callbacks:

ts
app.ticker.add((ticker) => profiler.span("game", () => game.update(ticker.deltaMS)));

Your own spans in three.js ​

ts
renderer.setAnimationLoop(() => {
  profiler.span("update", () => update());
  profiler.span("render", () => renderer.render(scene, camera));
});