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

    The per-frame LOD settle wait, plus the run-scoped bookkeeping its end-of-run report needs.

    One instance per capture run: the latch, the streak counter and the warn-once flags are all run-scoped.

    Index
    timeouts: number = 0
    consecutiveTimeouts: number = 0
    disabled: boolean = false
    everDisabled: boolean = false

    Sticky counterpart of disabled: true once the latch has fired at any point in the run, and never cleared by a re-arm. The latch itself comes back on, so it cannot answer "were any frames captured without waiting?" at the end of the run — this can. It doubles as the warn-once guard, so a run that latches and re-arms repeatedly logs one line rather than one per latch.

    predicateThrew: boolean = false
    • Read the injected quiescence predicate, tri-state and throw-safe.

      null means "do not wait": either this scene has no lod_group to wait for (no hook, no registry, or a registry with none in it), or the predicate threw. The guard mirrors AnimationController.pacingSuspended() and exists for the same reason — this is a guard on the INJECTION POINT, not on a known thrower. Unguarded, a throw would be caught by the loop's outer handler, reported as "Recording failed" and discard the whole sequence, which is a catastrophic price for a diagnostic predicate.

      The degradation is FRAME-SCOPED, not run-scoped: the predicate is re-probed on the next frame, so a transient throw costs that one frame's wait and nothing more. Only the WARNING is once-per-run, so a persistently throwing provider does not emit one line per frame.

      A frame whose opening probe throws is skipped whole: it counts no settle timeout AND does not reset consecutiveTimeouts. So an alternating throw/timeout run latches disabled over more than MAX_CONSECUTIVE_LOD_TIMEOUTS frames. That is intended — the streak measures consecutive timeouts, not consecutive frames — but it is worth stating rather than rediscovering.

      Returns boolean | null

    • Wait for this frame's pose to settle, if this scene has anything to wait for and the latch is not currently holding the wait off.

      MUST be called after the orbit callback has been removed: the camera pose is fixed from that point on, so the extra frames only let pending loads land. Draining before it would keep advancing the turntable while we wait, smearing the sweep.

      Returns Promise<void>

    • The bounded wait itself: one mandatory selector-catch-up tick, then poll.

      Returns Promise<boolean>

      whether the scene settled. false also covers "a Stop or abort broke us out" — the caller distinguishes the two, because only a genuine give-up counts as a timeout.

    • Make a degraded sequence visible rather than a mystery: some frames were captured before their LOD levels finished loading, so they may not show the level the selector had settled on.

      "May not show the settled level" rather than "may be coarse", in both branches, because the predicate is direction-blind: displayed !== active also fires while the never-downgrade gate legitimately holds a FINER previously-displayed level over a coarser aspiration that is still streaming. Those frames look better than the selection, not worse, and telling the user they are coarse would be wrong.

      The two branches report genuinely different things, and conflating them was actively misleading. Once the latch has fired (sticky everDisabled, since the latch itself re-arms), timeouts stops describing the run: it counts only the frames that WAITED and gave up, while every frame captured while the wait was off was taken with no wait at all — so on a 600-frame capture a handful of counted timeouts can sit in front of hundreds of undrained frames. (It is NOT pinned at MAX_CONSECUTIVE_LOD_TIMEOUTS: that constant bounds the consecutive STREAK, and a run that alternates timeout/settle can reach any total before three land in a row.) So: an exact count only when waiting stayed on for the whole run; otherwise say what actually happened and claim no number. The exact branch's denominator is attemptedFrames, not capturedFrames — a timeout is counted before the capture attempt, so a frame that timed out and then threw would otherwise be in the numerator but not the denominator.

      Parameters

      • capturedFrames: number
      • attemptedFrames: number

      Returns string | null

      the toast to show, or null when the run needs no report.