Files
ComfyUI_frontend/src/extensions/core/load3d/interfaces.ts
Johnpaul Chiwetelu 538f007f1d Road to No Explicit Any Part 5: load3d Module (#8064)
## Summary
- Removes all `any` types from the load3d module
- Uses generics for EventCallback to provide type-safe event handling
- Types node parameters with LGraphNode
- Types onExecuted callback with NodeExecutionOutput
- Types Camera Config property casts with CameraConfig interface

## Changes
- `interfaces.ts`: EventCallback<T> generic, EventManagerInterface
generic methods
- `EventManager.ts`: Generic
emitEvent/addEventListener/removeEventListener
- `AnimationManager.ts`: setupModelAnimations originalModel typed as
GLTF union
- `Load3d.ts`: Event listener methods use EventCallback<T>
- `load3d.ts`: Node params typed as LGraphNode, onExecuted uses
NodeExecutionOutput, CameraConfig casts

## Test plan
- [x] `pnpm typecheck` passes
- [x] `pnpm lint` passes
- [x] `pnpm test:unit` passes

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8064-Road-to-No-Explicit-Any-Part-5-load3d-Module-2e96d73d365081efbc01f2d8a4f3c11f)
by [Unito](https://www.unito.io)
2026-01-15 02:21:38 +01:00

207 lines
5.7 KiB
TypeScript

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { ViewHelper } from 'three/examples/jsm/helpers/ViewHelper'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { type GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader'
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader'
import { type OBJLoader2Parallel } from 'wwobjloader2'
export type MaterialMode =
| 'original'
| 'pointCloud'
| 'normal'
| 'wireframe'
| 'depth'
export type UpDirection = 'original' | '-x' | '+x' | '-y' | '+y' | '-z' | '+z'
export type CameraType = 'perspective' | 'orthographic'
export type BackgroundRenderModeType = 'tiled' | 'panorama'
export interface CameraState {
position: THREE.Vector3
target: THREE.Vector3
zoom: number
cameraType: CameraType
}
export interface SceneConfig {
showGrid: boolean
backgroundColor: string
backgroundImage?: string
backgroundRenderMode?: BackgroundRenderModeType
}
export interface ModelConfig {
upDirection: UpDirection
materialMode: MaterialMode
showSkeleton: boolean
}
export interface CameraConfig {
cameraType: CameraType
fov: number
state?: CameraState
}
export interface LightConfig {
intensity: number
}
export interface EventCallback<T = unknown> {
(data: T): void
}
export interface Load3DOptions {
// Optional target dimensions for aspect ratio control
width?: number
height?: number
// Dynamic dimension provider (called on every render)
// Use this for reactive dimensions that change over time
getDimensions?: () => { width: number; height: number } | null
// Viewer mode flag (affects aspect ratio behavior)
isViewerMode?: boolean
// Optional context menu callback
onContextMenu?: (event: MouseEvent) => void
}
export interface CaptureResult {
scene: string
mask: string
normal: string
}
interface BaseManager {
init(): void
dispose(): void
reset(): void
}
export interface AnimationItem {
name: string
index: number
}
export interface SceneManagerInterface extends BaseManager {
scene: THREE.Scene
gridHelper: THREE.GridHelper
toggleGrid(showGrid: boolean): void
setBackgroundColor(color: string): void
setBackgroundImage(uploadPath: string): Promise<void>
removeBackgroundImage(): void
setBackgroundRenderMode(mode: BackgroundRenderModeType): void
handleResize(width: number, height: number): void
captureScene(width: number, height: number): Promise<CaptureResult>
}
export interface CameraManagerInterface extends BaseManager {
activeCamera: THREE.Camera
perspectiveCamera: THREE.PerspectiveCamera
orthographicCamera: THREE.OrthographicCamera
getCurrentCameraType(): CameraType
toggleCamera(cameraType?: CameraType): void
setFOV(fov: number): void
setCameraState(state: CameraState): void
getCameraState(): CameraState
handleResize(width: number, height: number): void
setControls(controls: OrbitControls): void
}
export interface ControlsManagerInterface extends BaseManager {
controls: OrbitControls
handleResize(): void
}
export interface LightingManagerInterface extends BaseManager {
lights: THREE.Light[]
setLightIntensity(intensity: number): void
}
export interface ViewHelperManagerInterface extends BaseManager {
viewHelper: ViewHelper
viewHelperContainer: HTMLDivElement
createViewHelper(container: Element | HTMLElement): void
update(delta: number): void
handleResize(): void
}
export interface EventManagerInterface {
addEventListener<T>(event: string, callback: EventCallback<T>): void
removeEventListener<T>(event: string, callback: EventCallback<T>): void
emitEvent<T>(event: string, data: T): void
}
export interface AnimationManagerInterface extends BaseManager {
currentAnimation: THREE.AnimationMixer | null
animationActions: THREE.AnimationAction[]
animationClips: THREE.AnimationClip[]
selectedAnimationIndex: number
isAnimationPlaying: boolean
animationSpeed: number
setupModelAnimations(
model: THREE.Object3D,
originalModel: THREE.Object3D | THREE.BufferGeometry | GLTF | null
): void
updateAnimationList(): void
setAnimationSpeed(speed: number): void
updateSelectedAnimation(index: number): void
toggleAnimation(play?: boolean): void
update(delta: number): void
getAnimationTime(): number
getAnimationDuration(): number
setAnimationTime(time: number): void
}
export interface ModelManagerInterface {
originalFileName: string | null
originalURL: string | null
currentModel: THREE.Object3D | null
originalModel: THREE.Object3D | THREE.BufferGeometry | GLTF | null
originalRotation: THREE.Euler | null
currentUpDirection: UpDirection
init(): void
dispose(): void
clearModel(): void
reset(): void
setupModel(model: THREE.Object3D): Promise<void>
addModelToScene(model: THREE.Object3D): void
setOriginalModel(model: THREE.Object3D | THREE.BufferGeometry | GLTF): void
setUpDirection(direction: UpDirection): void
materialMode: MaterialMode
originalMaterials: WeakMap<THREE.Mesh, THREE.Material | THREE.Material[]>
normalMaterial: THREE.MeshNormalMaterial
standardMaterial: THREE.MeshStandardMaterial
wireframeMaterial: THREE.MeshBasicMaterial
depthMaterial: THREE.MeshDepthMaterial
setMaterialMode(mode: MaterialMode): void
setupModelMaterials(model: THREE.Object3D): void
}
export interface LoaderManagerInterface {
gltfLoader: GLTFLoader
objLoader: OBJLoader2Parallel
mtlLoader: MTLLoader
fbxLoader: FBXLoader
stlLoader: STLLoader
init(): void
dispose(): void
loadModel(url: string, originalFileName?: string): Promise<void>
}
export const SUPPORTED_EXTENSIONS = new Set([
'.gltf',
'.glb',
'.obj',
'.fbx',
'.stl',
'.spz',
'.splat',
'.ply',
'.ksplat'
])