Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...

    Module core/layer/luxar-layer

    Layer mode — render a Luxar scene inside a host application's own Three.js renderer, camera, and scene graph.

    This is the headless sibling of LuxarApp. Where LuxarApp owns the whole pipeline (renderer, camera, controls, post-processing, panels, input), LuxarLayer owns none of it: the host keeps its renderer and camera, and the layer contributes a THREE.Group plus the per-frame bookkeeping that keeps Luxar's streaming, LOD selection, and depth sorting correct.

    The seam this rests on is already in the architecture: SceneLoader.loadScene returns a plain THREE.Group, and LODGroupRegistryDeps / configureDepthSort are defined purely in terms of injectable getters. Nothing in the data, cache, LOD, or material path needs SceneManager.

    The minimal embed shape:

    import { LuxarLayer } from '@luxar/viewer';

    const layer = new LuxarLayer({
    renderer, // host-owned
    getCamera: () => camera, // host-owned
    getViewportSize: () => renderer.getSize(new THREE.Vector2()),
    scene, // host-owned
    });
    await layer.load('https://example.com/imaging.luxar.zarr');

    // in the host's render loop, BEFORE renderer.render():
    layer.update();

    // on teardown:
    await layer.dispose();
    • Calling LuxarLayer.update once per frame, before its own render.
    • Calling LuxarLayer.resize after a viewport or camera-projection change (the layer cannot observe the host's canvas).
    • Draw order for its own geometry. Luxar stamps the configured renderOrder onto every Group it owns; host transparent groups should use explicit lower/higher values rather than rely on insertion order.
    • Scene environment sharing. If the host leaves scene.environment unset, the first Luxar physical mesh installs a prefiltered RoomEnvironment there, which can also affect the host's own lighting-model materials. A host-supplied environment is preserved, and an environment owned by the layer is released by LuxarLayer.dispose.
    • Calling LuxarLayer.handleContextLost when WebGL context loss is reported, then LuxarLayer.handleContextRestored after rebuilding its own renderer / post-processing resources.

    Everything a scene declares under viewer_config that is applied by ui/rendering-controls.ts rather than by the node path is silently inert here — tone_mapping, exposure, global_gamma, global_offset, the bloom_* family, background_color, and the whole camera block. The layer owns no post-processing, no camera, and no UI, so nothing consumes them. Only per-node appearance (colormap, blending mode, opacity, absorption, the intensity/offset window) travels with the geometry and takes effect.

    Tone mapping is the one worth calling out, because it is invisible from the scene file and changes what the data looks like. Luxar tone-maps in the mega-shader, a post-processing pass — PostProcessingManager even forces renderer.toneMapping = NoToneMapping because of it — so it is not a per-material setting that could be pushed onto the nodes. Measured in a host application: a scene authored with ACES rendered pixel-identical to one authored with None. (Measured, not asserted — no test in this repo covers it.)

    The consequence: emissive geometry in a host with no tone mapping clips flat. additive blending sums contributions into a framebuffer that clamps at 1.0, and normalising amplitudes fixes the per-splat scale, not the accumulated one. Without a filmic rolloff, overlapping bright structure goes to white with no gradient.

    A host that wants the rolloff has to tone-map itself (renderer.toneMapping = THREE.ACESFilmicToneMapping, which an OutputPass will pick up) — noting that this applies to the host's own geometry too. Otherwise the only exposure controls are the scene's authored opacity and LuxarLayer.setExposure, and max blending is the one mode that cannot saturate at all.

    One layer per page, and never alongside a LuxarApp. The scene-loader manager, dimension manager, material manager, and worker pool are process singletons; two owners would share and then corrupt each other's state. The layer has no notifier UI; archive failures are exposed through LuxarLayer.onDatasetFault and LuxarLayer.getDatasetFault so the host can surface them.

    LuxarLayer
    ViewportSize
    LuxarLayerOptions