Onceworlds
Engine · Testing

Test it without a browser

Headless tests with simulate, the chaos scenarios, and what check and doctor look at.

The engine runs with no DOM and no GPU. @onceworlds/engine/test is how you (and the AI tool building the game) check a game in seconds.

// test/match.test.js
import { simulate } from '@onceworlds/engine/test';
import { expect, test } from 'vitest';
import { config } from '../game.config.js';

test('a full match ends with everyone ranked, through a reloaded host and a dropped player', async () => {
  const run = await simulate(config, { humans: 2, bots: 2, seed: 7, minutes: 3, chaos: ['reload-host', 'drop-player'], latency: [10, 60] });
  expect(run.errors).toEqual([]);
  expect(run.ranking).toHaveLength(4);
});

What onceworlds check, doctor and the platform each look at

The lints

Each finding names the file and line and says what to write instead. They read the code's text, so they can be wrong: a comment // onceworlds-ignore <id> on the line (or the line above) silences one.

Id What it finds
sim-random Math.random(), Date.now() or performance.now() inside a system or a script's fixed hook
timers setTimeout or setInterval in game code (a Timer, node.timer or time.dt instead)
dom-in-system document, window or localStorage inside a system or a script hook
backend-import an import of three.js or Rapier
inner-html innerHTML, outerHTML, insertAdjacentHTML or document.write
host-state a system without authority: 'host' that writes a component the host owns (net: { owner: 'host' })
unbounded-spawn a system that spawns every step with no despawn or cap in sight, or a while (true)
big-file a script over 1,500 lines or 300 KB, an image over 2 MB or 4096 px, a sound over 3 MB
touch an action map nothing on a phone can use, or more than four touch buttons; and (a note) a button with no touch or an axis with no stick
how-to-play an engine game with no "controls" in onceworlds.json
contrast text colors too close to the background they are drawn on (under 3:1)

Budgets

check measures the first player's page during the simulated matches and compares the busiest moment with what each quality tier of the platform's Graphics setting can draw at 60 frames a second on the devices it is for (low: a phone from a few years ago, medium: a recent phone or a laptop, high: a desktop).

Per frame low medium high
2D draw commands 1,500 3,000 5,000
3D draw calls 150 300 600
3D lights 6 12 24
Physics bodies 150 300 500
Entities 4,000 8,000 15,000

Over the low budget is a note (phones will drop frames: batch with instanced meshes, merge static scenery, pool and despawn); over the high budget is a likely problem. Entities that keep growing to the end of a run are reported too: something is spawned and never despawned.