Skip to main content

Culling

Viewport culling skips elements whose bounding box falls outside the visible area, so frame cost scales with what is on screen rather than the total scene size. It is driven entirely through renderScene options in @oh-just-another/renderer-core.

Enabling viewport cullingโ€‹

Pass a world-space viewport rectangle in RenderSceneOptions. Shapes whose AABB does not intersect that rectangle are skipped. Inflate the rect slightly to avoid pop-in during a pan โ€” VIEWPORT_CULL_PADDING_RATIO (0.05 = 5% per side) is exported so you can tune the inflation in one place.

import {
renderScene,
VIEWPORT_CULL_PADDING_RATIO,
type RenderSceneOptions,
} from "@oh-just-another/renderer-core";

const pad = viewportWidth * VIEWPORT_CULL_PADDING_RATIO;
const viewport = {
x: camera.x - pad,
y: camera.y - pad,
width: viewportWidth + pad * 2,
height: viewportHeight + pad * 2,
};

renderScene(scene, target, { viewport });

renderScene(scene, target, options) takes no separate camera argument โ€” the world-to-screen transform comes from scene.viewport.

Spatial index for large scenesโ€‹

For very large scenes, pass a pre-built spatialIndex (a SpatialGrid from @oh-just-another/scene) alongside viewport. The renderer then queries the index for candidate shapes instead of scanning every layer โ€” it starts to pay off around ~10k shapes.

Bounds cache and dirty rectanglesโ€‹

boundsCache (an ElementCache<Bounds>) shares AABB computations across frames, hit-testing, and overlay drawing. When only a small region changed, pass a world-space dirtyWorld rectangle so the renderer clips to that region and skips shapes outside it.

import { ElementCache, renderScene } from "@oh-just-another/renderer-core";
import type { Bounds } from "@oh-just-another/types";

const boundsCache = new ElementCache<Bounds>();
renderScene(scene, target, { viewport, boundsCache });

These options compose: combine viewport, spatialIndex, boundsCache, and dirtyWorld to cull aggressively while reusing work across the editor, hit-test, and overlay passes.