import { HotSpotQuery, Nullable, IDisposable, IColor4Like, IReadonlyObservable } from '@babylonjs/core/index.js'; import { Observable } from '@babylonjs/core/Misc/observable.js'; import { EngineContext } from '@babylonjs/lite'; import * as lit from 'lit'; import { LitElement, CSSResultGroup, PropertyValues, TemplateResult } from 'lit'; import * as lit_html from 'lit-html'; /** * Flags for selectively resetting parts of the viewer state. */ type ResetFlag = "source" | "environment" | "camera" | "animation" | "post-processing" | "material-variant" | "shadow"; declare const shadowQualityOptions: readonly ["none", "normal", "high"]; /** * Shadow quality levels. */ type ShadowQuality = (typeof shadowQualityOptions)[number]; declare const toneMappingOptions: readonly ["none", "standard", "aces", "neutral"]; /** * Tone mapping modes. */ type ToneMapping = (typeof toneMappingOptions)[number]; declare const ssaoOptions: readonly ["enabled", "disabled", "auto"]; /** * Screen-space ambient occlusion options. */ type SSAOOptions = (typeof ssaoOptions)[number]; /** * Camera orbit as [alpha, beta, radius]. */ type CameraOrbit = [alpha: number, beta: number, radius: number]; /** * Camera target as [x, y, z]. */ type CameraTarget = [x: number, y: number, z: number]; /** * Camera auto-orbit configuration. */ type CameraAutoOrbit = { /** * Whether the camera should automatically orbit around the model when idle. */ enabled: boolean; /** * The speed at which the camera orbits around the model when idle. */ speed: number; /** * The delay in milliseconds before the camera starts orbiting around the model when idle. */ delay: number; }; /** * Environment configuration parameters. */ type EnvironmentParams = { /** * The intensity of the environment lighting. */ intensity: number; /** * The blur applied to the environment lighting. */ blur: number; /** * The rotation of the environment lighting in radians. */ rotation: number; }; /** * Shadow configuration parameters. */ type ShadowParams = { /** * The quality of shadow being used. */ quality: ShadowQuality; }; /** * Post-processing configuration. */ type PostProcessing = { /** * The tone mapping to use for rendering the scene. */ toneMapping: ToneMapping; /** * The contrast applied to the scene. */ contrast: number; /** * The exposure applied to the scene. */ exposure: number; /** * Whether to enable screen space ambient occlusion (SSAO). */ ssao: SSAOOptions; }; /** * Options for controlling which parts of the environment to update. */ type EnvironmentOptions = Partial>; /** * Options for loading an environment. */ type LoadEnvironmentOptions = EnvironmentOptions & Partial>; /** * @internal `LoadEnvironmentOptions` after the base class has resolved the optional `lighting` and * `skybox` flags to definite booleans (defaults to `true` for both when omitted, otherwise honors the * caller's choice). Engine-specific extras such as `extension` are forwarded as-is. Passed to the * subclass `_loadEnvironmentImpl` so it doesn't repeat the default-resolution logic. */ type ResolvedLoadEnvironmentOptions = Omit & { readonly lighting: boolean; readonly skybox: boolean; }; /** * A hot spot query specifying either a surface point or a fixed world position. */ type ViewerHotSpotQuery = ({ /** * The type of the hot spot. */ type: "surface"; /** * The index of the mesh within the loaded model. */ meshIndex: number; } & HotSpotQuery) | { /** * The type of the hot spot. */ type: "world"; /** * The fixed world space position of the hot spot. */ position: [x: number, y: number, z: number]; /** * The fixed world space normal of the hot spot. */ normal: [x: number, y: number, z: number]; }; /** * A hot spot definition with an optional camera pose. */ type HotSpot = ViewerHotSpotQuery & { /** * An optional camera pose to associate with the hotspot. */ cameraOrbit?: CameraOrbit; }; /** * Provides the result of a hot spot query. */ declare class ViewerHotSpotResult { /** * 2D canvas position in pixels. */ readonly screenPosition: [x: number, y: number]; /** * 3D world coordinates. */ readonly worldPosition: [x: number, y: number, z: number]; /** * Visibility range is [-1..1]. A value of 0 means camera eye is on the plane. */ visibility: number; } /** * Backend-agnostic options for loading a model. * @remarks * The full Viewer accepts the wider LoadAssetContainerOptions from core. * This type captures the subset that both backends support. */ type ViewerLoadModelOptions = Partial>; /** * Backend-agnostic options shared by all viewer implementations. */ type ViewerBaseOptions = Partial<{ /** * The default clear color of the scene. */ clearColor: [r: number, g: number, b: number, a?: number]; /** * When enabled, rendering will be suspended when no scene state driven by the Viewer has changed. * This can reduce resource CPU/GPU pressure when the scene is static. * Enabled by default. * @remarks * Only honored by the full Viewer; the Lite Viewer has no scene-mutation tracking and ignores this * option. Both flavors suspend rendering while the canvas is offscreen regardless of this setting. */ autoSuspendRendering: boolean; /** * The default source model to load into the viewer. */ source: string; /** * The file extension to use for determining the loader plugin for the default source model (e.g. ".glb", ".obj"). * @remarks * If not set, the extension is inferred from the source URL when possible. This is needed for sources whose * extension cannot be inferred from the URL (e.g. data URLs or extension-less URLs). */ pluginExtension: string; /** * The default environment to load into the viewer for lighting (IBL). */ environmentLighting: string; /** * The default environment to load into the viewer for the skybox. */ environmentSkybox: string; /** * The default environment configuration. */ environmentConfig: Partial; /** * The default camera orbit. * @remarks The default camera orbit is restored when a new model is loaded. */ cameraOrbit: Partial; /** * The default camera target. * @remarks The default camera target is restored when a new model is loaded. */ cameraTarget: Partial; /** * Automatically rotates a 3D model or scene without requiring user interaction. * @remarks The default camera auto orbit is restored when a new model is loaded. */ cameraAutoOrbit: Partial; /** * Whether to play the default animation immediately after loading. * @remarks The default animation auto play is restored when a new model is loaded. */ animationAutoPlay: boolean; /** * The default speed of the animation. * @remarks The default animation speed is restored when a new model is loaded. */ animationSpeed: number; /** * The default selected animation. * @remarks The default selected animation is restored when a new model is loaded. */ selectedAnimation: number; /** * The default post processing configuration. */ postProcessing: Partial; /** * Shadow configuration. */ shadowConfig: Partial; /** * The default selected material variant. * @remarks The default material variant is restored when a new model is loaded. */ selectedMaterialVariant: string; /** * The default hotspots. */ hotSpots: Record; /** * Boolean indicating if the scene must use right-handed coordinates system. */ useRightHandedSystem: boolean; /** * If true, load glTF files using the OpenPBR material instead of the default PBR material. * @experimental */ useOpenPBR: boolean; /** * Called when a fatal error occurs that prevents the viewer from functioning. */ onFaulted: (error: Error) => void; }>; /** * The subset of the Viewer API that ViewerElementBase depends on. * Both the full Babylon.js Viewer and ViewerLite implement this contract. */ interface IViewer extends IDisposable { /** * Fired when the environment has changed. */ readonly onEnvironmentChanged: IReadonlyObservable; /** * Fired when the environment configuration has changed. */ readonly onEnvironmentConfigurationChanged: IReadonlyObservable; /** * Fired when an error occurs while loading the environment. */ readonly onEnvironmentError: IReadonlyObservable; /** * Fired when the shadows configuration changes. */ readonly onShadowsConfigurationChanged: IReadonlyObservable; /** * Fired when the post processing state changes. */ readonly onPostProcessingChanged: IReadonlyObservable; /** * Fired when a model is loaded into the viewer (or unloaded from the viewer). */ readonly onModelChanged: IReadonlyObservable>; /** * Fired when an error occurs while loading a model. */ readonly onModelError: IReadonlyObservable; /** * Fired when progress changes on loading activity. */ readonly onLoadingProgressChanged: IReadonlyObservable; /** * Fired when the camera auto orbit state changes. */ readonly onCameraAutoOrbitChanged: IReadonlyObservable; /** * Fired when the selected animation changes. */ readonly onSelectedAnimationChanged: IReadonlyObservable; /** * Fired when the animation speed changes. */ readonly onAnimationSpeedChanged: IReadonlyObservable; /** * Fired when the selected animation is playing or paused. */ readonly onIsAnimationPlayingChanged: IReadonlyObservable; /** * Fired when the current point on the selected animation timeline changes. */ readonly onAnimationProgressChanged: IReadonlyObservable; /** * Fired when the selected material variant changes. */ readonly onSelectedMaterialVariantChanged: IReadonlyObservable; /** * Fired when the hot spots object changes to a complete new object instance. */ readonly onHotSpotsChanged: IReadonlyObservable; /** * Fired when the cameras as hot spots property changes. */ readonly onCamerasAsHotSpotsChanged: IReadonlyObservable; /** * Fired after each frame is rendered. */ readonly onAfterRenderObservable: IReadonlyObservable; /** * Fired when the clear color changes. */ readonly onClearColorChanged: IReadonlyObservable; /** * Gets or sets the clear color (background color) of the viewer. */ clearColor: IColor4Like; /** * Gets the camera auto-orbit configuration. */ get cameraAutoOrbit(): Readonly; /** * Sets the camera auto-orbit configuration. Only specified fields are updated. */ set cameraAutoOrbit(value: Partial>); /** * Resets the camera to its default state. * @param reframe If true, reframes the camera to fit the model. If undefined, automatically determined. */ resetCamera(reframe?: boolean): void; /** * Updates the camera pose. * @param pose The new pose of the camera. Any unspecified values are left unchanged. */ updateCamera(pose: { alpha?: number; beta?: number; radius?: number; targetX?: number; targetY?: number; targetZ?: number; }): void; /** * Gets the environment configuration. */ get environmentConfig(): Readonly; /** * Sets the environment configuration. Only specified fields are updated. */ set environmentConfig(value: Partial>); /** * Loads an environment from the specified URL. * @param url The URL of the environment to load. * @param options The options for loading the environment. * @param abortSignal An optional signal that can be used to abort the load. */ loadEnvironment(url: string, options?: LoadEnvironmentOptions, abortSignal?: AbortSignal): Promise; /** * Resets the environment to its default state. * @param options The options to use when resetting the environment. * @param abortSignal An optional signal that can be used to abort the reset. */ resetEnvironment(options?: EnvironmentOptions, abortSignal?: AbortSignal): Promise; /** * Gets the post-processing configuration. */ get postProcessing(): Readonly; /** * Sets the post-processing configuration. Only specified fields are updated. */ set postProcessing(value: Partial>); /** * Gets the current shadow configuration. */ readonly shadowConfig: Readonly; /** * Updates the shadow configuration. * @param value The new shadow configuration. * @param abortSignal Optional signal that can be used to abort the update. */ updateShadows(value: Partial>, abortSignal?: AbortSignal): Promise; /** * Loads a 3D model from the specified source. * @param source The source of the model to load. * @param options The options for loading the model. * @param abortSignal An optional signal that can be used to abort the load. */ loadModel(source: string | File | ArrayBufferView, options?: ViewerLoadModelOptions, abortSignal?: AbortSignal): Promise; /** * Unloads the current 3D model if one is loaded. * @param abortSignal An optional signal that can be used to abort the reset. */ resetModel(abortSignal?: AbortSignal): Promise; /** * The list of animation names for the currently loaded model. */ readonly animations: readonly string[]; /** * Gets or sets the index of the selected animation. */ selectedAnimation: number; /** * Gets or sets the speed scale at which animations are played. */ animationSpeed: number; /** * True if an animation is currently playing. */ readonly isAnimationPlaying: boolean; /** * Gets or sets the current point on the selected animation timeline, normalized between 0 and 1. */ animationProgress: number; /** * Toggles between playing and pausing the selected animation. */ toggleAnimation(): void; /** * Plays the selected animation. */ playAnimation(): void; /** * Pauses the selected animation. */ pauseAnimation(): Promise; /** * The list of material variant names for the currently loaded model. */ readonly materialVariants: readonly string[]; /** * Gets or sets the selected material variant. */ selectedMaterialVariant: Nullable; /** * Gets or sets the hot spots configuration. */ hotSpots: Record; /** * Gets or sets whether cameras embedded in the model should be exposed as hot spots. */ camerasAsHotSpots: boolean; /** * Queries a named hot spot and returns its screen and world positions. * @param name The name of the hot spot to query. * @param result The result object to populate. * @returns True if the hot spot was found. */ queryHotSpot(name: string, result: ViewerHotSpotResult): boolean; /** * Updates the camera to focus on a named hotspot. * @param name The name of the hotspot to focus on. * @returns True if the hotspot was found and the camera was updated. */ focusHotSpot(name: string): boolean; /** * True if a model is currently loaded. */ readonly isModelLoaded: boolean; /** * The current loading progress. False when not loading, true when loading with indeterminate progress, or a number between 0 and 1. */ readonly loadingProgress: boolean | number; /** * Resets the viewer to its initial state based on the options passed in to the constructor. * @param flags The flags that specify which parts of the viewer to reset. If no flags are provided, all parts will be reset. */ reset(...flags: ResetFlag[]): void; /** * Disposes the viewer and releases all resources. */ dispose(): void; } /** * Common base for the full Babylon.js {@link Viewer} and the lite Viewer. * * Encapsulates the pieces that are identical between both engine backends: * - The 18 public observables exposed by the viewer surface area * - In-flight load operation tracking (used to compute aggregate `loadingProgress`) * - The `_throwIfDisposedOrAborted` helper used at the start of every async operation * - The disposed flag and observable teardown in `dispose()` * * Subclasses are responsible for everything engine-specific (scene/engine creation, * model + environment loading orchestration, camera, post-processing, shadows, etc.) * and for declaring `implements IViewer` themselves so the public API contract is * verified at the leaf class level. */ declare abstract class ViewerBase { /** * Fired when the environment has changed. */ readonly onEnvironmentChanged: Observable; /** * Fired when the environment configuration has changed. */ readonly onEnvironmentConfigurationChanged: Observable; /** * Fired when an error occurs while loading the environment. */ readonly onEnvironmentError: Observable; /** * Fired when the shadows configuration changes. */ readonly onShadowsConfigurationChanged: Observable; /** * Fired when the post processing state changes. */ readonly onPostProcessingChanged: Observable; /** * Fired when a model is loaded into the viewer (or unloaded from the viewer). * @remarks * The event argument is the source that was loaded, or null if no model is loaded. */ readonly onModelChanged: Observable>>; /** * Fired when an error occurs while loading a model. */ readonly onModelError: Observable; /** * Fired when progress changes on loading activity. */ readonly onLoadingProgressChanged: Observable; /** * Fired when the camera auto orbit state changes. */ readonly onCameraAutoOrbitChanged: Observable; /** * Fired when the selected animation changes. */ readonly onSelectedAnimationChanged: Observable; /** * Fired when the animation speed changes. */ readonly onAnimationSpeedChanged: Observable; /** * Fired when the selected animation is playing or paused. */ readonly onIsAnimationPlayingChanged: Observable; /** * Fired when the current point on the selected animation timeline changes. */ readonly onAnimationProgressChanged: Observable; /** * Fired when the selected material variant changes. */ readonly onSelectedMaterialVariantChanged: Observable; /** * Fired when the hot spots object changes to a complete new object instance. */ readonly onHotSpotsChanged: Observable; /** * Fired when the cameras as hot spots property changes. */ readonly onCamerasAsHotSpotsChanged: Observable; /** * Fired after each frame is rendered. */ readonly onAfterRenderObservable: Observable; /** * Fired when the clear color changes. */ readonly onClearColorChanged: Observable; /** * @internal Tracks in-flight load operations (model + environment + shadows) so that * `loadingProgress` can return either an aggregate progress number, `true` (indeterminate), * or `false` (no operations in flight). */ protected readonly _loadOperations: Set; }>>; /** @internal True after `dispose()` has been called. */ protected _isDisposed: boolean; /** * @internal Backend-agnostic viewer options stored at construction time. Subclasses declare this * with their own (narrower) options type that extends {@link ViewerBaseOptions} and assign it from * their own constructor (typically via a parameter property). */ protected abstract readonly _options?: Readonly; /** * The current loading progress. False when no load is in flight, true when at least one * load is in flight with indeterminate progress, or a number between 0 and 1 representing * the average of all in-flight loads' progress. */ get loadingProgress(): boolean | number; /** * Begin tracking a new load operation. Subclasses call this at the start of an async load * and dispose the returned handle when it completes (or fails). The handle exposes a * `progress` setter that, when assigned, fires `onLoadingProgressChanged`. * @returns A handle that can be disposed when the operation completes; the `progress` setter * updates the aggregate `loadingProgress` as the operation runs. */ protected _beginLoadOperation(): IDisposable & { progress: Nullable; }; /** * @internal Throws if the viewer has been disposed or any of the supplied abort signals * are aborted. Used at the start of every async operation to bail out early. * @param abortSignals Optional abort signals to check. */ protected _throwIfDisposedOrAborted(...abortSignals: (Nullable | undefined)[]): void; /** Lock guarding lighting-side environment loads. */ private readonly _loadEnvironmentLightingLock; /** Abort controller for the currently in-flight lighting-side load (null when none). */ private _loadEnvironmentLightingAbortController; /** Lock guarding skybox-side environment loads. */ private readonly _loadEnvironmentSkyboxLock; /** Abort controller for the currently in-flight skybox-side load (null when none). */ private _loadEnvironmentSkyboxAbortController; /** * @internal The abort signal of the currently in-flight lighting-side load, or `undefined` if * none. Subclasses can use this in `_throwIfDisposedOrAborted` to bail out of dependent async * work (shadows, post-processing, etc.) when the user starts a new lighting load. */ protected get _loadEnvironmentLightingAbortSignal(): AbortSignal | undefined; /** * @internal The abort signal of the currently in-flight skybox-side load, or `undefined` if * none. Subclasses can use this in `_throwIfDisposedOrAborted` to bail out of dependent async * work (shadows, post-processing, etc.) when the user starts a new skybox load. */ protected get _loadEnvironmentSkyboxAbortSignal(): AbortSignal | undefined; /** * Loads an environment from the specified URL. The lighting and skybox sides have * independent locks and abort controllers so concurrent requests for one side don't * cancel an in-flight load for the other. * @param url The URL of the environment to load. * @param options Selects which sides to update (defaults to both) and forwards engine-specific extras. * @param abortSignal Optional signal that can be used to abort the load externally. * @returns A promise that resolves when the environment has finished loading. */ loadEnvironment(url: string, options?: LoadEnvironmentOptions, abortSignal?: AbortSignal): Promise; /** * Removes the loaded environment. By default removes both lighting and skybox; pass `options` * to remove only one side. Subclasses (notably the full Viewer) may override to add backend-specific * fallback behavior such as substituting a default environment for lighting when the scene contains * PBR materials. * @param options Selects which sides to remove (defaults to both). * @param abortSignal Optional signal that can be used to abort the operation externally. * @returns A promise that resolves when the environment has finished resetting. */ resetEnvironment(options?: EnvironmentOptions, abortSignal?: AbortSignal): Promise; /** * @internal Internal helper exposing the dual-lock orchestration with a nullable URL. * Used by the public `loadEnvironment` (with a string URL) and by subclass `resetEnvironment` * implementations (which pass `undefined` to clear or `"auto"` to load defaults). * * Subclasses should NOT override this — override the abstract `_loadEnvironmentImpl` instead. */ protected _updateEnvironment(url: Nullable, options?: LoadEnvironmentOptions, abortSignal?: AbortSignal): Promise; /** * @internal Engine-specific environment loading. Subclasses implement this with their actual * texture loading / scene mutation logic. The base class handles only the surrounding lock + * abort-prev orchestration and the composite abort signal; everything else (`onEnvironmentChanged` / * `onEnvironmentError` notifications, snapshot-helper bracketing, etc.) is the impl's responsibility. * * Implementations should: * - Throw on failure. They should fire `onEnvironmentError` themselves before throwing if they * want external observers to be notified. * - Fire `onEnvironmentChanged` on success. * - Periodically re-check abort by calling `throwIfAborted(abortSignal, compositeAbortSignal)` * at safe points within the load (e.g. after long-running awaits). * * @param url Trimmed URL string, `undefined` (caller asked to clear), or `null`. * @param options Resolved options — `lighting` and `skybox` are guaranteed booleans indicating * which sides the caller is updating; engine-specific extras (e.g. `extension`) are forwarded as-is. * @param abortSignal The caller's external abort signal (or `undefined`). * @param compositeAbortSignal Signal that fires when ALL relevant internal load operations have aborted. */ protected abstract _loadEnvironmentImpl(url: Nullable, options: ResolvedLoadEnvironmentOptions, abortSignal: AbortSignal | undefined, compositeAbortSignal: AbortSignal): Promise; /** @internal Current environment intensity. Initialized from options in subclass constructors. */ protected _environmentIntensity: number; /** @internal Current environment skybox blur. Initialized from options in subclass constructors. */ protected _environmentBlur: number; /** @internal Current environment rotation in radians. Initialized from options in subclass constructors. */ protected _environmentRotation: number; get environmentConfig(): Readonly; set environmentConfig(value: Partial>); /** * @internal Push the current `_environmentIntensity` value into the engine's environment state. * Called by the public `environmentConfig` setter only when the value changes. */ protected abstract _applyEnvironmentIntensity(): void; /** * @internal Push the current `_environmentBlur` value into the engine's environment state. * Called by the public `environmentConfig` setter only when the value changes. */ protected abstract _applyEnvironmentBlur(): void; /** * @internal Push the current `_environmentRotation` value into the engine's environment state. * Called by the public `environmentConfig` setter only when the value changes. */ protected abstract _applyEnvironmentRotation(): void; /** @internal Initialized from options in subclass constructors. */ protected _autoOrbitEnabled: boolean; /** @internal Initialized from options in subclass constructors. */ protected _autoOrbitSpeed: number; /** @internal Initialized from options in subclass constructors. */ protected _autoOrbitDelay: number; get cameraAutoOrbit(): Readonly; set cameraAutoOrbit(value: Partial>); /** * @internal Push the current `_autoOrbitEnabled` value into engine state. * Called by the public `cameraAutoOrbit` setter only when the value changes. */ protected abstract _applyCameraAutoOrbitEnabled(): void; /** * @internal Push the current `_autoOrbitSpeed` value into engine state. * Called by the public `cameraAutoOrbit` setter only when the value changes. */ protected abstract _applyCameraAutoOrbitSpeed(): void; /** * @internal Push the current `_autoOrbitDelay` value into engine state. * Called by the public `cameraAutoOrbit` setter only when the value changes. */ protected abstract _applyCameraAutoOrbitDelay(): void; /** * @internal The current scene clear color, stored as a stable mutable record so consumers * holding a reference returned by the `clearColor` getter see updates from the setter and from * `reset("environment")`. The setter mutates this object in-place rather than replacing it. */ protected readonly _clearColor: IColor4Like; /** * The viewer clear color (e.g. background). */ get clearColor(): Readonly; set clearColor(value: Readonly); /** * @internal Push the current `_clearColor` value into the engine's scene state. Called by the * public `clearColor` setter; subclasses may also call this directly during construction to sync * engine state to the initial field values. */ protected abstract _applyClearColor(): void; /** @internal Pure state — no engine state. Subclasses initialize via the public `hotSpots` setter in their constructor body. */ private _hotSpots; /** * The set of defined hotspots. */ get hotSpots(): Record; set hotSpots(value: Record); /** Lock guarding model loads (and resets). */ private readonly _loadModelLock; /** Abort controller for the currently in-flight model load (null when none). */ private _loadModelAbortController; /** * @internal The abort signal of the currently in-flight model load, or `undefined` if none. * Subclasses can use this in `_throwIfDisposedOrAborted` to bail out of dependent async work * (shadows, environment fallback, etc.) when the user starts a new model load. */ protected get _loadModelAbortSignal(): AbortSignal | undefined; /** * Loads a 3D model from the specified source. * @param source The source of the model to load. * @param options Engine-specific options for loading the model. * @param abortSignal Optional signal that can be used to abort the load externally. * @returns A promise that resolves when the model has finished loading. */ loadModel(source: string | File | ArrayBufferView, options?: ViewerLoadModelOptions, abortSignal?: AbortSignal): Promise; /** * Unloads the current 3D model if one is loaded. * @param abortSignal Optional signal that can be used to abort the reset. * @returns A promise that resolves when the current model has been unloaded. */ resetModel(abortSignal?: AbortSignal): Promise; /** * @internal Internal helper exposing the model load orchestration with `source: undefined` meaning * "unload the current model". Subclasses should NOT override this — override `_loadModelImpl` instead. */ protected _updateModel(source: string | File | ArrayBufferView | undefined, options?: ViewerLoadModelOptions, abortSignal?: AbortSignal): Promise; /** * @internal Engine-specific model loading. Subclasses implement this with their actual model * loading logic. The base class handles only the surrounding lock + abort-prev orchestration; * everything else (load-operation progress tracking, `onModelChanged` / `onModelError` * notifications, snapshot-helper bracketing) is the impl's responsibility. * * Implementations should: * - Throw on failure. They should fire `onModelError` themselves before throwing if they want * external observers to be notified. * - Fire `onModelChanged` on success. * - Manage their own `_beginLoadOperation` / dispose pair if they want to contribute to * `loadingProgress`. * - Periodically re-check abort by calling `throwIfAborted(abortSignal, internalAbortSignal)` * at safe points within the load (e.g. after long-running awaits). * - Treat `source === undefined` as "unload the current model" — this is how `resetModel` flows * through. They should still fire `onModelChanged(null)` so consumers see the unload. * * @param source Source URL/File/ArrayBufferView, or `undefined` to unload the current model. * @param options Caller's options (or undefined). May contain engine-specific extras. * @param abortSignal The caller's external abort signal (or `undefined`). * @param internalAbortSignal Signal that fires when a NEWER model load supersedes this one. */ protected abstract _loadModelImpl(source: string | File | ArrayBufferView | undefined, options: ViewerLoadModelOptions | undefined, abortSignal: AbortSignal | undefined, internalAbortSignal: AbortSignal): Promise; /** * @internal Optional post-lock hook invoked AFTER the model load lock is released, allowing * subclasses to do follow-up work that needs other locks (e.g. environment fallback). The base * skips this hook if the load was superseded by a newer one before we got here. * * Implementations that await additional work should re-check `internalAbortSignal.aborted` * after each await to avoid acting on stale state (a newer load may have started during the * await window). * * Default: no-op. */ protected _afterLoadModel(source: string | File | ArrayBufferView | undefined, options: ViewerLoadModelOptions | undefined, abortSignal: AbortSignal | undefined, internalAbortSignal: AbortSignal): Promise; /** Lock guarding shadow updates. */ private readonly _updateShadowsLock; /** Abort controller for the currently in-flight shadow update (null when none). */ private _shadowsAbortController; /** * @internal The abort signal of the currently in-flight shadow update, or `undefined` if none. * Subclasses can use this in `_throwIfDisposedOrAborted` to bail out of dependent async work * when the user starts a new shadow update. */ protected get _shadowsAbortSignal(): AbortSignal | undefined; /** * @internal The currently committed shadow quality. Subclasses initialize this from their * options in their constructor and read it in their `_loadModelImpl` etc. The base class * commits a new value here only after `_updateShadowsImpl` succeeds, so failed/aborted * shadow updates don't leave this field out of sync with engine state. */ protected _shadowQuality: ShadowQuality; /** @internal */ abstract get selectedMaterialVariant(): Nullable; /** @internal */ abstract set selectedMaterialVariant(value: Nullable); /** * Gets the current shadow configuration. */ get shadowConfig(): Readonly; /** * Updates the shadow configuration. Skips work if the requested value matches the currently * committed one. Subclasses can override this to validate the requested quality (e.g. throw on * unsupported combinations) before delegating to `super.updateShadows(value, abortSignal)`. * @param value The new shadow configuration. * @param abortSignal Optional signal that can be used to abort the update externally. * @returns A promise that resolves when the shadow update completes. */ updateShadows(value: Partial>, abortSignal?: AbortSignal): Promise; /** * Runs the engine-specific shadow update at the given quality under the shared lock, with * abort-prev semantics. Subclasses should call this (rather than `_updateShadowsImpl` directly) * when they need to re-run the shadow setup (e.g. after a model change or environment change). * The public `updateShadows` also routes through this helper. * @param quality The shadow quality to apply. Defaults to the currently committed quality * (`this._shadowQuality`), which is the right choice for re-running shadow setup without * changing the committed quality. The public `updateShadows` passes a resolved new quality. * @param abortSignal Optional external abort signal. * @returns A promise that resolves when the shadow update completes. */ protected _updateShadows(quality?: ShadowQuality, abortSignal?: AbortSignal): Promise; /** * @internal Engine-specific shadow setup. Subclasses implement this with their actual shadow * generation logic. The base class handles all surrounding orchestration: lock acquisition, * abort-prev semantics, quality resolution, and the success-only commit of `_shadowQuality`. * * Implementations should: * - Throw on failure; the base class propagates the error to the caller without committing the new quality. * - Use `quality` (not `this._shadowQuality`, which still holds the pre-update value) to drive the setup. * - Periodically re-check abort by calling `throwIfAborted(abortSignal, internalAbortSignal)` at safe points. */ protected abstract _updateShadowsImpl(quality: ShadowQuality, abortSignal: AbortSignal | undefined, internalAbortSignal: AbortSignal): Promise; /** * Disposes the viewer and releases shared resources (observables, disposed flag). * Subclasses MUST override this method to dispose their own engine-specific state * (engine, scene, abort controllers, models, etc.) and call `super.dispose()` last * so observable consumers see the engine-specific notifications before observables clear. * * Subclasses should also early-return if `_isDisposed` is already true. */ dispose(): void; /** * Resets the viewer to its initial state based on the options passed in to the constructor. * @param flags The flags that specify which parts of the viewer to reset. If no flags are provided, all parts will be reset. * - "source": Reset the loaded model. * - "environment": Reset environment related state. * - "shadow": Reset shadow related state. * - "animation": Reset animation related state. * - "camera": Reset camera related state. * - "post-processing": Reset post-processing related state. * - "material-variant": Reset material variant related state. */ reset(...flags: ResetFlag[]): void; /** * @internal * Orchestrates the reset operation in canonical flag order. The {@link interpolate} parameter is * forwarded to per-flag hooks (currently only `_resetCamera`) so internal callers can reset * without camera animation. */ protected _reset(interpolate: boolean, ...flags: ResetFlag[]): void; /** * @internal Resets the loaded model to the source specified at construction (or no model if no source was specified). */ protected _resetModel(): void; /** @internal */ protected abstract _resetEnvironment(): void; /** * @internal Resets the shadow configuration to the value specified at construction. */ protected _resetShadows(): void; /** @internal */ protected abstract _resetAnimation(): void; /** * @internal * @param interpolate If true, animate camera transitions when supported. Subclasses without bounds-based * reframing may ignore this parameter. */ protected abstract _resetCamera(interpolate: boolean): void; /** @internal */ protected abstract _resetPostProcessing(): void; /** * @internal Resets the selected material variant to the value specified at construction (or null if not specified). */ protected _resetMaterialVariant(): void; } /** * The options for the Lite Viewer. */ type ViewerOptions = ViewerBaseOptions; /** * Options for {@link Viewer.loadModel} on the Lite Viewer. */ type LoadModelOptions = ViewerLoadModelOptions; /** * Options for creating a Lite Viewer bound to a canvas. */ type CanvasViewerOptions = ViewerBaseOptions; /** * The default options for the Lite Viewer. */ declare const DefaultViewerOptions: { readonly clearColor: [0, 0, 0, 0]; readonly autoSuspendRendering: true; readonly environmentConfig: { readonly intensity: 1; readonly blur: 0.3; readonly rotation: 0; }; readonly environmentLighting: "auto"; readonly environmentSkybox: "none"; readonly cameraAutoOrbit: { readonly enabled: false; readonly delay: 2000; readonly speed: 0.05; }; readonly animationAutoPlay: false; readonly animationSpeed: 1; readonly shadowConfig: { readonly quality: "none"; }; readonly postProcessing: { readonly toneMapping: "neutral"; readonly contrast: 1; readonly exposure: 1; readonly ssao: "auto"; }; readonly useRightHandedSystem: false; readonly useOpenPBR: false; }; /** * A lightweight implementation of the {@link IViewer} interface built on the Babylon Lite API. * * @remarks * Babylon Lite is a WebGPU-only engine that provides a subset of the full Babylon.js feature set. * Features that are not available in Lite (SSAO, "high" shadow quality, hot spots, File/ArrayBufferView model sources) * will log warnings and fall back gracefully. * * The `autoSuspendRendering` option is silently ignored: Lite has no scene-mutation tracking, so it cannot * detect when a scene is idle. Rendering is still suspended while the canvas is offscreen (see * {@link CreateViewerForCanvas}), which is the case that dominates cost on pages with multiple viewers. */ declare class Viewer extends ViewerBase implements IViewer { private readonly _engine; protected readonly _options?: ViewerOptions | undefined; private readonly _scene; private readonly _camera; private readonly _deviceLostRecovery; private _detachControl; /** True while the engine's requestAnimationFrame loop is running. False while suspended or disposed. */ private _renderLoopRunning; /** * True once the scene has been registered with the engine (deferred builders run, renderables bucketed). * Distinct from {@link _renderLoopRunning}: suspending rendering stops the rAF loop but leaves the scene * registered, so code that needs to know "has the scene been built" must consult this instead. */ private _sceneRegistered; /** Number of live suspension handles returned by {@link _suspendRendering}. Rendering runs only at zero. */ private _suspendRenderCount; /** * Serializes every engine start/stop and scene (un)registration, so a suspend/resume triggered by the * offscreen observer can never interleave with {@link _beginRendering}'s stop, unregister, register, * start sequence (which is itself re-entered from model loads, environment loads, and construction). */ private readonly _renderLoopLock; /** * Resolves the pending `startEngine` await when the render loop is stopped before its first frame. * Lite's `startEngine` promise only settles from inside the rAF callback, so stopping the loop first * (by suspension or disposal) would otherwise leave the await pending forever. */ private _renderLoopStopped; private _autoOrbitIdleTime; private _lastPointerTime; /** The currently-loaded lighting URL ("auto" resolves to the embedded default). null = no lighting loaded. */ private _currentLightingUrl; /** The currently-loaded skybox URL ("auto" resolves to the embedded default). null = no skybox loaded. */ private _currentSkyboxUrl; private _toneMapping; private _contrast; private _exposure; private _ssaoOption; /** Serializes the async PBR-pipeline rebuilds triggered by image-processing updates * (`setSceneImageProcessing`) and environment relights (`rebuildScenePbrPipelines`), so overlapping * changes can't run concurrent rebuilds (which race on the scene's renderable list and leak). */ private readonly _pbrRebuildLock; private _shadowGenerator; private _shadowLight; private _shadowGround; private _container; /** GPU picker for double-click focus, created lazily on first double-click. Disposed with the viewer. */ private _picker; /** The source that was passed to the most recent {@link loadModel} call, for notifications. */ private _modelSource; /** * True once the first model load has built its Lite material group (via `registerScene`). Because * `_scene` is created once and never recreated, and glTF models all share Lite's singleton PBR group * builder, later model loads reuse that already-built group: their meshes are enqueued into the * per-frame material-swap queue and the running render loop materializes them, so those loads must * NOT re-register the scene (re-registration clears the swap queue and would drop the model). See the * (re-)registration decision in {@link _loadModelImpl}. */ private _modelMaterialGroupBuilt; /** Cached animation-aware model bounds for the current model. Reset on unload. See {@link _computeModelBounds}. */ private _cachedModelBounds; private _selectedAnimation; private _animationSpeed; private _wasPlaying; private _lastProgress; private _selectedMaterialVariant; private _camerasAsHotSpots; /** * Aborts the in-flight camera interpolation (from {@link focusHotSpot}) when a new one starts or * the viewer is disposed. Null when no interpolation is running. */ private _cameraInterpolationAbort; private _defaultAlpha; private _defaultBeta; private _defaultRadius; private _defaultTarget; /** * Creates a new Viewer instance. * @param _engine The Babylon Lite engine context. * @param _options Optional viewer configuration. */ constructor(_engine: EngineContext, _options?: ViewerOptions | undefined); /** @internal */ protected _applyClearColor(): void; /** @internal Lite stores auto-orbit state on the base class fields and consults them in its idle loop. No engine push needed. */ protected _applyCameraAutoOrbitEnabled(): void; /** @internal Lite stores auto-orbit state on the base class fields. */ protected _applyCameraAutoOrbitSpeed(): void; /** @internal Lite stores auto-orbit state on the base class fields. */ protected _applyCameraAutoOrbitDelay(): void; resetCamera(reframe?: boolean): void; /** * Shared implementation of camera reset. Resolves the reframe default (matching the full Viewer: * reframe to model bounds when the selected animation differs from the default, otherwise return to * the explicit default pose) and moves the camera there, optionally animating the transition. * @param reframe Whether to reframe to model bounds; when undefined, decided from animation state. * @param interpolate Whether to animate the camera to the reset pose. */ private _resetCameraCore; updateCamera(pose: { alpha?: number; beta?: number; radius?: number; targetX?: number; targetY?: number; targetZ?: number; }): void; /** * Moves the camera to a goal pose, either by animating (via {@link interpolateArcRotateCamera}) or by * snapping directly. Either way, any in-flight interpolation is first canceled so it can't fight the * new pose. Omitted or NaN goal fields keep the camera's current value for that channel. * @param goal The destination camera pose. * @param interpolate Whether to animate the transition. */ private _moveCameraTo; /** * Frames the camera to the loaded model's bounds, matching the full Viewer's framing math. Near/far * planes and zoom limits are applied immediately; the orbit pose is moved (snapped or animated) via * {@link _moveCameraTo}. * * When `applyDefaultPoseOverrides` is true, the bounds-derived orbit pose is overridden per-channel by * any explicit `cameraOrbit`/`cameraTarget` options — mirroring the full Viewer's * `_resetCamera` -> `_reframeCameraFromBounds`. With no such options this equals the pure bounds * framing used on model load, so a reset returns to exactly the load-time framing. * @param interpolate Whether to animate the camera to the framing pose. * @param applyDefaultPoseOverrides Whether to override the bounds pose with explicit camera options. * @returns True if the model had bounds and the camera was framed; false if there is no model to frame. */ private _frameCameraToModel; /** * Compute the aggregate world-space bounding box of the loaded model, accounting for * animation. * * Delegates to Lite's {@link computeMaxExtents}, which steps through the currently-selected * animation group and unions every sampled pose. This captures the full swept volume of * node (TRS), skeletal, and morph-target animation — so skinned models like the * acrobaticPlane glTF frame correctly instead of reporting their (much smaller) bind-pose * AABB. Meshes are gathered with {@link getContainerMeshes} so Viewer-added meshes (e.g. the * shadow-receiver disc) are excluded. * * The result is cached for the lifetime of the loaded model (reset in * `_unloadCurrentModel`) so the two consumers — `_frameCameraToModel` (camera target + * radius + near/far planes) and `_setupShadows` (light positioning, ground placement, * frustum sizing) — share a single animation sweep rather than stepping it twice. * * @returns aggregate `min`, `max`, `center`, and bounding-sphere `radius` * (= half the diagonal), or `null` if the model has no bounds info. */ private _computeModelBounds; /** @internal Lite has no engine state for intensity. */ protected _applyEnvironmentIntensity(): void; /** @internal */ protected _applyEnvironmentBlur(): void; /** @internal */ protected _applyEnvironmentRotation(): void; /** @internal */ protected _loadEnvironmentImpl(url: Nullable, options: ResolvedLoadEnvironmentOptions, abortSignal: AbortSignal | undefined, compositeAbortSignal: AbortSignal): Promise; get postProcessing(): Readonly; set postProcessing(value: Partial>); /** * Apply the current committed post-processing state to the running scene via * `setSceneImageProcessing`, serialized through {@link _pbrRebuildLock} so overlapping calls * never run concurrent PBR-pipeline rebuilds. Each queued apply re-reads the latest committed state * when it runs, so a burst of rapid changes collapses to the final state (intermediate updates that * no longer differ are no-ops). */ private _applyImageProcessingDynamic; /** * Force a rebuild of the loaded model's PBR pipelines so they pick up the scene's current environment * (IBL) textures. Needed because Lite bakes the environment into the PBR shaders at build time and * `loadEnvironment` doesn't rebuild existing PBR groups, so a model built before its environment loads * renders unlit/black. Used when an environment is added or changed AFTER a model is already displayed. * * `rebuildScenePbrPipelines` re-runs the PBR group builder against the scene's current `_envTextures`, * producing pipelines pixel-identical to a model built with the environment present from the start. * * Serialized through {@link _pbrRebuildLock} with the other image-processing updates (which also * rebuild PBR pipelines) so the two can't race. * @returns A promise that resolves once the model's PBR pipelines have been rebuilt. */ private _rebuildModelPbrForEnvironment; /** * Build the Babylon Lite {@link ImageProcessingUpdate} that mirrors the Viewer's committed * post-processing state (`_toneMapping`, `_exposure`, `_contrast`). SSAO has no * `scene.imageProcessing` slot in Lite — it's tracked in `_ssaoOption` but doesn't render anything * yet (Lite has no SSAO support). * @returns The Lite image-processing update mirroring the Viewer's committed state. */ private _liteImageProcessingUpdate; /** * Push the Viewer's committed post-processing state directly into `scene.imageProcessing`. Used on * paths where the scene is not yet registered or is about to be (re-)registered — construction, and * after env loads (Lite's env loader overwrites `scene.imageProcessing` with its own defaults, so we * re-push our values before re-registration bakes them into the shaders). The dynamic path (the * `postProcessing` setter) instead uses `setSceneImageProcessing` for a targeted pipeline rebuild. */ private _applyImageProcessingToScene; /** * Updates the shadow configuration. * @param value The new shadow configuration. * @param abortSignal Optional signal that can be used to abort the update externally. * @returns A promise that resolves when the shadow update completes. */ updateShadows(value: Partial>, abortSignal?: AbortSignal): Promise; /** * @internal * Lite cannot cleanly add or remove shadow infrastructure (light, ground disc, shadow generator) * after the scene has been registered. Adding meshes post-register requires re-running deferred * GPU builders, which corrupts the existing model's pipeline state. Reloading the model breaks * for similar reasons (the previous scene state isn't fully torn down). * * For now, shadow quality is effectively fixed at the value provided in the initial constructor * options: `_setupShadows` runs once during `_loadModelImpl` (before `addToScene` and the first * `registerScene`), so initial setup works correctly. Subsequent calls to `updateShadows` change * the committed `_shadowQuality` field but do not re-run shadow setup. Callers that need to * change shadow quality should recreate the viewer. */ protected _updateShadowsImpl(quality: ShadowQuality, abortSignal: AbortSignal | undefined, internalAbortSignal: AbortSignal): Promise; private _setupShadows; private _rotateShadowLightWithEnvironment; /** @internal */ protected _loadModelImpl(source: string | File | ArrayBufferView | undefined, options: ViewerLoadModelOptions | undefined, abortSignal: AbortSignal | undefined, internalAbortSignal: AbortSignal): Promise; private _unloadCurrentModel; get animations(): readonly string[]; get selectedAnimation(): number; set selectedAnimation(index: number); get animationSpeed(): number; set animationSpeed(value: number); get isAnimationPlaying(): boolean; get animationProgress(): number; set animationProgress(value: number); toggleAnimation(): void; playAnimation(): void; pauseAnimation(): Promise; private _getActiveAnimationGroup; /** * Enforces the "only the selected animation may be playing" invariant by stopping every * non-selected animation group (`stopAnimation` blocks subsequent ticks) and pausing the * selected one (so its tick still runs and applies the current-time pose). * * Lite's `tickAnimation` writes bone TRS every frame regardless of `playing`, so a merely * paused non-selected group would still pollute the mesh transforms with its current frame's * pose. Only `stopAnimation` blocks tick entirely. * * The selected group's tick must be allowed to run (so switching between animations updates * the pose). Lite's `pauseAnimation` doesn't un-stop a previously-stopped group, so we run * `playAnimation` then `pauseAnimation` to clear the stopped flag while ending up paused — * the tick fires next frame and applies the time-0 pose. */ private _isolateSelectedAnimation; private _setupAnimations; private _pollAnimationState; get materialVariants(): readonly string[]; get selectedMaterialVariant(): Nullable; set selectedMaterialVariant(value: Nullable); get camerasAsHotSpots(): boolean; set camerasAsHotSpots(value: boolean); queryHotSpot(name: string, result: ViewerHotSpotResult): boolean; focusHotSpot(name: string): boolean; /** * Starts a camera interpolation toward the given goal pose, canceling any interpolation already in * flight. Lite's arc-rotate camera has no built-in interpolation, so this drives * {@link interpolateArcRotateCamera} from the scene render loop. The returned promise is intentionally * swallowed: it rejects when the transition is superseded, aborted, or interrupted by user input, * none of which are error conditions here. * @param goal The destination camera pose; omitted fields keep the current value. */ private _interpolateCameraTo; /** * Resolves a named hotspot to its world position, screen position, and visibility, writing the * result into `result`. Returns the hotspot definition on success (so callers like * {@link focusHotSpot} can read its `cameraOrbit`), or `null` if the hotspot is unknown or cannot * be resolved (e.g. an out-of-range surface vertex). * * Surface hotspots track skeletal + morph animation: the three referenced vertices are deformed * for the current frame via {@link computeDeformedPositionToRef} (mesh-local), barycentric- * blended, then transformed to world space by the mesh world matrix — mirroring Babylon.js core's * `GetHotSpotToRef`. World hotspots use their fixed position/normal. * @param name The name of the hotspot to resolve. * @param result The result object to write the world position, screen position, and visibility into. * @returns The hotspot definition on success, or `null` if it cannot be resolved. */ private _queryHotSpot; /** * Computes the world-space position and normal of a surface hotspot on `mesh` from three vertex * indices and barycentric weights, applying the mesh's current animation pose. Mirrors core's * `GetHotSpotToRef`: deform each vertex to mesh-local space, blend by barycentric, then transform * the single blended point (and the local triangle normal) to world space. * @param mesh The mesh the hotspot is anchored to. * @param pointIndex The three vertex indices defining the hotspot's triangle. * @param barycentric The barycentric weights blending the three vertices. * @param outPos Receives the world-space hotspot position. * @param outNormal Receives the world-space hotspot normal. * @returns `true` if the position and normal were computed, or `false` if a vertex is out of range. */ private _getSurfaceHotSpotToRef; get isModelLoaded(): boolean; /** @internal */ protected _resetEnvironment(): void; /** @internal */ protected _resetAnimation(): void; /** * @internal * Resets the camera to its default/framing pose, animating the transition when `interpolate` is true * (e.g. a user-initiated reset) and snapping when false (e.g. an initial reset before the first frame). */ protected _resetCamera(interpolate: boolean): void; /** @internal */ protected _resetPostProcessing(): void; /** * Registers the scene with the engine and starts the render loop. * Safe to call multiple times — stops and re-registers if already running. * @remarks * Serialized against suspend/resume via {@link _renderLoopLock} so a scroll-driven suspension can never * land in the middle of the stop, unregister, register, start sequence below. */ private _beginRendering; /** * Starts the engine's render loop, unless rendering is suspended (or the viewer is disposed), and waits * for the first frame. * @remarks * Lite's `startEngine` promise resolves from inside the rAF callback, so it never settles if the loop is * stopped before that first frame. {@link _renderLoopStopped} races against it so a suspension or a * disposal arriving in that window can't leave this await (and any model load awaiting it) pending forever. */ private _startRenderLoop; /** Stops the engine's render loop (if running) and releases anyone awaiting its first frame. */ private _stopRenderLoop; /** * Suspends rendering until the returned disposable is disposed. * @remarks * Reference counted, mirroring the full Viewer: rendering only resumes once every suspension handle has * been disposed. The scene stays registered while suspended, so resuming does not rebuild anything. * @returns A disposable that resumes rendering (when no other suspensions are outstanding). * @internal */ _suspendRendering(): IDisposable; dispose(): void; private _onPointerActivity; /** * Handles a canvas double-click: GPU-picks the model at the cursor and, on a hit, focuses the camera * on the picked point; on a miss (background), reframes the camera. Mirrors the full Viewer's * `POINTERDOUBLETAP` handler. * @param event The double-click mouse event; its offset coordinates locate the pick on the canvas. */ private _onCanvasDoubleClick; /** * Picks the model at the given canvas coordinates and either focuses the picked point (hit) or * reframes the camera (miss). Only the loaded model's meshes are pickable, so Viewer-added meshes * (e.g. the shadow-receiver disc) never swallow a pick or count as a "model" hit. * @param x The canvas-relative CSS x coordinate of the double-click. * @param y The canvas-relative CSS y coordinate of the double-click. */ private _handleDoubleClick; /** * Focuses the camera on a world-space point, mirroring the full Viewer's double-tap-on-model behavior. * The target and radius are first snapped so the point lies on the current view axis at its picked * depth — this preserves the camera position and avoids a dolly along the view axis — then the target * is interpolated to the actual point (orbit angles and radius held). * @param point The world-space point to focus on. */ private _focusCameraOnPoint; private _updateAutoOrbit; } /** * Creates a new {@link Viewer} instance for the given canvas element. * @param canvas The HTML canvas element to render into. * @param options Optional viewer configuration. * @returns A promise that resolves to the initialized Viewer. */ declare function CreateViewerForCanvas(canvas: HTMLCanvasElement, options?: CanvasViewerOptions): Promise; type ResetMode = "auto" | "reframe" | [ResetFlag, ...flags: ResetFlag[]]; interface ViewerElementEventMap extends HTMLElementEventMap { viewerready: Event; viewerrender: Event; environmentchange: Event; environmentconfigurationchange: Event; environmenterror: ErrorEvent; shadowsconfigurationchange: Event; modelchange: CustomEvent>; modelerror: ErrorEvent; loadingprogresschange: Event; selectedanimationchange: Event; animationspeedchange: Event; animationplayingchange: Event; animationprogresschange: Event; selectedmaterialvariantchange: Event; } interface ViewerElementBase { addEventListener(type: K, listener: (this: HTMLElement, ev: ViewerElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; removeEventListener(type: K, listener: (this: HTMLElement, ev: ViewerElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } /** * Abstract base class for viewer custom elements. * Contains all shared UI logic and depends only on IViewer. */ declare abstract class ViewerElementBase extends LitElement { protected readonly _options: Options; private readonly _viewerLock; private _animationSliderResizeObserver; /** @internal */ protected _viewer?: ViewerClass; /** * Creates an instance of a ViewerElementBase subclass. * @param _options The options to use when creating the Viewer. */ protected constructor(_options?: Options); private readonly _propertyBindings; /** @internal */ static get observedAttributes(): string[]; /** @internal */ static styles: CSSResultGroup; /** * Get hotspot world and screen values from a named hotspot * @param name slot of the hot spot * @param result resulting world and screen positions * @returns world position, world normal and screen space coordinates */ queryHotSpot(name: string, result: ViewerHotSpotResult): boolean; /** * Updates the camera to focus on a named hotspot. * @param name The name of the hotspot to focus on. * @returns true if the hotspot was found and the camera was updated, false otherwise. */ focusHotSpot(name: string): boolean; protected accessor _isFaultedBacking: boolean; protected get _isFaulted(): boolean; /** * When true, the scene will be rendered even if no scene state has changed. */ accessor renderWhenIdle: boolean; /** * The model URL. */ accessor source: Nullable; /** * Forces the model to be loaded with the specified extension. * @remarks * If this property is not set, the extension will be inferred from the model URL when possible. */ accessor extension: Nullable; /** * If true, load glTF files using the OpenPBR material instead of the default PBR material. * @experimental */ accessor useOpenPBR: boolean; /** * The texture URLs used for lighting and skybox. Setting this property will set both environmentLighting and environmentSkybox. */ get environment(): { lighting: Nullable; skybox: Nullable; }; set environment(url: string); /** * The texture URL for lighting. */ accessor environmentLighting: Nullable; /** * The texture URL for the skybox. */ accessor environmentSkybox: Nullable; /** * A value between 0 and 2 that specifies the intensity of the environment lighting. */ accessor environmentIntensity: Nullable; /** * A value in radians that specifies the rotation of the environment. */ accessor environmentRotation: Nullable; /** * The type of shadows to use. */ accessor shadowQuality: Nullable; private accessor _loadingProgress; /** * Gets information about loading activity. * @remarks * false indicates no loading activity. * true indicates loading activity with no progress information. * A number between 0 and 1 indicates loading activity with progress information. */ get loadingProgress(): boolean | number; /** * A value between 0 and 1 that specifies how much to blur the skybox. */ accessor skyboxBlur: Nullable; /** * The tone mapping to use for rendering the scene. */ accessor toneMapping: Nullable; /** * The contrast applied to the scene. */ accessor contrast: Nullable; /** * The exposure applied to the scene. */ accessor exposure: Nullable; /** * Enables or disables screen space ambient occlusion (SSAO). */ accessor ssao: Nullable; /** * The clear color (e.g. background color) for the viewer. */ accessor clearColor: Nullable; /** * Enables or disables camera auto-orbit. */ accessor cameraAutoOrbit: boolean; /** * The speed at which the camera auto-orbits around the target. */ accessor cameraAutoOrbitSpeed: Nullable; /** * The delay in milliseconds before the camera starts auto-orbiting. */ accessor cameraAutoOrbitDelay: Nullable; /** * The set of defined hot spots. */ accessor hotSpots: Record; /** * True if the viewer has any hotspots. */ protected get _hasHotSpots(): boolean; /** * True if the default animation should play automatically when a model is loaded. */ accessor animationAutoPlay: boolean; /** * The list of animation names for the currently loaded model. */ get animations(): readonly string[]; /** * True if the loaded model has any animations. */ protected get _hasAnimations(): boolean; /** * The currently selected animation index. */ accessor selectedAnimation: Nullable; /** * True if an animation is currently playing. */ get isAnimationPlaying(): boolean; /** * The speed scale at which animations are played. */ accessor animationSpeed: number; /** * The current point on the selected animation timeline, normalized between 0 and 1. */ accessor animationProgress: number; private accessor _animations; private accessor _isAnimationPlaying; private accessor _showAnimationSlider; /** * The list of material variants for the currently loaded model. */ get materialVariants(): readonly string[]; /** * The currently selected material variant. */ accessor selectedMaterialVariant: Nullable; /** * True if scene cameras should be used as hotspots. */ accessor camerasAsHotSpots: boolean; /** * Determines the behavior of the reset function, and the associated default reset button. * @remarks * - "auto" - Resets the camera to the initial pose if it makes sense given other viewer state, such as the selected animation. * - "reframe" - Reframes the camera based on the current viewer state (ignores the initial pose). * - [ResetFlag] - A space separated list of reset flags that reset various aspects of the viewer state. */ accessor resetMode: ResetMode; private accessor _canvasContainer; private accessor _hotSpotSelect; /** * Toggles the play/pause animation state if there is a selected animation. */ toggleAnimation(): void; /** * Resets the Viewer state based on the @see resetMode property. */ reset(): void; private _reset; /** * Resets the camera to its initial pose. */ resetCamera(): void; /** * Reloads the viewer. This is typically only needed when the viewer is in a faulted state (e.g. due to the context being lost). */ reload(): void; /** @internal */ connectedCallback(): void; /** @internal */ disconnectedCallback(): void; /** @internal */ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void; /** @internal */ protected update(changedProperties: PropertyValues): void; /** * Determines whether a full viewer reload is required for the given property changes. * Subclasses can override to add additional reload triggers. * @param changedProperties The properties that have changed. * @returns True if the viewer needs to be reloaded. */ protected _needsReload(changedProperties: Map): boolean; /** @internal */ protected render(): TemplateResult<1>; /** * Renders the progress bar. * @returns The template result for the progress bar. */ protected _renderProgressBar(): TemplateResult; /** * Renders the toolbar. * @returns The template result for the toolbar. */ protected _renderToolbar(): TemplateResult; /** * Renders the reload button. * @returns The template result for the reload button. */ protected _renderReloadButton(): TemplateResult; /** * Renders UI elements that overlay the viewer. * Override this method to provide additional rendering for the component. * @returns TemplateResult The rendered template result. */ protected _renderOverlay(): TemplateResult; /** * Dispatches a custom event. * @param type The type of the event. * @param event A function that creates the event. */ protected _dispatchCustomEvent(type: TEvent, event: (type: TEvent) => ViewerElementEventMap[TEvent]): void; /** * Handles changes to the selected animation. * @param event The change event. */ protected _onSelectedAnimationChanged(event: Event): void; /** * Handles changes to the animation speed. * @param event The change event. */ protected _onAnimationSpeedChanged(event: Event): void; /** * Handles changes to the animation timeline. * @param event The change event. */ protected _onAnimationTimelineChanged(event: Event): void; /** * Handles pointer down events on the animation timeline. * @param event The pointer down event. */ protected _onAnimationTimelinePointerDown(event: Event): void; /** * Handles changes to the selected material variant. * @param event The change event. */ protected _onMaterialVariantChanged(event: Event): void; /** * Handles changes to the hot spot list. * @param event The change event. */ protected _onHotSpotsChanged(event: Event): void; private _onAnimationSliderChanged; private _createPropertyBinding; /** * Creates a viewer for the specified canvas. * Subclasses must implement this to return an appropriate IViewer instance. * @param canvas The canvas to create the viewer for. * @returns The created viewer. */ protected abstract _createViewer(canvas: HTMLCanvasElement, options: Options): Promise; private _setupViewer; private _tearDownViewer; /** * Called during teardown after the viewer has been disposed. * Subclasses can override to clean up additional state. */ protected _onViewerTornDown(): void; private _updateModel; private _updateEnv; private _updateShadows; } /** * Viewer custom element backed by the Babylon Lite engine (WebGPU-only). * Provides the same `` tag as the full viewer — the two are mutually exclusive. */ declare abstract class ViewerElement extends ViewerElementBase { protected constructor(options?: CanvasViewerOptions); /** * Gets the underlying Viewer instance (when the viewer is in a loaded state). */ get viewer(): Viewer | undefined; protected _createViewer(canvas: HTMLCanvasElement, options: CanvasViewerOptions): Promise; } /** * Displays a 3D model using the Babylon Lite Viewer (WebGPU-only). * @remarks * This element registers as `` and is mutually exclusive with the full Babylon.js viewer element. * Import `@babylonjs/viewer/lite` instead of `@babylonjs/viewer` to use the Lite viewer. */ declare class HTML3DElement extends ViewerElement { /** * Creates a new HTML3DElement backed by the Lite viewer. * @param options The options to use for the viewer. */ constructor(options?: Readonly); } /** * Creates a custom HTML element that creates an HTML3DElement with the specified name and configuration. * @param elementName The name of the custom element. * @param options The options to use for the viewer. */ declare function ConfigureCustomViewerElement(elementName: string, options: Readonly): void; /** * Displays child elements at the screen space location of a hotspot in a babylon-viewer. * @remarks * The babylon-viewer-annotation element must be a child of a babylon-viewer element. */ declare class HTML3DAnnotationElement extends LitElement { /** @internal */ static styles: lit.CSSResult; private readonly _internals; private readonly _mutationObserver; private _viewerAttachment; private _connectingAbortController; private _updateAnnotation; /** * The name of the hotspot to track. */ accessor hotSpot: string; /** @internal */ connectedCallback(): void; /** @internal */ disconnectedCallback(): void; /** @internal */ protected render(): lit_html.TemplateResult<1>; /** @internal */ protected update(changedProperties: PropertyValues): void; private _sanitizeInnerHTML; } export { ConfigureCustomViewerElement, CreateViewerForCanvas, DefaultViewerOptions, HTML3DAnnotationElement, HTML3DElement, Viewer, ViewerElement, ViewerHotSpotResult }; export type { CameraAutoOrbit, CanvasViewerOptions, EnvironmentOptions, HotSpot, LoadModelOptions, PostProcessing, ShadowQuality, ToneMapping, ViewerElementEventMap, ViewerHotSpotQuery, ViewerOptions };