UNPKG

ecspresso

Version:

A minimal Entity-Component-System library for typescript and javascript.

249 lines (248 loc) 8.65 kB
/** * 3D Renderer Plugin for ECSpresso * * An opt-in Three.js-based 3D rendering plugin that automates scene graph wiring. * Import from 'ecspresso/plugins/rendering/renderer3D' * * This plugin includes 3D transform propagation automatically. */ import type { WebGLRenderer, WebGLRendererParameters, Scene, Camera, Object3D, Mesh, Group, ColorRepresentation } from 'three'; import { type Plugin } from 'ecspresso'; import type { ComponentsConfig, EmptyConfig, EventsConfig, ResourcesConfig } from '../../type-utils'; import { type LocalTransform3D, type WorldTransform3D, type Transform3DComponentTypes, type Transform3DPluginOptions } from 'ecspresso/plugins/spatial/transform3D'; export type { LocalTransform3D, WorldTransform3D, Transform3DComponentTypes }; export { createTransform3D, createLocalTransform3D, createWorldTransform3D, DEFAULT_LOCAL_TRANSFORM_3D, DEFAULT_WORLD_TRANSFORM_3D, } from 'ecspresso/plugins/spatial/transform3D'; /** * Visibility component for 3D entities. */ export interface Visible3D { visible: boolean; } /** * Aggregate component types for the 3D renderer plugin. * Included automatically via `.withPlugin(createRenderer3DPlugin({ ... }))`. */ export interface Renderer3DComponentTypes extends Transform3DComponentTypes { mesh: Mesh; group: Group; object3d: Object3D; visible3d: Visible3D; /** Controls Three.js Object3D.renderOrder for manual z-ordering */ renderOrder: number; } /** * Events emitted by the 3D renderer plugin. */ export interface Renderer3DEventTypes { hierarchyChanged: { entityId: number; oldParent: number | null; newParent: number | null; }; } /** * Resources provided by the 3D renderer plugin. */ export interface Renderer3DResourceTypes { threeRenderer: WebGLRenderer; scene: Scene; camera: Camera; } /** * Common options shared between both initialization modes. */ interface Renderer3DPluginCommonOptions<G extends string = 'renderer3d'> { /** System group name (default: 'renderer3d') */ systemGroup?: G; /** Priority for render sync system (default: 500) */ renderSyncPriority?: number; /** Options for the included 3D transform plugin */ transform?: Transform3DPluginOptions; /** When true, starts a requestAnimationFrame loop to drive ecs.update() automatically (default: true) */ startLoop?: boolean; } /** * Options when providing pre-initialized Three.js objects. */ export interface Renderer3DPluginPreInitOptions<G extends string = 'renderer3d'> extends Renderer3DPluginCommonOptions<G> { /** Pre-initialized WebGLRenderer */ renderer: WebGLRenderer; /** Pre-initialized Scene */ scene: Scene; /** Pre-initialized Camera */ camera: Camera; container?: never; background?: never; width?: never; height?: never; antialias?: never; shadows?: never; cameraOptions?: never; threeInit?: never; } /** * Camera configuration for managed mode. * * Discriminated on `projection`. Defaults to `'perspective'` when omitted. * Orthographic cameras use `viewSize` (world-unit height at zoom=1) to define * the base frustum; `zoom` maps directly to Three.js's `OrthographicCamera.zoom`. */ export type CameraOptions = { projection?: 'perspective'; fov?: number; near?: number; far?: number; position?: { x: number; y: number; z: number; }; lookAt?: { x: number; y: number; z: number; }; } | { projection: 'orthographic'; viewSize?: number; zoom?: number; near?: number; far?: number; position?: { x: number; y: number; z: number; }; lookAt?: { x: number; y: number; z: number; }; }; /** * Options when letting the plugin create and manage Three.js objects. */ export interface Renderer3DPluginManagedOptions<G extends string = 'renderer3d'> extends Renderer3DPluginCommonOptions<G> { renderer?: never; scene?: never; camera?: never; /** Container element to append the canvas to (or CSS selector string). Defaults to `document.body`. */ container?: HTMLElement | string; /** Scene background color. */ background?: ColorRepresentation; /** Canvas width. When omitted, auto-sizes to container. */ width?: number; /** Canvas height. When omitted, auto-sizes to container. */ height?: number; /** Enable antialiasing (default: true) */ antialias?: boolean; /** Enable shadow mapping (default: false) */ shadows?: boolean; /** Camera configuration */ cameraOptions?: CameraOptions; /** Escape hatch for raw WebGLRendererParameters not otherwise exposed. */ threeInit?: Partial<WebGLRendererParameters>; } /** * Configuration options for the 3D renderer plugin. * * Supports two modes: * 1. **Pre-initialized**: Pass already-initialized renderer, scene, camera * 2. **Managed**: Omit them and the plugin creates everything during `ecs.initialize()` * * This plugin includes 3D transform propagation automatically. * * @example Pre-initialized mode * ```typescript * const renderer = new WebGLRenderer({ antialias: true }); * const scene = new Scene(); * const camera = new PerspectiveCamera(75, w / h, 0.1, 1000); * * const ecs = ECSpresso.create() * .withPlugin(createRenderer3DPlugin({ renderer, scene, camera })) * .build(); * ``` * * @example Managed mode * ```typescript * const ecs = ECSpresso.create() * .withPlugin(createRenderer3DPlugin({ * container: '#game', * background: 0x1099bb, * antialias: true, * cameraOptions: { fov: 75, position: { x: 0, y: 5, z: 10 } }, * })) * .build(); * await ecs.initialize(); * ``` */ export type Renderer3DPluginOptions<G extends string = 'renderer3d'> = Renderer3DPluginPreInitOptions<G> | Renderer3DPluginManagedOptions<G>; interface PositionOption3D { x?: number; y?: number; z?: number; } interface TransformOptions3D { rotation?: { x?: number; y?: number; z?: number; }; scale?: number | { x: number; y: number; z: number; }; visible?: boolean; } /** * Create components for a mesh entity. * Returns an object suitable for spreading into spawn(). * * @example * ```typescript * const player = ecs.spawn({ * ...createMeshComponents(myMesh, { x: 10, y: 0, z: -5 }), * velocity: { x: 0, y: 0, z: 0 }, * }); * ``` */ export declare function createMeshComponents(mesh: Mesh, position?: PositionOption3D, options?: TransformOptions3D): Pick<Renderer3DComponentTypes, 'mesh' | 'localTransform3D' | 'worldTransform3D' | 'visible3d'>; /** * Create components for a group entity. * Returns an object suitable for spreading into spawn(). * * @example * ```typescript * const enemies = ecs.spawn({ * ...createGroupComponents(enemyGroup, { x: 50, y: 0, z: -30 }), * }); * ``` */ export declare function createGroupComponents(group: Group, position?: PositionOption3D, options?: TransformOptions3D): Pick<Renderer3DComponentTypes, 'group' | 'localTransform3D' | 'worldTransform3D' | 'visible3d'>; /** * Create components for a generic Object3D entity. * Returns an object suitable for spreading into spawn(). * * @example * ```typescript * const obj = ecs.spawn({ * ...createObject3DComponents(myObject, { x: 0, y: 0, z: 0 }), * }); * ``` */ export declare function createObject3DComponents(object3d: Object3D, position?: PositionOption3D, options?: TransformOptions3D): Pick<Renderer3DComponentTypes, 'object3d' | 'localTransform3D' | 'worldTransform3D' | 'visible3d'>; type Renderer3DLabels = 'renderer3d-sync' | 'renderer3d-scene-graph' | 'renderer3d-render' | 'transform3d-propagation'; type Renderer3DReactiveQueryNames = 'renderer3d-meshes' | 'renderer3d-groups' | 'renderer3d-objects'; type Renderer3DWorldConfig = ComponentsConfig<Renderer3DComponentTypes> & EventsConfig<Renderer3DEventTypes> & ResourcesConfig<Renderer3DResourceTypes>; /** * Create a 3D rendering plugin for ECSpresso. * * This plugin provides: * - 3D transform propagation (localTransform3D -> worldTransform3D) * - Render sync system (updates Three.js objects from ECS components) * - Scene graph management (auto-adds/removes Three.js objects) * - Render call (renderer.render(scene, camera) each frame) * - Optional requestAnimationFrame loop */ export declare function createRenderer3DPlugin<G extends string = 'renderer3d'>(options: Renderer3DPluginOptions<G>): Plugin<Renderer3DWorldConfig, EmptyConfig, Renderer3DLabels, G, never, Renderer3DReactiveQueryNames>;