Performance
The engine is optimized to handle large datasets without lag. This page explains the internal optimizations that make this possible.
Automatic Optimizations
These optimizations happen automatically—you don't need to configure anything.
Viewport Culling
Only items within the visible viewport (plus a small buffer) are drawn. Items outside the view are skipped entirely.
┌─────────────────────────────────────┐
│ World (1M items) │
│ │
│ ┌───────────────┐ │
│ │ Viewport │ ← Only these │
│ │ (500 items) │ are rendered │
│ └───────────────┘ │
│ │
└─────────────────────────────────────┘
Spatial Indexing (R-Tree)
For large datasets (500+ items), the engine uses RBush, an extremely fast R-Tree spatial index.
Without R-Tree: To find visible items, every single item must be checked → O(n)
With R-Tree: Only items in the viewport region are queried → O(log n)
The R-Tree is built automatically when you call drawRect, drawCircle, or drawImage with an array of items.
Style Batching
When multiple items share the same style, the engine batches them to reduce canvas state changes:
// These are batched internally (single fillStyle set)
engine.drawRect(
[
{ x: 0, y: 0, style: { fillStyle: "#ff0000" } },
{ x: 1, y: 0, style: { fillStyle: "#ff0000" } },
{ x: 2, y: 0, style: { fillStyle: "#ff0000" } },
],
1
);
Manual Optimizations
For specific use cases, you can enable additional optimizations.
Static Caching
For scenarios where all items are visible at once, use static caching to pre-render content to an offscreen canvas.
// Pre-render items once
engine.drawStaticRect(items, "cache-key", 1);
See Drawing & Layers → Static Caching for details.
Performance Tips
Do
- Use arrays for batch rendering instead of calling
drawRectin a loop - Use static caching when all items need to be visible with dragging enabled
- Reuse style objects when possible to help style batching
// Good - single call with array
engine.drawRect(items, 1);
Avoid
- Calling draw methods in a loop - use arrays instead
- Creating new style objects per item when they're identical
// Bad - 1000 separate calls
for (const item of items) {
engine.drawRect(item, 1);
}