Performance Guidelines
Open the editor to profile performance live.
These are practical targets, not hard engine limits. The runtime does not enforce budgets.
Frame Time
At 60 FPS you have ~16.6ms per frame. Clearing, grid, and primitives usually cost a little; most of the budget is your physics.
Suggested Object Counts
| Primitive | Comfortable | Stress zone | Notes |
|---|---|---|---|
particles | ≤ 500 | ~2,000 | arc + fill each |
lines | ≤ 1,000 | ~3,000 | Path + stroke each |
vectors | ≤ 200 | ~500 | Line + arrowhead |
circles | ≤ 300 | ~1,000 | Arc + optional fill |
arcs | ≤ 200 | ~500 | Arc + stroke |
bars | ≤ 100 | ~500 | fillRect + label |
text keys | ≤ 10 | ~20 | Single HUD panel |
TIP
Prefer fewer particles or shorter trails over exotic draw tricks. Cap arrays early.
dt Clamping
dt is capped at 0.05s. If the tab was idle for seconds, the next step is still at most 50ms — the sim slows rather than teleporting.
Optimization Patterns
Cap trails
javascript
state.trail.push({ x: state.x, y: state.y });
if (state.trail.length > 200) state.trail.shift();Cull off-screen draws
javascript
const visible = state.particles.filter(
(p) => p.x > -50 && p.x < w + 50 && p.y > -50 && p.y < h + 50
);Pool particle objects
javascript
function spawn(x, y) {
const p = state.pool.pop() || {};
p.x = x; p.y = y;
p.vx = (Math.random() - 0.5) * 100;
p.vy = -100;
p.life = 1;
state.particles.push(p);
}Measure FPS in the HUD
javascript
if (!state.fpsAccum) { state.fpsAccum = 0; state.fpsCount = 0; }
state.fpsAccum += dt;
state.fpsCount++;
if (state.fpsAccum >= 1) {
state.lastFPS = state.fpsCount / state.fpsAccum;
state.fpsCount = 0;
state.fpsAccum = 0;
}
return {
text: {
FPS: (state.lastFPS ?? 0).toFixed(0),
dt: (dt * 1000).toFixed(1) + 'ms',
},
};WARNING
If FPS drops, profile your loops first (distance checks, N² boids). Drawing is rarely the only bottleneck.
Memory
- Unbounded
statearrays grow forever — the engine never trims them. - A few hundred trail points is fine; tens of thousands can cause GC pauses.
- The module registry is created once per compile — not a concern.
Keep arrays capped and recycle when spawning/despawning often.