Appearance
LoaderService
Loads 3D model files into the scene. Handles GLTF/GLB, FBX, PLY, LAS (modern ILoader-based), STL, OBJ (legacy), and chunked manifest-based models.
Access
Registered under the name "loader". No service dependencies.
ts
import { LoaderService } from "@optellix/xviewr-sdk";
await viewer.ready();
const loader = viewer.getService<LoaderService>("loader");
const model = await loader?.loadFile({
url: "/models/part.glb",
type: "glb",
filename: "part.glb",
});Public API
Lifecycle
init(context: ServiceContext): Promise<void>destroy(): Promise<void>getStatus(): ServiceStatus
Loading
loadFile(fileSpec: FileSpec, options?: LoadOptions): Promise<THREE.Object3D>— generic entry point. Dispatches byfileSpec.type. Fortype: "chunked", delegates toloadChunkedModel.loadChunkedModel(manifestUrl: string, options?: ChunkedLoadOptions & { fileSpec?: FileSpec }): Promise<THREE.Group>— fetches a chunk manifest, loads baseline LOD chunks concurrently, returns a rootGroup. Detail LODs are loaded on demand byLODService.
Registration / queries
registerLoader(loader: ILoader): Promise<void>— register a custom loader by extension.getSupportedFormats(): string[]— flat list of extensions plus"chunked".
Types
ILoader
ts
interface ILoader {
readonly name: string;
readonly supportedExtensions: string[]; // e.g. [".glb", ".gltf"]
readonly description: string;
canLoad(url: string, extension: string): boolean;
load(url: string, options?: ILoaderOptions): Promise<LoadResult>;
dispose?(): void;
}ILoaderOptions
ts
interface ILoaderOptions {
onProgress?: (progress: number) => void;
signal?: AbortSignal;
}LoadResult
ts
interface LoadResult {
object3d: THREE.Object3D;
metadata: {
format: string;
fileName: string;
fileSize?: number;
loadedAt?: string;
loadedBy?: string;
statistics?: { triangles: number; vertices: number; objects: number };
[key: string]: any;
};
}Events
| Event | Payload |
|---|---|
loader:registered | { loader: string; extensions: string[] } |
model:loading-started | { fileSpec: FileSpec } |
model:loading-progress | { fileSpec: FileSpec; progress: number } |
model:loading-error | { error: LoaderError; fileSpec: FileSpec } |
model:loaded | { model: THREE.Object3D; fileSpec: FileSpec } |
model:chunked-loading-started | { manifestUrl; root; fileSpec; chunkCount } |
model:chunk-loaded | { chunkId; root; group; fileSpec; loaded; total } |
model:chunked-ready | { root; fileSpec; chunkCount } |
model:edges-loaded | { scene; appliedCount } |
model:edges-failed | { url; reason } |
Example
ts
const loader = viewer.getService<LoaderService>("loader");
if (!loader) throw new Error("loader service unavailable");
const root = await loader.loadFile(
{ url: "/models/assembly.glb", type: "glb", filename: "assembly.glb" },
{ onProgress: (p) => console.log(`${(p * 100).toFixed(1)}%`) },
);
viewer.root.add(root);
// Chunked manifest
const chunked = await loader.loadChunkedModel("/chunks/manifest.json", {
baselineLevel: "lod0",
baselineConcurrency: 8,
onChunkLoaded: (id, loaded, total) =>
console.log(`chunk ${id}: ${loaded}/${total}`),
});
viewer.root.add(chunked);