UNPKG

prophetk-3d-viewer

Version:

A Three.js r128 based GLB/GLTF model viewer for WeChat Mini Program and Web.

313 lines (291 loc) • 11.6 kB
export interface ModelConfig { /** Parent model ID; TRS is relative to the parent. Missing parents defer display. */ parent?: string | null; id?: string; name?: string; url: string; position?: [number, number, number]; /** Euler XYZ degrees. */ rotation?: [number, number, number]; scale?: number | [number, number, number]; normalize?: boolean; /** Opt in to selection and dragging on a horizontal plane; default false. */ isMovable?: boolean; /** Hide this model and descendants when rendering, preserving interaction; default false. */ invisible?: boolean; /** Non-empty event name enables clicks, independently of isMovable. */ clickEvent?: string; } export type ModelPosition = [number, number, number]; export interface ModelTransform { /** Omitted for scene-root models. */ parent?: string; id: string; /** Current parent-local position, matching ModelConfig.position. */ position: ModelPosition; /** Euler XYZ degrees, regardless of the object's internal Euler order. */ rotation: [number, number, number]; scale: [number, number, number]; } export type ModelEventReason = 'pointer' | 'release' | 'multitouch' | 'touchcancel' | 'blur' | 'resize' | 'low-angle' | 'modelremoved' | 'scenechange' | 'selectioncleared' | 'dispose' | 'parentchange'; export type ModelEvent = { type: 'click'; modelId: string; event: string; } | { type: 'selectionchange'; modelId: string | null; previousModelId: string | null; reason: ModelEventReason; } | { type: 'dragstart' | 'drag' | 'dragend' | 'dragcancel' | 'dragblocked'; modelId: string; /** Parent-local coordinates, matching ModelConfig.position. */ startPosition: ModelPosition; position: ModelPosition; reason?: ModelEventReason; message?: string; }; export interface ModelTouchEvent { touches: ArrayLike<{ clientX: number; clientY: number; identifier?: number }>; changedTouches?: ArrayLike<{ clientX: number; clientY: number; identifier?: number }>; pointerType?: string; } export interface ModelWheelEvent { /** Negative zooms in; positive zooms out. */ deltaY: number; /** 0: pixels (default), 1: lines, 2: pages. */ deltaMode?: 0 | 1 | 2; ctrlKey?: boolean; } export interface DecalOptions { projectionMode?: 'cylindrical' | 'projector' | 'orthographic'; mode?: 'cylindrical' | 'projector' | 'orthographic'; angle?: number; height?: number; scaleX?: number; scaleY?: number; arcWidth?: number; heightRange?: number; opacity?: number; position?: [number, number, number]; direction?: [number, number, number]; targetPoint?: [number, number, number]; rotation?: [number, number, number]; roll?: number; rollDeg?: number; up?: [number, number, number]; width?: number; projectorPosition?: [number, number, number]; projectorDirection?: [number, number, number]; projectorTarget?: [number, number, number]; projectorRotation?: [number, number, number]; projectorRoll?: number; projectorRollDeg?: number; projectorUp?: [number, number, number]; projectorWidth?: number; projectorHeight?: number; projectorNormalThreshold?: number; normalThreshold?: number; } export interface SceneProjectorDecalConfig extends Omit<DecalOptions, 'target'> { target?: string; url?: string; debug?: boolean; debugColor?: number | string; debugLength?: number; } export interface SceneButtonUiConfig { type: 'button'; id?: string; /** Normalized screen-space position, origin at the canvas bottom-left corner. Usually 0..1. */ position?: [number, number]; /** Normalized button width and height relative to the canvas. Usually 0..1. */ scale?: [number, number]; text?: string; img?: string; alpha?: number; event?: string; backgroundColor?: string; borderColor?: string; color?: string; fontSize?: number; } export interface SceneSliderUiConfig { type: 'slider' | 'slide'; id?: string; /** Normalized screen-space position, origin at the canvas bottom-left corner. Usually 0..1. */ position?: [number, number]; /** Normalized slider width and height relative to the canvas. Usually 0..1. */ scale?: [number, number]; text?: string; min?: number; max?: number; value?: number; step?: number; alpha?: number; event?: string; /** Built-in target such as 'decal.scaleX' or 'decal.scaleY'. */ target?: string; trackColor?: string; fillColor?: string; thumbColor?: string; thumbBorderColor?: string; color?: string; fontSize?: number; } export interface SceneLabelUiConfig { type: 'label'; /** Unique id used by setUiLabelText(id, text). */ id: string; /** Normalized screen-space position, origin at the canvas bottom-left corner. Usually 0..1. */ position?: [number, number]; /** Normalized label width and height relative to the canvas. Usually 0..1. */ scale?: [number, number]; text?: string; alpha?: number; backgroundColor?: string; borderColor?: string; borderWidth?: number; radius?: number; padding?: number; color?: string; fontSize?: number; align?: 'left' | 'center' | 'right'; } export type SceneUiConfig = SceneButtonUiConfig | SceneSliderUiConfig | SceneLabelUiConfig; export type CameraControlMode = 'orbit' | 'pan'; export interface SceneCameraConfig { /** Single-finger / left-mouse drag on empty space. Defaults to orbit. */ controlMode?: CameraControlMode; position?: [number, number, number]; lookAt?: [number, number, number]; fov?: number; near?: number; far?: number; /** Spherical angles in radians; radius in world units. */ orbit?: { theta?: number; phi?: number; radius?: number }; [key: string]: unknown; } export interface SceneEnvironmentConfig { url?: string; showSkybox?: boolean; /** Show the horizontal reference grid while dragging. Defaults to true. */ showDragGrid?: boolean; /** Show the selected model's bounds. Defaults to true. */ showBounds?: boolean; [key: string]: unknown; } export interface SceneConfig { renderer?: Record<string, unknown>; environment?: SceneEnvironmentConfig; camera?: SceneCameraConfig; lights?: Array<Record<string, unknown>>; models?: ModelConfig[]; ui?: SceneUiConfig[]; decal?: DecalOptions & { target?: string; url?: string; decalAngleDeg?: number; decalHeight?: number; }; decal_projector?: SceneProjectorDecalConfig; decalProjector?: SceneProjectorDecalConfig; } export interface PlatformAdapter { getWindowInfo(): { pixelRatio?: number; windowWidth?: number; windowHeight?: number }; getPixelRatio(): number; getContext(canvas: unknown, type: string): unknown; requestJson(url: string): Promise<unknown>; fetchFile(url: string, options?: Record<string, unknown>): Promise<string>; fetchArrayBuffer(url: string, options?: Record<string, unknown>): Promise<ArrayBuffer>; readFileBase64?(path: string): Promise<string>; createImage(canvas?: unknown): unknown; createCanvas?(width: number, height: number): unknown; requestAnimationFrame(canvas: unknown, callback: FrameRequestCallback): number; cancelAnimationFrame(canvas: unknown, id: number): void; } export class ModelRenderer { constructor(canvas: unknown, options?: { platform?: PlatformAdapter; bgColor?: string; width?: number; height?: number; renderMode?: 'on-demand' | 'continuous'; onUiEvent?: (detail: { type: string; event: string; text?: string; x?: number; y?: number }) => void; onModelEvent?: (detail: ModelEvent) => void; }); setUiEventHandler(handler?: (detail: { type: string; event: string; text?: string; x?: number; y?: number }) => void): void; setUiLabelText(id: string, text: string): boolean; resize(width: number, height: number, rect?: { left?: number; top?: number }): void; loadModel(url: string | ModelConfig, options?: Partial<ModelConfig>): Promise<unknown>; switchModel(url: string | ModelConfig, options?: Partial<ModelConfig>): Promise<unknown>; loadScene(config?: SceneConfig | string): Promise<void>; clearModel(target: string | { id?: string; url?: string }): number; clearAllModels(): number; /** Preserve local TRS; null detaches to the scene root. */ setParent(modelId: string, parentId: string | null): void; SetParent(modelId: string, parentId: string | null): void; getSelectedModelId(): string | null; /** JSON-encoded ModelTransform[] for all loaded models, including waiting children; '[]' when empty. */ getModelTransforms(): string; clearSelection(): void; getCameraControlMode(): CameraControlMode; setCameraControlMode(mode: CameraControlMode): void; onTouchStart(event: ModelTouchEvent): void; onTouchMove(event: ModelTouchEvent): void; onTouchEnd(event: ModelTouchEvent): void; onTouchCancel(event?: Partial<ModelTouchEvent>, reason?: ModelEventReason): void; /** Returns whether the camera distance changed; both camera modes support wheel zoom. */ onWheel(event: ModelWheelEvent): boolean; applyDecal(url: string, options?: DecalOptions): Promise<void>; updateDecal(options: DecalOptions): void; updateDecal(angle: number, height: number, scaleX?: number, scaleY?: number): void; updateProjectorDecal(options?: DecalOptions): void; removeDecal(): void; dispose(): void; } export class WechatPlatformAdapter implements PlatformAdapter { constructor(options?: { wx?: unknown; canvas?: unknown }); } export class WebPlatformAdapter implements PlatformAdapter { constructor(options?: { window?: Window; document?: Document }); } export class WebModelViewer { constructor(options: { container: string | HTMLElement; canvas?: HTMLCanvasElement; bgColor?: string; width?: number; height?: number; renderMode?: 'on-demand' | 'continuous'; onUiEvent?: (detail: { type: string; event: string; text?: string; x?: number; y?: number }) => void; onModelEvent?: (detail: ModelEvent) => void; }); loadModel(url: string | ModelConfig, options?: Partial<ModelConfig>): Promise<unknown>; switchModel(url: string | ModelConfig, options?: Partial<ModelConfig>): Promise<unknown>; loadScene(config?: SceneConfig | string): Promise<void>; clearModel(target: string | { id?: string; url?: string }): number; clearAllModels(): number; /** Preserve local TRS; null detaches to the scene root. */ setParent(modelId: string, parentId: string | null): void; SetParent(modelId: string, parentId: string | null): void; getSelectedModelId(): string | null; /** JSON-encoded ModelTransform[] for all loaded models, including waiting children; '[]' when empty. */ getModelTransforms(): string; clearSelection(): void; getCameraControlMode(): CameraControlMode; setCameraControlMode(mode: CameraControlMode): void; applyDecal(url: string, options?: DecalOptions): Promise<void>; updateDecal(options: DecalOptions): void; updateDecal(angle: number, height: number, scaleX?: number, scaleY?: number): void; updateProjectorDecal(options?: DecalOptions): void; removeDecal(): void; setUiLabelText(id: string, text: string): boolean; resize(): void; dispose(): void; } export function createWebModelViewer(options: ConstructorParameters<typeof WebModelViewer>[0]): WebModelViewer; export const THREE: unknown; export const DEFAULT_SCENE_CONFIG: SceneConfig;