Guides
Rendering Modes

Rendering Modes

Two independent choices decide where the canvas lives and how big it is.

mode — where the canvas goes

overlay (default)

The canvas is mounted as the first child of the target's parent and stacked over the original content. pointer-events is none, so every click passes through to the real DOM underneath.

new Mirage(target, { mode: "overlay" });

Use it when you want to replace the look of live UI while keeping it fully interactive. Pair it with data-mirage-dom="hide" so the user sees only the WebGL version.

duplicate

The canvas is mounted into a separate container and shows a copy of the target. The original stays visible where it is. pointer-events is auto, because the copy is what the user actually looks at.

new Mirage(target, {
  mode: "duplicate",
  container: document.querySelector("#preview") as HTMLElement,
});

If you omit container, it falls back to the target's parent.

Use it for previews, thumbnails, mini-maps, or a stylized second view of the same content.

Comparison

overlayduplicate
Canvas positionfixed or absolute over the targetNormal flow inside container
pointer-eventsnoneauto
Original DOMUsually hidden with data-mirage-domStays visible
canvasSize optionAppliesIgnored (always the target's box)
Typical useShader-skinned live UIPreview / second view

canvasSize — how big the canvas is

Only meaningful in overlay mode.

viewport (default)

The canvas is sized to window.innerWidth/Height plus a 200 px overscan margin on each side, and pinned with position: fixed at -200px, -200px.

Meshes are positioned in viewport space and scroll is applied as an offset. Off-screen content still exists in the scene graph but costs almost nothing to rasterize.

new Mirage(target, { mode: "overlay", canvasSize: "viewport" });

The overscan margin is what stops elements from popping in at the edges during fast scrolling.

document

The canvas matches the target's full bounding box and is positioned absolute at the target's offset.

new Mirage(target, { mode: "overlay", canvasSize: "document" });
⚠️

A 12,000 px tall page means a 12,000 px tall framebuffer — multiplied by devicePixelRatio and by quality. This exceeds MAX_TEXTURE_SIZE on many GPUs and will drop frames or fail to allocate. Only use document when an effect genuinely needs to sample content outside the viewport.

viewportdocument
Canvas sizeWindow + 400 pxFull target box
CSS positionfixedabsolute
Cost on long pagesFlatGrows with page height
Texture cullingEnabledDisabled
Best forScrolling pagesShort, fixed-height sections

Texture culling via IntersectionObserver is only enabled when mode === "overlay" and canvasSize === "viewport". In any other combination every image texture stays resident.

Choosing

  • Full-page shader treatment on a scrolling site → overlay + viewport
  • A hero section with a fixed height and a refraction effect → overlay + document
  • Live preview panel next to an editor → duplicate

Mirage Engine — MIT Licensed © 2026 dltldn333