Reference
Configuration

Configuration

import type { MirageConfig } from "mirage-engine";

MirageConfig is the core config plus sandwich options:

type MirageConfig = CoreConfig & {
  sandwich?: boolean | SandwichConfig;
};
 
type CoreConfig = OverlayConfig | DuplicateConfig;

The union is discriminated by mode, so TypeScript only offers container after you write mode: "duplicate".

Shared options

Available in both modes.

OptionTypeDefaultDescription
quality"low" | "medium" | "high" | number"medium"Device-pixel multiplier for text canvases, SVG rasterization and render targets.
layer"base" | "selected" | number"base"Which Three.js layer channel the camera renders.
resizeDebounceboolean | ResizeConfigtrueDebounce window resize. true means 150 ms.
travelerClipArea`${number}px` | `${number}%` | number1Scissor box size when capturing traveler layers.
debugboolean—Declared but not yet read by the engine.
style{ zIndex?: string }—Declared but not yet read by the engine.

quality

new Mirage(target, { quality: "high" }); // factor 4
new Mirage(target, { quality: 3 });      // factor 3
ValueFactor
"low"1
"medium"2
"high"4
numberthat number, clamped to a 0.1 minimum

Higher values sharpen text and render targets at a quadratic memory cost. See Performance.

layer

new Mirage(target, { layer: "selected" });

"base" renders channel 0. "selected" renders channel 1, so only elements marked with data-mirage-select appear. A raw number targets that channel directly.

resizeDebounce

type ResizeConfig = {
  delay?: number;     // default 150 (ms)
  onStart?: () => void;
  onEnd?: () => void;
};
new Mirage(target, {
  resizeDebounce: {
    delay: 250,
    onStart: () => document.body.classList.add("is-resizing"),
    onEnd: () => document.body.classList.remove("is-resizing"),
  },
});

Set false to re-extract on every resize event — accurate but expensive.

travelerClipArea

Controls how much of the scene is captured behind each traveler mesh.

FormMeaning
1 (number)Ratio of the traveler's own size
"120%"Ratio, as a percentage
"40px"Fixed padding added around the traveler's box

Widen it when a refraction effect samples content outside its own bounds and you see clipped edges.

Overlay mode

interface OverlayConfig extends BaseConfig {
  mode?: "overlay";
  canvasSize?: "viewport" | "document";
}
OptionTypeDefaultDescription
mode"overlay""overlay"Canvas is mounted over the target in place.
canvasSize"viewport" | "document""viewport"Canvas allocation strategy.

"viewport" sizes the canvas to the window plus a 200 px overscan margin and pins it position: fixed. This is what keeps long scrolling pages at 60fps.

"document" sizes the canvas to the full target box. Use it only when you need effects that read outside the viewport; it degrades badly on tall documents.

Duplicate mode

interface DuplicateConfig extends BaseConfig {
  mode: "duplicate";
  container?: HTMLElement;
}
OptionTypeDefaultDescription
mode"duplicate"—Required to select this mode.
containerHTMLElementtarget's parentWhere the canvas is mounted.

The canvas gets pointer-events: auto in this mode (it is none in overlay), because the copy is the thing the user looks at.

Sandwich

type SandwichConfig = { frontSelector?: string };
ValueEffect
omitted / trueEnabled, selecting [data-mirage-sandwich='front']
falseDisabled
{ frontSelector: ".hud" }Enabled with a custom selector
new Mirage(target, { sandwich: { frontSelector: ".floating-ui" } });
new Mirage(target, { sandwich: false });

Sandwich is on by default. Pass sandwich: false if you do not want Mirage appending layer elements to document.body.

See Sandwich Layering.

Full example

import { Mirage } from "mirage-engine";
 
const mirage = new Mirage(document.querySelector("#app") as HTMLElement, {
  mode: "overlay",
  canvasSize: "viewport",
  quality: "high",
  layer: "base",
  travelerClipArea: "140%",
  resizeDebounce: { delay: 200 },
  sandwich: { frontSelector: "[data-hud]" },
});
 
await mirage.start();

Mirage Engine — MIT Licensed © 2026 dltldn333