@vctrl/hooks
Version:
vctrl/hooks is a React hooks package designed to simplify 3D model loading and management within React applications. It's part of the vectreal-core ecosystem and is primarily used in the vctrl/viewer React component and the official website application.
245 lines (244 loc) • 9.38 kB
TypeScript
import { ModelFileTypes } from '../../../core/src/model-loader/index.ts';
import { Object3D } from 'three';
import { useOptimizeModel } from '../use-optimize-model';
import { default as eventSystem } from './event-system';
import { initialState } from './state';
import { ServerOptions, ServerSceneData } from '../../../core/src/index.ts';
export type { ExtendedGLTFDocument, SceneAssetDataEntry, SerializedSceneAssetDataMap as SceneAssetDataMap, ServerSceneData, ServerScenePayload } from '../../../core/src/index.ts';
/**
* Type representing the input for file/folder uploads.
* Can be either File objects or FileSystemDirectoryHandle for folder drag-and-drop.
*/
export type InputFileOrDirectory = (File | FileSystemDirectoryHandle)[];
/**
* Represents a loaded 3D model file with its metadata.
*/
export interface ModelFile {
/** The Three.js Object3D scene containing the loaded model */
model: Object3D;
/** The file type/format of the model (GLTF, GLB, USDZ) */
type: ModelFileTypes;
/** The original filename of the model */
name: string;
/** Byte size of referenced source package (gltf + referenced buffers/images) */
sourcePackageBytes?: number;
/** Byte size of referenced texture assets from source package */
sourceTextureBytes?: number;
}
/**
* Configuration options for loading a scene from the server.
*/
export interface SceneLoadOptions {
/** The unique identifier of the scene to load */
sceneId: string;
/** Server configuration (endpoint, auth, headers) */
serverOptions?: ServerOptions;
/** Whether to automatically apply scene settings (default: true) */
applySettings?: boolean;
/** 'direct' parses glTF JSON straight with GLTFLoader (view-only fast path). */
parseMode?: 'document' | 'direct';
}
/**
* Configuration options for loading an already-resolved scene payload.
*/
export interface SceneDataLoadOptions {
/** Optional scene identifier for resolved payloads. */
sceneId?: string;
/** Resolved server scene payload */
sceneData: ServerSceneData;
/** Whether to automatically apply scene settings (default: true) */
applySettings?: boolean;
/** 'direct' parses glTF JSON straight with GLTFLoader (view-only fast path). */
parseMode?: 'document' | 'direct';
}
/**
* Result of a scene load operation based on server data.
* Combines the loaded model with its settings.
*/
export interface SceneLoadResult extends ServerSceneData {
/** The loaded model file */
file: ModelFile;
/** Scene ID that was loaded */
sceneId?: string;
}
/**
* State interface for model loading data.
* Contains the current loaded file, loading status, and progress information.
*/
export interface LoadData {
/** The currently loaded model file, or null if no model is loaded */
file: ModelFile | null;
/** Whether a file is currently being loaded */
isFileLoading: boolean;
/** Loading progress percentage (0-100) */
progress: number;
/** List of supported model file types */
supportedFileTypes: ModelFileTypes[];
}
/**
* Action types for the model loading reducer.
* Defines all possible state mutations for model loading operations.
*/
export type Action = {
type: 'set-file';
payload: ModelFile;
} | {
type: 'set-file-loading';
payload: boolean;
} | {
type: 'set-progress';
payload: number;
} | {
type: 'reset-state';
};
/**
* Available event types emitted by the model loading system.
* Used for subscribing to various stages of the loading process.
*/
export type EventTypes = 'multiple-models' | 'not-loaded-files' | 'load-start' | 'load-progress' | 'load-complete' | 'load-reset' | 'load-error' | 'server-load-start' | 'server-load-complete' | 'server-load-error';
export type ViewerLoadErrorCode = 'unsupported_format' | 'binary_load_failed' | 'gltf_load_failed' | 'missing_assets' | 'server_load_failed' | 'not_found' | 'quota_exceeded' | 'unknown';
export interface StructuredLoadError {
code: ViewerLoadErrorCode;
message: string;
recoverable: boolean;
source: 'local-upload' | 'server-load';
cause?: unknown;
context?: Record<string, unknown>;
}
/**
* Maps event types to their corresponding data payloads.
* Ensures type safety when handling events.
*/
export type EventData = {
/** Array of model files when multiple are detected */
'multiple-models': File[];
/** Array of unsupported files */
'not-loaded-files': File[];
/** No data for load start event */
'load-start': null;
/** Progress value (0-100) */
'load-progress': number;
/** The loaded model file data */
'load-complete': LoadData['file'];
/** No data for reset event */
'load-reset': null;
/** Normalized error payload when loading fails */
'load-error': StructuredLoadError | Error | unknown;
/** Scene ID being loaded from server */
'server-load-start': string;
/** Complete scene load result */
'server-load-complete': SceneLoadResult;
/** Normalized error payload during server scene loading */
'server-load-error': StructuredLoadError | Error | unknown;
};
/**
* Type-safe event handler function.
* @template T - The event type being handled
*/
export type EventHandler<T extends EventTypes> = (data?: EventData[T]) => void;
/**
* Return type for the useLoadModel hook.
* Conditionally includes optimizer integration based on whether an optimizer was provided.
*
* @template HasOptimizer - Boolean indicating if optimizer integration is included
*/
export type UseLoadModelReturn<HasOptimizer extends boolean> = typeof initialState & {
/**
* Subscribe to model loading events.
* @param event - The event type to listen for
* @param handler - Callback function to handle the event
*/
on: typeof eventSystem.on;
/**
* Unsubscribe from model loading events.
* @param event - The event type to stop listening for
* @param handler - The callback function to remove
*/
off: typeof eventSystem.off;
/**
* Load 3D model files from File objects or directory handles.
* Supports GLTF, GLB, and USDZ formats with associated assets.
*/
load: (filesOrDirectories: InputFileOrDirectory) => Promise<void>;
/**
* Load a scene from already-resolved scene data.
* Preserves original asset payload semantics and bypasses upload-style file processing.
*/
loadFromData: (options: SceneDataLoadOptions) => Promise<SceneLoadResult>;
/**
* Load a scene from the server by scene ID.
* Fetches both the model and scene settings, applies them automatically.
*
* @param options - Scene loading configuration
* @returns Promise resolving to the loaded scene data
*
* @example
* ```tsx
* const model = useLoadModel()
*
* // Load a scene from the server
* const scene = await model.loadFromServer({
* sceneId: 'abc-123',
* serverOptions: {
* endpoint: '/api/load-scene',
* apiKey: 'optional-auth-token'
* }
* })
* ```
*/
loadFromServer: (options: SceneLoadOptions) => Promise<SceneLoadResult>;
/**
* Reset the model loading state and clear any loaded models.
*/
reset: () => void;
/**
* Optimizer integration object.
* - When optimizer is provided: Contains full optimization methods and state
* - When no optimizer: null
*/
optimizer: HasOptimizer extends true ? OptimizerIntegrationReturn<true> : null;
};
/**
* Return type of the useOptimizeModel hook.
* Provides access to all optimization methods and state.
*/
export type OptimizerReturnType = ReturnType<typeof useOptimizeModel>;
/**
* Conditional return type for optimizer integration.
* Extends the optimizer with additional integration methods when present.
*
* @template HasOptimizer - Boolean indicating if optimizer is integrated
*/
export type OptimizerIntegrationReturn<HasOptimizer extends boolean = false> = HasOptimizer extends true ? OptimizerReturnType & {
/**
* Whether the optimizer is still preparing the currently visible model.
*/
isPreparing: boolean;
/**
* Applies an optimization and updates the loaded model with the result.
*
* This method:
* 1. Runs the specified optimization function
* 2. Retrieves the optimized model
* 3. Loads it back into the scene
* 4. Updates the model state
*
* @template TOptions - Type of options for the optimization function
* @param optimizationFunction - The optimization to apply (e.g., simplifyOptimization)
* @param options - Configuration options for the optimization
* @returns Promise that resolves when optimization is complete and model is updated
*
* @example
* // Apply simplification optimization
* await optimizer.applyOptimization(
* optimizer.simplifyOptimization,
* { ratio: 0.5 }
* )
*
* @example
* // Apply multiple optimizations in sequence
* await optimizer.applyOptimization(optimizer.dedupOptimization)
* await optimizer.applyOptimization(optimizer.quantizeOptimization, { bits: 12 })
*/
applyOptimization: <TOptions>(optimizationFunction?: ((options?: TOptions) => Promise<void>) | undefined, options?: TOptions) => Promise<void>;
} : null;