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

    Interface UrlParams

    All URL parameters recognized by the viewer, as a typed snapshot.

    Produced once by readUrlParams and threaded through the app; every consumer that wants a URL-derived value accepts the relevant field via options rather than reading window.location itself. Adding a new recognized parameter means adding a field here and a line to readUrlParams.

    interface UrlParams {
        src: string | null;
        theme: string | null;
        title: string | null;
        view: string | null;
        control: string | null;
        controlToken: string | null;
        controlAllowCrossOrigin: boolean;
        panel: string | null;
        debug: boolean;
        verboseLog: boolean;
        kiosk: boolean;
        noCache: boolean;
        noSliceCache: boolean;
        noOpfs: boolean;
        opfsReadConcurrency: number | null;
        cacheDebug: boolean;
        clearCache: boolean;
        lodFade: boolean;
        allowLinks: boolean;
        lodEnergyComp: boolean;
        lodFinest: boolean;
        lodBias: number | null;
        blendWarmup: boolean;
        depthSort: boolean;
        densityGuard: boolean;
        densityCap: number | null;
        noPrefetch: boolean;
        prefetchDebug: boolean;
        cacheStats: boolean;
        renderer: "webgl" | "webgpu" | null;
        webgpuForceWebGL: boolean;
        perfTimestamp: boolean;
        hdr: "auto" | "off" | null;
        hdrHeadroom: number | null;
        renderAlways: boolean;
        renderAudit: boolean;
        gpuBudgetMB: number | null;
        cacheBudgetMB: number | null;
        workers: number | null;
        prefetch: number | null;
        textScale: number | null;
        dpr: number | null;
        input: InputProfileOverride | null;
        lineJoin: LineJoinStyleName | null;
        linePrimitive: LinePrimitive | null;
        bakeEnv: boolean;
        probe: string | null;
        envResolution: number | null;
        viewAxis: ViewAxisName | null;
    }
    Index
    src: string | null

    Dataset source URL (?src=...). Null when not provided.

    theme: string | null

    Theme override (?theme=light etc). Null when not provided.

    title: string | null

    Browser tab title (?title=...). luxar serve --open derives it from the dataset file name so several open viewer tabs are tellable apart; a scene's authored viewer_config.title overrides it at load.

    view: string | null

    Shareable view bookmark JSON (?view=...).

    control: string | null

    Remote-control socket URL, already resolved and validated (?control, or ?control=ws://host/control to split the origin). Null when control is off — which is the default — or when the supplied value was refused. See normalizeControlSocketUrl.

    controlToken: string | null

    Shared secret presented to the hub as ?token= (?controlToken=...), matching luxar serve --control-token. Null when the hub is open.

    A token in a query string lands in browser history and in the address bar of whatever tablet is driving the display. That is acceptable for a LAN kiosk and is not a substitute for not exposing the hub to a network you do not trust.

    controlAllowCrossOrigin: boolean

    Permit a cross-origin control socket (?controlAllowCrossOrigin). Off by default so a crafted link cannot point the display at someone else's hub.

    panel: string | null

    Alternative control-panel module (?panel=/my-panel.js), resolved and validated same-origin. Null when absent or refused.

    Read only by control.html; the viewer itself ignores it. See normalizePanelModuleUrl.

    debug: boolean

    Enable the window.__luxarDebug interface (?debug).

    verboseLog: boolean

    ?verboseLog — also print per-query / per-part detail lines (log.verbose). Off by default: on huge partition trees they reach tens of thousands of console calls per slice step.

    kiosk: boolean

    ?kiosk — lock this display down for unattended public use.

    A hard override over the scene's authored ui.kiosk block, because this is the OPERATOR's channel: a store that predates the block, or one borrowed for an exhibit it was never authored for, still has to be lockable from the launch command. See config/kiosk.ts.

    noCache: boolean

    Disable all cache layers (?noCache).

    noSliceCache: boolean

    Disable only the SliceCache / S-cache (?noSliceCache).

    noOpfs: boolean

    Disable only the L2 OPFS persistent tier (?noOpfs); L0/L1/S-cache stay on. The deterministic sibling of the OPFS circuit breaker — use it in environments whose OPFS is known to stall (automated Chromium).

    opfsReadConcurrency: number | null

    Override the page-wide OPFS read cap (?opfsReadConcurrency=N).

    cacheDebug: boolean

    Verbose cache logging (?cacheDebug).

    clearCache: boolean

    Clear caches on init (?clearCache).

    lodFade: boolean

    Whether the substitutive-LOD level dissolve is enabled: when a blendable (additive/luminous/volumetric) group changes its displayed level, dissolve the outgoing level into the incoming one over config.lod.fadeMs instead of a hard visibility swap (anti-popping). Driven by time since the change, not by the camera's distance to a threshold, so a parked camera always settles on one level. On by default; pass ?noLodFade to disable it (e.g. to compare against the hard swap or isolate a rendering issue).

    allowLinks: boolean

    Whether a picked element's authored link may be opened on left-click (issue #1917). On by default; pass ?noLinks to disable it.

    The switch an embedder showing third-party scenes wants: .zattrs is untrusted, so this guarantees no navigation can originate in the data. It suppresses the navigation, the two link items in the right-click menu and the pointer cursor; Copy still works, since the clipboard is not navigation.

    lodEnergyComp: boolean

    Whether streaming brightness compensation is enabled: as a blendable (additive/luminous/volumetric) LOD leaf's additive ladder streams in, scale its opacity by 1/e(k) so the partial prefix renders at full-level brightness instead of brightening up as chunks arrive (anti-popping WITHIN one level's stream, orthogonal to lodFade's dissolve BETWEEN levels). On by default; pass ?noLodEnergy to disable it (e.g. to compare against the uncompensated brightening ramp).

    lodFinest: boolean

    Force the finest LOD level regardless of projected screen coverage (?lodFinest). For high-quality still/video capture — the gallery harness appends it — where a coarse level would look blurry even though the subject is small in frame. Off by default (opt-in, unlike the three on-by-default flags above).

    lodBias: number | null

    Session-wide replacement-LOD bias (?lodBias=<positive number>), in screen-area units. 2 advances an occupancy-halved ladder by one level; 4 by two. Null keeps the neutral 1 default.

    blendWarmup: boolean

    WebGL-only blend warm-up. On by default; pass ?noBlendWarmup to disable the off-interaction-path pre-linking of reachable blend-mode program variants.

    depthSort: boolean

    Whether gsplat depth sorting is enabled (depth-sorting Phases 2-3): the async worker sort that keeps normal-mode splats composited back-to-front, plus the per-frame camera-motion re-sort scheduler. On by default; pass ?depthSort=0 (also false/off) to disable it — normal-mode gsplats then keep the identity (storage) order, which pins deterministic output for E2E/visual runs and reproduces pre-Phase-2 behavior for comparison.

    densityGuard: boolean

    Projected-density guard (per-node keep-fraction thinning + refinement rung cap on over-drawn nodes; config.densityGuard). On by default; ?noDensityGuard disables it for the session — the A/B lever for the audit bench and for reproducing an overdraw report.

    densityCap: number | null

    Session-only override of the density guard's blendable cap (?densityCap=8, elements per drawing-buffer pixel; config.densityGuard.capElementsPerPixel is 4). Both consumers follow it — the shader keep-fraction ladder and the refinement rung gate — so a threshold sweep is one URL edit per arm, no rebuild and nothing persisted. The non-blendable cap (1) only moves when the override is below it, so it stays the tighter of the two. Null/invalid ⇒ the configured cap.

    noPrefetch: boolean

    Disable adjacent-chunk prefetching (?noPrefetch).

    prefetchDebug: boolean

    Verbose prefetch logging (?prefetchDebug).

    cacheStats: boolean

    Auto-open the data-loading monitor in expanded mode on the Cache tab (?cacheStats). Useful for measuring L0/L1/L2 hit rates without having to find the monitor's keyboard shortcut first.

    renderer: "webgl" | "webgpu" | null

    Force a specific rendering backend regardless of the default resolution. Useful for per-load A/B comparisons and for diagnosing TSL-vs-GLSL divergences without restarting the dev server.

    • ?renderer=webgl — THREE.WebGLRenderer + GLSL ShaderMaterial (the production default).
    • ?renderer=webgpu — opt into WebGPURenderer + TSL NodeMaterial. The renderer internally dispatches to a real WebGPU adapter when available or falls back to its WebGL2 backend otherwise.
    • Unset (null) — fall back to the build-time VITE_LUXAR_USE_WEBGPU env var (opt-in to WebGPU); if that is also unset, the default is webgl.

    Any other value is normalized to null (defer to env / default).

    webgpuForceWebGL: boolean

    Diagnostic flag (?webgpuForceWebgl) that keeps the WebGPURenderer / TSL NodeMaterial pipeline selected but asks Three.js to back it with its internal WebGL2 backend instead of a native WebGPU adapter. Ignored when renderer resolves to webgl.

    perfTimestamp: boolean

    Opt-in to GPU timestamp queries (?perfTimestamp). Only honored under WebGPURenderer with a backend that exposes the timestamp-query feature. When set, the renderer is constructed with { trackTimestamp: true } and the perf bench reads per-frame GPU time via renderer.resolveTimestampsAsync('render'). Has a small runtime cost so the perf bench is the only intended caller; never set on the production viewer URL.

    hdr: "auto" | "off" | null

    ?hdr[=<headroom>|off] — PROTOTYPE, WebGPU only. HDR output (an extended-range rgba16float canvas, tone-mapping mode extended) is on by default in WebGPU sessions on HDR displays; the URL overrides the Settings › Advanced › HDR Output preference for this page load: off (also 0 / false) forces SDR, any other value (bare ?hdr, ?hdr=4) forces 'auto'. Null when absent.

    hdrHeadroom: number | null

    The explicit ?hdr=<headroom> value (multiple of SDR white), clamped to [HDR_HEADROOM_MIN, HDR_HEADROOM_MAX]; it pins the headroom for the session. Null for a bare ?hdr / no flag — the headroom is then resolved per display (utils/hdr/hdr-headroom.ts).

    renderAlways: boolean

    ?renderAlways — render every loop tick (the pre-render-on-change loop). A kill switch: the pixels are identical, only the redundant re-renders of an unchanged frame come back.

    renderAudit: boolean

    ?renderAudit — debug only (needs ?debug): render every tick and count, in the perf counter render.missedDirty, ticks the scheduler would have skipped whose pixels nonetheless changed.

    gpuBudgetMB: number | null

    Override the adaptive GPU-geometry byte budget, in megabytes (?gpuBudgetMB=1536). Pins the single VRAM budget shared by the buffer pool and LOD-group retention, bypassing the auto-size heuristic. Useful for large scenes on high-VRAM machines (raise it) or for testing eviction on constrained ones (lower it). 0 disables the byte budget (unbounded resident geometry). Null/invalid (missing or negative) ⇒ auto-size from navigator.deviceMemory.

    cacheBudgetMB: number | null

    Override the total in-memory cache pool (L0 + L1 + S-cache), in megabytes (?cacheBudgetMB=1536). Used where performance.memory is unavailable — WKWebView (the native app) and Safari — so heap-aware sizing has a real budget to split instead of the tiny fixed fallback. The native launcher injects it automatically. Its implied non-cache remainder also replaces the heap-derived GPU-geometry signal in either direction. Null/invalid ⇒ fall back to the measured heap, then to the fixed config sizes. See cache/heap-budget.ts.

    workers: number | null

    Worker pool size for the session (?workers=16; 0 = auto from the core count). Beats the stored Settings value, which it otherwise mirrors: a launcher on a dedicated display machine sets it without touching that machine's saved preferences. Clamped to the Settings range at boot.

    prefetch: number | null

    Concurrent chunk fetches for the session (?prefetch=12) — the Settings popover's "Prefetch Limit". Same precedence and clamping as workers.

    textScale: number | null

    Scale every overlay's text for the session (?textScale=0.8). Wins over the scene's authored viewer_config.text_scale. Only the type shrinks or grows: overlay positions, widths and anchors stay where they were authored. Clamped to [0.25, 4]. See ui/overlay-manager.ts.

    dpr: number | null

    Pin a fixed device pixel ratio and disable adaptive DPR for the session (?dpr=1). The value is clamped to [0.25, native DPR] at apply time and the adaptive-resolution toggle is locked off so persisted settings can't silently re-enable it. Primarily for deterministic E2E/visual-regression runs, agent:debug sessions, and bug repros. Null/invalid (missing, non-numeric, <= 0) ⇒ normal adaptive behavior.

    input: InputProfileOverride | null

    Force the session's JS input profile (?input=touch|mouse): pointer flags, hover capability, touch points, and device tier. This changes device-class fallback budgets (touch only — mouse keeps the detected tier), primary-tip pen routing, the Safari gesture-canceller gate, and whether the help overlay lists its Touch section; touch additionally applies the mobile rendering budgets (adaptive-DPR floor and refresh ceiling, high-DPR cap, GPU-byte and element-texture ceilings, data-worker count) and skips the blend-variant program warm-up. Stylesheets and non-pen gesture routing keep following the real media features and PointerEvent.pointerType, so a faithful check still needs device emulation or a real device. null (missing or unrecognised) ⇒ detect from the browser. See utils/input-capabilities.ts.

    lineJoin: LineJoinStyleName | null

    Force a line join style for the session (?lineJoin=none|miter).

    Overrides whatever each node authored, which is exactly its purpose: it is a debugging and workaround lever, so it must win over the scene file. Precedence is ?lineJoin= > authored node attribute > the built-in default. null (missing or unrecognised) means "no override" — distinct from 'none', which is an explicit request for no join geometry. See types/line-join.ts.

    linePrimitive: LinePrimitive | null

    Select the line rendering primitive for the session (?linePrimitive=screen-space|capsule, issue #1352). The session's strongest word: it overrides the Advanced → Line primitive policy setting (whose auto mode otherwise sizes the scene before material build — see types/line-primitive.ts).

    capsule (the default) profiles the 2D point-to-segment distance in pixel space — direction-stable end-on, bisector-cut joins; screen-space is the classic flat quad. Session-wide by design (a renderer implementation choice, not scene content — there is no authored per-node attribute). null (missing or unrecognised) means the built-in default. See types/line-primitive.ts.

    bakeEnv: boolean

    Bake the scene environment (?bakeEnv, driven by luxar env bake): once the load settles, capture the scene-derived cube map at probe / envResolution, expose the container on __luxarDebug.environment.lastBake and download it. See rendering/environment/bake.ts.

    probe: string | null

    Probe for the bake (?probe=auto|node:<path>|x,y,z). Null → the scene's config or auto.

    envResolution: number | null

    Cube face size for the bake (?envResolution=128). Null → the scene's config or 128.

    viewAxis: ViewAxisName | null

    Axis-aligned opening view for the session (?viewAxis=xy|xz|yz): face the plane of the dimensions with those names, horizontal axis right. Beats the scene's authored viewer_config.camera.view_axis; the scene's up still picks whether the vertical axis points up or down (an image-convention scene keeps y down). Named viewAxis, not view, because ?view= / #view= is the bookmark parameter. null (missing or unrecognised) ⇒ the authored preset, else the historical look-along-−Z framing. See scene/scene-manager/camera/view-axis.ts.