UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in

346 lines (345 loc) • 16.9 kB
/// <reference types="webxr" /> import 'three/examples/jsm/renderers/webgl-legacy/nodes/WebGLNodes.js'; import type { EffectComposer } from "postprocessing"; import { BufferGeometry, Camera, DepthTexture, Group, Material, Object3D, OrthographicCamera, PerspectiveCamera, Scene, Texture, WebGLRenderer, type WebGLRendererParameters, type WebXRArrayCamera } from 'three'; import type { EffectComposer as ThreeEffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js"; import { Addressables } from './engine_addressables.js'; import { AnimationsRegistry } from './engine_animation.js'; import { Application } from './engine_application.js'; import { AssetDatabase } from './engine_assetdatabase.js'; import { Input } from './engine_input.js'; import { type ILightDataRegistry } from './engine_lightdata.js'; import { LODsManager } from "./engine_lods.js"; import { NetworkConnection } from './engine_networking.js'; import { Physics } from './engine_physics.js'; import { PlayerViewManager } from './engine_playerview.js'; import { RendererData as SceneLighting } from './engine_scenelighting.js'; import { Time } from './engine_time.js'; import type { CoroutineData, ICamera, IComponent, IContext, ILight, Model, Vec2 } from "./engine_types.js"; import type { INeedleXRSessionEventReceiver, NeedleXRSession } from './engine_xr.js'; import { NeedleMenu } from './webcomponents/needle menu/needle-menu.js'; export declare const build_scene_functions: { [name: string]: (context: Context) => Promise<void>; }; export declare class LoadingProgressArgs { /** the name or URL of the loaded file */ name: string; /** the loading progress event from the loader */ progress: ProgressEvent; /** the index of the loaded file */ index: number; /** the total number of files to load */ count: number; } export declare class ContextCreateArgs { /** list of glTF or GLB files to load */ files: Array<string>; abortSignal?: AbortSignal; /** called when loading a provided glTF file started */ onLoadingStart?: (index: number, file: string) => void; /** called on update for each loaded glTF file */ onLoadingProgress?: (args: LoadingProgressArgs) => void; /** Called after a gLTF file has finished loading */ onLoadingFinished?: (index: number, file: string, glTF: Model | null) => void; } export declare class ContextArgs { name?: string; /** for debugging only */ alias?: string; /** the hash is used as a seed when initially loading the scene files */ hash?: string; /** when true the context will not check if it's visible in the viewport and always update and render */ runInBackground?: boolean; /** the DOM element the context belongs to or is inside of (this does not have to be the canvas. use renderer.domElement if you want to access the dom canvas) */ domElement?: HTMLElement | null; /** externally owned renderer */ renderer?: WebGLRenderer; /** externally owned camera */ camera?: Camera; /** externally owned scene */ scene?: Scene; } export declare enum FrameEvent { Start = -1, EarlyUpdate = 0, Update = 1, LateUpdate = 2, OnBeforeRender = 3, OnAfterRender = 4, PrePhysicsStep = 9, PostPhysicsStep = 10, Undefined = -1 } /** threejs callback event signature */ export declare type OnRenderCallback = (renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, material: Material, group: Group) => void; export declare function registerComponent(script: IComponent, context?: Context): void; /** * The context is the main object that holds all the data and state of the Needle Engine. * It can be used to access the scene, renderer, camera, input, physics, networking, and more. * @example * ```typescript * import { Behaviour } from "@needle-tools/engine"; * import { Mesh, BoxGeometry, MeshBasicMaterial } from "three"; * export class MyScript extends Behaviour { * start() { * console.log("Hello from MyScript"); * this.context.scene.add(new Mesh(new BoxGeometry(), new MeshBasicMaterial())); * } * } * ``` */ export declare class Context implements IContext { private static _defaultTargetFramerate; /** When a new context is created this is the framerate that will be used by default */ static get DefaultTargetFrameRate(): number | undefined; /** When a new context is created this is the framerate that will be used by default */ static set DefaultTargetFrameRate(val: number | undefined); private static _defaultWebglRendererParameters; /** The default parameters that will be used when creating a new WebGLRenderer. * Modify in global context to change the default parameters for all new contexts. * @example * ```typescript * import { Context } from "@needle-tools/engine"; * Context.DefaultWebGLRendererParameters.antialias = false; * ``` */ static get DefaultWebGLRendererParameters(): WebGLRendererParameters; /** The needle engine version */ get version(): string; /** The currently active context. Only set during the update loops */ static get Current(): Context; /** @internal this property should not be set by user code */ static set Current(context: Context); static get All(): Context[]; /** The name of the context */ name: string; /** An alias for the context */ alias: string | undefined | null; /** When the renderer or camera are managed by an external process (e.g. when running in r3f context). * When this is false you are responsible to call update(timestamp, xframe. * It is also currently assumed that rendering is handled performed by an external process * */ isManagedExternally: boolean; /** set to true to pause the update loop. You can receive an event for it in your components. * Note that script updates will not be called when paused */ isPaused: boolean; /** When enabled the application will run while not visible on the page */ runInBackground: boolean; /** * Set to the target framerate you want your application to run in (you can use ?stats to check the fps) * Set to undefined if you want to run at the maximum framerate */ targetFrameRate?: number | { value?: number; }; /** Use a higher number for more accurate physics simulation. * When undefined physics steps will be 1 for mobile devices and 5 for desktop devices * Set to 0 to disable physics updates * TODO: changing physics steps is currently not supported because then forces that we get from the character controller and rigidbody et al are not correct anymore - this needs to be properly tested before making this configureable */ private physicsSteps?; /** used to append to loaded assets */ hash?: string; /** The `<needle-engine>` web component */ domElement: HTMLElement; appendHTMLElement(element: HTMLElement): HTMLElement; get resolutionScaleFactor(): number; /** use to scale the resolution up or down of the renderer. default is 1 */ set resolutionScaleFactor(val: number); private _resolutionScaleFactor; private _boundingClientRectFrame; private _boundingClientRect; private _domX; private _domY; /** update bounding rects + domX, domY */ private calculateBoundingClientRect; /** The width of the `<needle-engine>` element on the website */ get domWidth(): number; /** The height of the `<needle-engine>` element on the website */ get domHeight(): number; /** the X position of the Needle Engine element on the website */ get domX(): number; /** the Y position of the Needlee Engine element on the website */ get domY(): number; get isInXR(): boolean; /** shorthand for `NeedleXRSession.active` * Automatically set by NeedleXRSession when a XR session is active * @returns the active XR session or null if no session is active * */ xr: NeedleXRSession | null; get xrSessionMode(): XRSessionMode | undefined; get isInVR(): boolean; get isInAR(): boolean; /** If a XR session is active and in pass through mode (immersive-ar on e.g. Quest) */ get isInPassThrough(): boolean; /** access the raw `XRSession` object (shorthand for `context.renderer.xr.getSession()`). For more control use `NeedleXRSession.active` */ get xrSession(): XRSession | null; /** @returns the latest XRFrame (if a XRSession is currently active) * @link https://developer.mozilla.org/en-US/docs/Web/API/XRFrame */ get xrFrame(): XRFrame | null; /** @returns the current WebXR camera while the WebXRManager is active (shorthand for `context.renderer.xr.getCamera()`) */ get xrCamera(): WebXRArrayCamera | undefined; private _xrFrame; get arOverlayElement(): HTMLElement; /** Current event of the update cycle */ get currentFrameEvent(): FrameEvent; private _currentFrameEvent; scene: Scene; renderer: WebGLRenderer; composer: EffectComposer | ThreeEffectComposer | null; readonly scripts: IComponent[]; readonly scripts_pausedChanged: IComponent[]; readonly scripts_earlyUpdate: IComponent[]; readonly scripts_update: IComponent[]; readonly scripts_lateUpdate: IComponent[]; readonly scripts_onBeforeRender: IComponent[]; readonly scripts_onAfterRender: IComponent[]; readonly scripts_WithCorroutines: IComponent[]; readonly scripts_immersive_vr: INeedleXRSessionEventReceiver[]; readonly scripts_immersive_ar: INeedleXRSessionEventReceiver[]; readonly coroutines: { [FrameEvent: number]: Array<CoroutineData>; }; /** callbacks called once after the context has been created */ readonly post_setup_callbacks: Function[]; /** called every frame at the beginning of the frame (after component start events and before earlyUpdate) */ readonly pre_update_callbacks: Function[]; /** called every frame before rendering (after all component events) */ readonly pre_render_callbacks: Array<(frame: XRFrame | null) => void>; /** called every frame after rendering (after all component events) */ readonly post_render_callbacks: Function[]; /** called every frame befroe update (this list is emptied every frame) */ readonly pre_update_oneshot_callbacks: Function[]; readonly new_scripts: IComponent[]; readonly new_script_start: IComponent[]; readonly new_scripts_pre_setup_callbacks: Function[]; readonly new_scripts_post_setup_callbacks: Function[]; readonly new_scripts_xr: INeedleXRSessionEventReceiver[]; /** The main camera component of the scene - this camera is used for rendering */ mainCameraComponent: ICamera | undefined; /** The main camera of the scene - this camera is used for rendering */ get mainCamera(): Camera; /** Set the main camera of the scene. If set to null the camera of the {@link mainCameraComponent} will be used - this camera is used for rendering */ set mainCamera(cam: Camera | null); private _mainCamera; private _fallbackCamera; application: Application; /** access animation mixer used by components in the scene */ animations: AnimationsRegistry; /** access timings (current frame number, deltaTime, timeScale, ...) */ time: Time; input: Input; /** access physics related methods (e.g. raycasting). To access the phyiscs engine use `context.physics.engine` */ physics: Physics; /** access networking methods (use it to send or listen to messages or join a networking backend) */ connection: NetworkConnection; /** * @deprecated AssetDataBase is deprecated */ assets: AssetDatabase; mainLight: ILight | null; /** @deprecated Use sceneLighting */ get rendererData(): SceneLighting; sceneLighting: SceneLighting; addressables: Addressables; lightmaps: ILightDataRegistry; players: PlayerViewManager; readonly lodsManager: LODsManager; readonly menu: NeedleMenu; get isCreated(): boolean; private _sizeChanged; private _isCreated; private _isCreating; private _isVisible; private _stats; constructor(args?: ContextArgs); /** calling this function will dispose the current renderer and create a new one */ createNewRenderer(params?: WebGLRendererParameters): void; private _intersectionObserver; private internalOnUpdateVisible; private _disposeCallbacks; /** will request a renderer size update the next render call (will call updateSize the next update) */ requestSizeUpdate(): void; /** Clamps the renderer max resolution. If undefined the max resolution is not clamped. Default is undefined */ maxRenderResolution?: Vec2; /** update the renderer and canvas size */ updateSize(force?: boolean): void; updateAspect(camera: PerspectiveCamera | OrthographicCamera, width?: number, height?: number): void; /** This will recreate the whole needle engine context and dispose the whole scene content * All content will be reloaded (loading times might be faster due to browser caches) * All scripts will be recreated */ recreate(): void; private _originalCreationArgs?; /** @deprecated use create. This method will be removed in a future version */ onCreate(opts?: ContextCreateArgs): Promise<boolean>; create(opts?: ContextCreateArgs): Promise<boolean>; private onUnhandledRejection; /** Dispatches an error */ private onError; /** Will destroy all scenes and objects in the scene */ clear(): void; dispose(): void; /**@deprecated use dispose() */ onDestroy(): void; private internalOnDestroy; registerCoroutineUpdate(script: IComponent, coroutine: Generator, evt: FrameEvent): Generator; unregisterCoroutineUpdate(coroutine: Generator, evt: FrameEvent): void; stopAllCoroutinesFrom(script: IComponent): void; private _cameraStack; setCurrentCamera(cam: ICamera): void; removeCamera(cam?: ICamera | null): void; private _onBeforeRenderListeners; private _onAfterRenderListeners; /** use this to subscribe to onBeforeRender events on threejs objects */ addBeforeRenderListener(target: Object3D, callback: OnRenderCallback): void; removeBeforeRenderListener(target: Object3D, callback: OnRenderCallback): void; /** use this to subscribe to onAfterRender events on threejs objects */ addAfterRenderListener(target: Object3D, callback: OnRenderCallback): void; removeAfterRenderListener(target: Object3D, callback: OnRenderCallback): void; private _createRenderCallbackWrapper; private _requireDepthTexture; private _requireColorTexture; private _renderTarget?; private _isRendering; get isRendering(): boolean; setRequireDepth(val: boolean): void; setRequireColor(val: boolean): void; get depthTexture(): DepthTexture | null; get opaqueColorTexture(): Texture | null; /** returns true if the dom element is visible on screen */ get isVisibleToUser(): boolean; private _createId; private internalOnCreate; private internalLoadInitialContent; /** Sets the animation loop. * Can not be done while creating the context or when disposed **/ restartRenderLoop(): boolean; private _renderlooperrors; /** Performs a full update step including script callbacks, rendering (unless isManagedExternally is set to false) and post render callbacks */ update(timestamp: DOMHighResTimeStamp, frame?: XRFrame | null): void; /** Call to **manually** perform physics steps. * By default the context uses the `physicsSteps` property to perform steps during the update loop * If you just want to increase the accuracy of physics you can instead set the `physicsSteps` property to a higher value * */ updatePhysics(steps: number): void; private _lastTimestamp; private _accumulatedTime; private _dispatchReadyAfterFrame; private internalStep; private internalOnBeforeRender; private internalUpdatePhysics; private internalOnRender; private internalOnAfterRender; renderNow(camera?: Camera): boolean; private _contextRestoreTries; private handleRendererContextLost; /** returns true if we should return out of the frame loop */ private _wasPaused; private onHandlePaused; private evaluatePaused; private renderRequiredTextures; private executeCoroutines; }