UNPKG

@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
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;