@vladkrutenyuk/three-kvy-core
Version:
Everything you need to create any-complexity 3D apps with Three.js. Empower Three.js with a modular, lifecycle-managed context that seamlessly propagates through objects via reusable features providing structured logic.
627 lines (610 loc) • 30.4 kB
TypeScript
declare namespace KVY {
import * as THREE from 'three';
import { EventEmitter } from 'eventemitter3';
/**
* Removes the first occurrence of a specified item from an array.
*
* @template T - The type of elements in the array.
* @param {T[]} array - The array from which to remove the item.
* @param {T} item - The item to remove from the array.
* @returns {boolean} - Returns `true` if the item was found and removed, otherwise `false`.
*/
declare function removeArrayItem<T>(array: T[], item: T): boolean;
declare const defineProps: <T>(o: T, properties: PropertyDescriptorMap & ThisType<any>) => T;
declare const readOnly: (value: any) => PropertyDescriptor;
declare const notEnumer: (value: any) => PropertyDescriptor;
var props = /*#__PURE__*/Object.freeze({
__proto__: null,
defineProps: defineProps,
notEnumer: notEnumer,
readOnly: readOnly
});
/**
* Traverses the ancestors of a given THREE.Object3D target and applies a callback function to each ancestor.
* The traversal is interruptible based on the return value of the callback function.
*
* @param {THREE.Object3D} target - The starting THREE.Object3D whose ancestors will be traversed.
* @param {(ancestor: THREE.Object3D) => boolean} callback - A function that is called with each ancestor. If the callback returns true, the traversal continues; if false, the traversal stops.
*/
declare function traverseUp(target: THREE.Object3D, callback: (ancestor: THREE.Object3D) => boolean): void;
type ThreeContextParams = {
renderer?: THREE.WebGLRendererParameters;
};
/**
* A utility for initializing core [Three.js](https://threejs.org) entities, managing their setup, and handling rendering.
* @see {@link https://three-kvy-core.vladkrutenyuk.ru/docs/api/three-context | Official Documentation}
* @see {@link https://github.com/vladkrutenyuk/three-kvy-core/blob/main/src/core/ThreeContext.ts | Source}
*/
declare class ThreeContext extends EventEmitter<ThreeContextEventMap, ThreeContext> {
/**
* Shortcut to create an instance of ThreeContext.
* @param {typeof import("three")} Three - Three.js `THREE` imported module, object containing class constructors `WebGLRenderer`, `PerspectiveCamera`, `Scene`, `Clock`, `Raycaster`.
* @param {{renderer: THREE.WebGLRendererParameters}} params - (optional) Object parameters
* @returns {ThreeContext} An instance of ThreeContext
* @example
* ```js
import * as THREE from "three";
import * as KVY from "@vladkrutenyuk/three-kvy-core";
const three = new KVY.ThreeContext.create(THREE, { renderer: { antialias: true } });
```
*/
static create(Three: {
WebGLRenderer: typeof THREE.WebGLRenderer;
PerspectiveCamera: typeof THREE.PerspectiveCamera;
Scene: typeof THREE.Scene;
Clock: typeof THREE.Clock;
Raycaster: typeof THREE.Raycaster;
}, params?: ThreeContextParams): ThreeContext;
/**
* (readonly) flag to mark that it is an instance of ThreeContext.
* @type {true}
*/
readonly isThreeContext: true;
/**
* (readonly) instance of Three.js `WebGLRenderer` used for rendering your awesome scene.
* @type {THREE.WebGLRenderer}
*/
readonly renderer: THREE.WebGLRenderer;
/**
* An instance of Three.js `PerspectiveCamera` camera which is used in rendering. Fires event `camerachanged` on set.
*/
get camera(): THREE.PerspectiveCamera;
set camera(value: THREE.PerspectiveCamera);
/** (readonly) instance of Three.js `Scene` that contains all objects to be rendered. */
readonly scene: THREE.Scene;
/** (readonly) instance of Three.js `Clock` */
readonly clock: THREE.Clock;
/** (readonly) instance of Three.js `Raycaster`. */
readonly raycaster: THREE.Raycaster;
/** (readonly) HTML element where the renderer canvas is appended on mount. */
get container(): HTMLDivElement | null;
/**
* (readonly) flag to check if the renderer canvas is currently mounted.
* @type {boolean}
*/
get isMounted(): boolean;
/**
* (readonly) flag to check whether this instance has been destroyed.
*/
get isDestroyed(): boolean;
private _camera;
private _container;
private _resizeObserver;
private _isMounted;
private _isDestroyed;
private _srcRenderFn;
private _renderFn;
/**
* This creates a new {@link ThreeContext} instance.
* @param {THREE.WebGLRenderer} renderer - An instance of Three.js `WebGLRenderer`
* @param {THREE.PerspectiveCamera} camera - An instance of Three.js `PerspectiveCamera`
* @param {THREE.Scene} scene - An instance of Three.js `Scene`
* @param {THREE.Clock} clock - An instance of Three.js `Clock`
* @param {THREE.Raycaster} raycaster - An instance of Three.js `Raycaster`
*/
constructor(renderer: THREE.WebGLRenderer, camera: THREE.PerspectiveCamera, scene: THREE.Scene, clock: THREE.Clock, raycaster: THREE.Raycaster);
/**
* Renders the scene using the current render function. Fires `renderbefore` and `renderafter` events.
*/
render(): void;
/**
* Overrides the render function with a custom implementation.
* @param {Function} fn
* @returns
*/
overrideRender(fn: () => void): this;
/**
* Resets the render function to its default implementation.
*/
resetRender(): this;
/**
* Append the renderer canvas to the given HTML container, initializes event listeners and resize observer.
* Fires `mount` event.
* @param {HTMLDivElement} container - The HTML container element where to mount (append) renderer canvas.
*/
mount(container: HTMLDivElement): this | undefined;
/**
* Remove the renderer canvas from DOM it was mounted, removes event listeners, disconnect resize observer.
* Fires `"unmount"` event.
*/
unmount(): this | undefined;
/**
* Destroys this instance, releasing resources and preventing further rendering.
* Fires `"destroy"` event.
*/
destroy(): void;
private resizeHandler;
private cameraChanged;
}
declare const ev: Readonly<{
RenderBefore: "renderbefore";
RenderAfter: "renderafter";
Mount: "mount";
Unmount: "unmount";
Destroy: "destroy";
CameraChanged: "camerachanged";
Resize: "resize";
}>;
type ThreeContextEventMap = {
[ev.RenderBefore]: [];
[ev.RenderAfter]: [];
[ev.Mount]: [root: HTMLDivElement];
[ev.Unmount]: [];
[ev.Destroy]: [];
[ev.Resize]: [width: number, height: number];
[ev.CameraChanged]: [
newCamera: THREE.PerspectiveCamera,
prevCamera: THREE.PerspectiveCamera
];
};
/**
* Base class, acting as a pluggable module, for extending {@link CoreContext} functionality.\
* It enables clean separation of concerns while maintaining full access to context capabilities.\
* Modules are assigned to context {@link CoreContext}, can provide services to features {@link Object3DFeature}, and manage their own
* lifecycle through the {@link useCtx useCtx(ctx)} pattern.
* @see {@link https://three-kvy-core.vladkrutenyuk.ru/docs/api/core-context-module | Official Documentation}
* @see {@link https://github.com/vladkrutenyuk/three-kvy-core/blob/main/src/core/CoreContextModule.ts | Source}
*/
declare abstract class CoreContextModule<TEventTypes extends EventEmitter.ValidEventTypes = string | symbol, TModules extends ModulesRecord = ModulesRecordDefault> extends EventEmitter<TEventTypes> {
/** Read-only flag to mark that it is an instance of {@link CoreContextModule}.*/
readonly isCoreContextModule: true;
/**
* (readonly) Getter for the instance of {@link CoreContext} this is assigned to.
* @warning **Throws exception** if try to access before assign.
*/
get ctx(): CoreContext<TModules>;
/** (readonly) Flag to check if this instance has been assigned to some {@link CoreContext}. */
get hasCtx(): boolean;
private _ctx?;
constructor();
/**
* Overridable Lifecycle Method. Called when the module is assigned to a {@link CoreContext}. \
* The returned cleanup function (optional) is called when the module is removed from the context.\
* Also cleanup is called if context is destroyed.\
* Calling the method manually is prohibited.
* @param {CoreContext} ctx - An instance of {@link CoreContext} to which this module was assigned.
* @returns {Function | undefined}
*/
protected useCtx(ctx: CoreContext<TModules>): ReturnOfUseCtx;
}
type ReturnOfUseCtx = undefined | (() => void) | void;
interface ICoreContextModuleProtected {
_ctx?: CoreContext<ModulesRecordDefault>;
useCtx<TModules extends ModulesRecord>(ctx: CoreContext<TModules>): ReturnOfUseCtx;
}
declare const Evnt: Readonly<{
AttCtx: "attachedctx";
DetCtx: "detachedctx";
FtAdd: "featureadded";
FtRem: "featureremoved";
Dstr: "destroy";
}>;
type Object3DFeaturabilityEventTypes<TModules extends ModulesRecord = {}> = {
[Evnt.AttCtx]: [ctx: CoreContext<TModules>];
[Evnt.DetCtx]: [ctx: CoreContext<TModules>];
[Evnt.FtAdd]: [feature: Object3DFeature<TModules>];
[Evnt.FtRem]: [feature: Object3DFeature<TModules>];
};
declare const key = "__kvy_ftblty__";
declare class Object3DFeaturability<TModules extends ModulesRecord = {}, TObj extends THREE.Object3D = THREE.Object3D> extends EventEmitter<Object3DFeaturabilityEventTypes<TModules>> {
/**
* Extracts {@link Object3DFeaturability} from the given object if it is featurable.
*
* @param obj - The object to extract {@link Object3DFeaturability} from.
* @returns The {@link Object3DFeaturability} instance if available, otherwise `null`.
*/
static extract<TModules extends ModulesRecord = {}, TObj extends THREE.Object3D = THREE.Object3D>(obj: TObj): Object3DFeaturability<TModules, TObj> | null;
/**
* Creates or retrieves {@link Object3DFeaturability} for the given object.
* If the object already has featurability, it is returned. Otherwise, a new instance is created.
*
* @param obj - The object to make featurable.
* @returns The {@link Object3DFeaturability} instance for the object.
*/
static from<TModules extends ModulesRecord = {}, TObj extends THREE.Object3D = THREE.Object3D>(obj: TObj): Object3DFeaturability<TModules, TObj>;
static destroy<TObj extends THREE.Object3D = THREE.Object3D>(obj: TObj, force?: boolean): void;
static log: (target: Object3DFeaturability, msg: string) => void;
readonly isObjectFeaturability = true;
readonly object: IFeaturablePrivate<TModules, TObj>;
get ctx(): CoreContext<TModules> | null;
get features(): Object3DFeature<any, string | symbol>[];
private _ctx;
private readonly _features;
private constructor();
/**
* Destroys the featurability instance and removes all features.
*/
destroy(force?: boolean): void;
destroyAllFeatures(): void;
/**
* Adds a new feature to the object.
* @param Feature The feature class.
* @param props The properties required for initialization.
* @param beforeAttach A callback invoked before attaching the feature.
* @returns The created feature instance.
*/
addFeature<TFeature extends Object3DFeature<any, any>, TProps>(Feature: new (object: IFeaturable, props: TProps) => TFeature, props: keyof TProps extends never ? undefined : TProps, beforeAttach?: (feature: TFeature) => void): TFeature;
addFeature<TFeature extends Object3DFeature<any, any>>(Feature: new (object: IFeaturable) => TFeature): TFeature;
/**
* Retrieves a feature of a specific class, if present.
* @param FeatureClass The feature class to search for.
* @returns The feature instance, or `null` if not found.
*/
getFeature<TFeatureClass extends typeof Object3DFeature>(FeatureClass: TFeatureClass): InstanceType<TFeatureClass> | null;
/**
* Retrieves a feature of a specific class, if present.
* @param FeatureClass The feature class to search for.
* @returns The feature instance, or `null` if not found.
*/
getFeatureBy<TFeature extends Object3DFeature = Object3DFeature>(predicate: (feature: TFeature) => boolean): TFeature | null;
/**
* Removes a feature from the object and destroys it.
* @param feature The feature instance to remove.
*/
destroyFeature<TFeature extends Object3DFeature<any, any>>(feature: TFeature): boolean;
/**
* Attaches or detaches the object from a `CoreContext`.
* @warning You should be careful to use this method manually
* @param ctx The `CoreContext` instance, or `null` to detach.
* @returns This instance.
* @warning Use with caution.
*/
setCtx(ctx: CoreContext<TModules> | null): this;
private onObjectAdded;
private inheritCtx;
private onObjectRemoved;
private attachCtx;
private detachCtx;
private propagateAttachCtxDown;
private propagateDetachCtxDown;
private _log;
}
type IFeaturable<TModules extends ModulesRecord = any, TObj extends THREE.Object3D = THREE.Object3D> = TObj & {
isFeaturable: true;
};
type IFeaturablePrivate<TModules extends ModulesRecord = any, TObj extends THREE.Object3D = THREE.Object3D> = TObj & {
[key]?: Object3DFeaturability<TModules, TObj>;
isFeaturable?: true;
};
type ModulesRecord = Record<string, CoreContextModule>;
type ModulesRecordDefault = Record<string, CoreContextModule & Record<string, any>>;
/**
* The primary central entity, acting as a main hub, that orchestrates the Three.js environment, animation loop, and module system.\
* Propagates through features `Object3DFeature` which are added to Three.js `Object3D`.\
* Provides an elegant lifecycle management system and handles fundametal initializations.
* @see {@link https://three-kvy-core.vladkrutenyuk.ru/docs/api/core-context | Official Documentation}
* @see {@link https://github.com/vladkrutenyuk/three-kvy-core/blob/main/src/core/CoreContext.ts | Source}
*/
declare class CoreContext<TModules extends ModulesRecord = ModulesRecordDefault> extends EventEmitter<{
destroy: [];
looprun: [];
loopstop: [];
}> {
/**
* Initialization shortcut. Creates and returns a new {@link CoreContext} instance.
* @param {typeof import("three")} Three - Object containing Three.js class constructors `WebGLRenderer`, `Scene`, `PerspectiveCamera`, `Clock`, `Raycaster`. In short, just use imported [`THREE`](https://threejs.org/docs/manual/en/introduction/Installation.html) Three.js module.
* @param {TModules} modules - (optional) Custom dictionary of any your modules {@link CoreContextModules}.
* @param {ThreeContextParams} params - (optional) Object paramateres
* @example
* ```js
* import * as THREE from "three";
* import * as KVY from "@vladkrutenyuk/three-kvy-core";
*
* const modules = {
* moduleA: new MyModuleA(),
* moduleB: new MyModuleB(),
* };
* const ctx = KVY.CoreContext.create(THREE, modules, { renderer: { antialias: true } });
* ```
* @returns {CoreContext}
*/
static create<TModules extends ModulesRecord = ModulesRecordDefault>(Three: {
Scene: typeof THREE.Scene;
WebGLRenderer: typeof THREE.WebGLRenderer;
PerspectiveCamera: typeof THREE.PerspectiveCamera;
Raycaster: typeof THREE.Raycaster;
Clock: typeof THREE.Clock;
}, modules?: Partial<TModules>, params?: ThreeContextParams): CoreContext<TModules>;
/** (readonly) Flag to mark that it is an instance of {@link CoreContext}. */
readonly isCoreContext: true;
/** (readonly) Instance of {@link ThreeContext}. Utility to manage Three.js setup. */
readonly three: ThreeContext;
/** (readonly) Dictionary of assinged modules.
* @type { { [key:string]: CoreContextModule } }
*/
readonly modules: TModules;
/**
* (readonly) Instance of Three.js `Object3D` that plays the role of entry point for a given context propagation.\
* By default, it's Three.js `Scene` instance given in `ThreeContext` of this (`this.root === this.three.scene`).\
* You can specify any other `root` if you initialize the context through constructor.
* @type {THREE.Object3D}
* */
get root(): IFeaturableRoot<TModules>;
/** (readonly) The seconds passed since the last frame. */
get deltaTime(): number;
/** (readonly) The seconds passed since the context loop started - by {@link run run()}. */
get time(): number;
/** (readonly) Flag to check if this instance is destroyed. */
get isDestroyed(): boolean;
/** (readonly) Flag to check if this instance loop is running. */
get isRunning(): boolean;
private readonly _root;
private readonly _clock;
private _time;
private _deltaTime;
private _isDestroyed;
private _isRunning;
/**
* This creates a new {@link CoreContext} instance.
* @param three - An instance of {@link ThreeContext}. Utility to manage Three.js setup.
* @param {THREE.Object3D} root - (optional) An instance of Three.js `Object3D`. The entry point for context propagation. If root is not providen then Three.js `Scene` from the given {@link ThreeContext} will be taken as root.
* @param {TModules} modules - (optional) Custom dictionary of any your modules {@link CoreContextModules}.
*/
constructor(three: ThreeContext, root?: THREE.Object3D, modules?: Partial<TModules>);
/** Run animation loop and Three.js rendering. Stoppable as many times as you need by `stop()`. */
run(): void;
/** Stop animation loop and Three.js rendering. Resumable as many times as you need by `run()`. */
stop(): void;
private _cleanups;
/**
* Assigns the given dictionary of modules to this instance.
* It will be merged with the existing dictionary of modules.
*
* @remarks Note that if the given dictionary contains a key for which a module is already assigned,
* it will be skipped, and a warning message will be fired.
*
* @param {{ [key: string]: CoreContextModule }} modules - Dictionary of module instances to assign to this context.
*/
assignModules(modules: Partial<TModules>): this;
/**
* Assign module by key to this instance.
* It will be added to the existing dictionary of modules by the given key.
*
* @remarks Note that if the given key is already assigned, it will be skipped, and a warning message will be fired.
* @param {string} key - The key by which to assign the module to the context in the dictionary.
* @param {CoreContextModule} module - An instance of `CoreContextModule` implementation.
* @returns
*/
assignModule<TKey extends keyof TModules>(key: TKey, module: TModules[TKey]): void;
/**
* Remove a module by key that was specified when it was assigned.
* @param {string} key - key by which a module was assigned.
*/
removeModule(key: keyof TModules): void;
/**
* Destroy this instance.
* - Sets {@link isDestroyed} to `true` permanently.
* - Stops its animation loop permanently.
* - Destroys its {@link three three}: {@link ThreeContext} permanently.
* - Fires the `"destroy"` event.
* - Cleans up {@link root} from the assigned logic when it was designated as `root` in the given CoreContext.
* - Removes all assigned {@link modules}.
* - Removes all listeners from its events.
*/
destroy(): this;
}
interface IFeaturableRoot<TModules extends ModulesRecord = any> extends IFeaturable<TModules> {
isRoot: true;
}
/**
* Base class for implementing reusable components (features) that can be added to any Three.js Object3D.\
* Features get the context {@link CoreContext} when their object is added to ctx.root hierarchy, and lose it when removed, or forcibly on call.\
* Handle the context attach and detach can be through overridable lyfecycle method {@link useCtx useCtx(ctx)} where context is providen as arguement.\
* Built-in overridable lifecycle event methods like {@link onBeforeRender onBeforeRender(ctx)} etc.
* Direct access to object {@link object this.object} the feature is attached to.
* @see {@link https://three-kvy-core.vladkrutenyuk.ru/docs/api/object-3d-feature | Official Documentation}
* @see {@link https://github.com/vladkrutenyuk/three-kvy-core/blob/main/src/core/Object3DFeature.ts | Source}
*/
declare abstract class Object3DFeature<TModules extends ModulesRecord = {}, TEventTypes extends EventEmitter.ValidEventTypes = string | symbol> extends EventEmitter<TEventTypes> {
/** (readonly) Flag to mark that it is an instance of `isObject3DFeature`. */
readonly isObject3DFeature: true;
/** (readonly) Unique increment number for this feature instance. */
readonly id: number;
/** UUID of feature instance. This gets automatically assigned, so this shouldn't be edited.
* Its generation way can be changed via overriding `Object3DFeature.generateUUID` static method.
*/
uuid: string;
/** (readonly) An instance of Three.js Object3D which this feature was added to. */
readonly object: IFeaturable<TModules>;
/**
* (readonly) Getter for the current attached `CoreContext`.
* @warning **Throws exception** if try to access before it is attached.
*/
get ctx(): CoreContext<TModules>;
/** (readonly) Flag to check if this feature has attached `CoreContext`. */
get hasCtx(): boolean;
private _ftblty;
private _ctx;
/**
* @private Must be initiallized through the `addFeature` static factory method.
* @param {IFeaturable<TModules>} object - The object that this feature is going to be attached to.
*/
constructor(object: IFeaturable);
/**
* Initializes the feature. Called internally after instantiation.
* @private
*/
init(): void;
/** Destroys this feature instance. */
destroy(): void;
private ftbltyAttachedToCtxHandler;
private ftbltyDetachedFromCtxHandler;
private _useCtxReturn;
private attachCtx;
private detachCtx;
/**
* Overridable Lifecycle Method. Called when some `CoreContext` is attached to this feature.
* The defined returned cleanup function (optional) is called when the context is detached from the feature.
* It is prohibitted to be called manually.
*
* @param {CoreContext<TModules>} ctx - An instance of `CoreContext` which is attached to this feature.
* @returns {undefined | (() => void) | void} A cleanup function, or `undefined` if no cleanup is needed.
* @override
*
* @example
* ```
* useCtx(ctx) {
* const mesh = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial());
* this.object.add(mesh);
*
* const listener = () => {
* // ...
* }
* const customTicker = ctx.modules.customTicker;
* customTicker.on("tick", listener);
*
* return () => {
* this.object.remove(mesh);
* mesh.geometry.dispose();
* mesh.material.dispose();
*
* customTicker.off("tick", listener);
* }
* }
* ```
*/
protected useCtx(ctx: CoreContext<TModules>): undefined | (() => void) | void;
/**
* When this feature `destroy()` is called.
* @override
*/
protected onDestroy(): void;
/**
* Before render is called. On each frame after loop run `ctx.run()` or `ctx.three.render()` is called manually.
* @param {CoreContext<TModules>} ctx - The current attached instance of `CoreContext`.
* @override
*/
onBeforeRender(ctx: CoreContext<TModules>): void;
/**
* After render is called. On each frame after loop run `ctx.run()` or `ctx.three.render()` is called manually.
* @param {CoreContext<TModules>} ctx - The current attached instance of `CoreContext`.
* @override
*/
onAfterRender(ctx: CoreContext<TModules>): void;
/**
* When container (where mounted) is resized.
* @param {CoreContext<TModules>} ctx - The current attached instance of `CoreContext`.
* @override
*/
onResize(ctx: CoreContext<TModules>): void;
/**
* When `ctx.three.mount(container)` is called.
* @param {CoreContext<TModules>} ctx - The current attached instance of `CoreContext`.
* @override
*/
onMount(ctx: CoreContext<TModules>): void;
/**
* When `ctx.three.unmount()` is called.
* @param {CoreContext<TModules>} ctx - The current attached instance of `CoreContext`.
* @override
*/
onUnmount(ctx: CoreContext<TModules>): void;
/**
* When `ctx.run()` is called.
* @param {CoreContext<TModules>} ctx - The current attached instance of `CoreContext`.
* @override
*/
onLoopRun(ctx: CoreContext<TModules>): void;
/**
* When `ctx.stop()` is called.
* @param {CoreContext<TModules>} ctx - The game context.
* @override
*/
onLoopStop(ctx: CoreContext<TModules>): void;
private _log;
private initCtxEventMethods;
/**
* initEventHandlerMethod (iehm)
*/
private iehm;
/**
* @returns Generates a unique identifier for [`Object3DFeature`](/docs/) instances.\
* By default, it uses [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID), but in case of fall back, it returns `${Math.random()}-${Date.now()}`.
* You can freely override this static method to any of your own generation, e.g:
* ```js
* CoreContext.generateUUID = () => nanoid(10)
* ```
*/
static generateUUID: () => string;
/**
* Static method for overriding to handle logs.
* @param {Object3DFeature} target - The feature instance.
* @param {string} msg - The log message.
*/
static log: (target: Object3DFeature, msg: string) => void;
}
/**
* A static factory method that creates {@link Object3DFeature} and adds it to a given Three.js `Object3D` instance.
* It uses a given feature class (not an instance) that extends {@link Object3DFeature}
* with optional constructor parameters. Returns an instance of the provided feature class.
* @param {THREE.Object3D} obj - The target Three.js `Object3D` instance to which the feature is added.
* @param {typeof Object3DFeature} Feature - The feature class to add, which extends {@link Object3DFeature}.
* @param {object | undefined} props - An object containing parameters for the feature's constructor. Optional of feature implementation has no custom props in constructor.
* @param {(feature: Object3DFeature) => void} [beforeAttach] - (optional) A callback invoked before attaching the feature
* @returns {Object3DFeature} The created feature instance.
*/
declare function addFeature<TObj extends THREE.Object3D, TFeature extends Object3DFeature<any, any>, TProps>(obj: TObj, Feature: new (object: IFeaturable, props: TProps) => TFeature, props: keyof TProps extends never ? undefined : TProps, beforeAttach?: (feature: TFeature) => void): TFeature;
declare function addFeature<TObj extends THREE.Object3D, TFeature extends Object3DFeature<any, any>>(obj: TObj, Feature: new (object: IFeaturable) => TFeature): TFeature;
/**
* A static method that retrieves a feature instance from the given object by its class (constructor). Returns first found such feature instance, or `null` if not.
* @param {THREE.Object3D} obj - The target Three.js Object3D instance to search for the feature.
* @param {typeof Object3DFeature} FeatureClass - The feature class (constructor) whose instance is being searched for. It must extends Object3DFeature.
* @returns {Object3DFeature | null}
*/
declare function getFeature<TObj extends THREE.Object3D, TFeatureClass extends typeof Object3DFeature>(obj: TObj, FeatureClass: TFeatureClass): InstanceType<TFeatureClass> | null;
/**
* Finds a feature in the given object using a predicate function. Returns the first matching instance of `Object3DFeature` if found, otherwise `null`.
* @param {THREE.Object3D} obj - The target Three.js `Object3D` instance to search within.
* @param {(feature: Object3DFeature) => boolean} predicate - A predicate function that receives a feature instance as an argument and returns a boolean indicating whether the feature matches.
* @returns {Object3DFeature | null}
*/
declare function getFeatureBy<TObj extends THREE.Object3D, TFeature extends Object3DFeature>(obj: TObj, predicate: (feature: TFeature) => boolean): TFeature | null;
/**
* Retrieves all features attached to a given object. Returns a copy of the feature list—an array of `Object3DFeature[]` instances—or `null` if no features were added.
* @remarks Note that changing returned array won't affect anything. It returns a **COPY** of this object features list.
* @param {THREE.Object3D} obj - The target Three.js `Object3D` instance.
* @returns {Object3DFeature[] | null}
*/
declare function getFeatures<TObj extends THREE.Object3D>(obj: TObj): Object3DFeature[] | null;
/**
* Destroys and detaches all features from the given object, freeing associated resources.
* If `recursively` is set to `true`, this method will apply cleanup recursively to the entire object hierarchy.
* @param {THREE.Object3D} obj - The target Three.js `Object3D` instance.
* @param {boolean} recursively - (Optional) Default is `false`. A boolean flag indicating whether to apply this method recursively to the object's hierarchy.
*/
declare function clear<TObj extends THREE.Object3D>(obj: TObj, recursively?: boolean): void;
declare const utils: {
removeArrayItem: typeof removeArrayItem;
props: typeof props;
traverseUp: typeof traverseUp;
assertDefined: <T>(value: T | null | undefined, name: string) => T;
};
declare const REVISION = "2.0.0";
declare global {
interface Window {
__THREE_KVY_CORE__?: string;
}
};
export { CoreContext, CoreContextModule, type ICoreContextModuleProtected, type IFeaturable, type IFeaturableRoot, type ModulesRecord, type ModulesRecordDefault, Object3DFeaturability, type Object3DFeaturabilityEventTypes, Object3DFeature, REVISION, type ReturnOfUseCtx, ThreeContext, type ThreeContextEventMap, type ThreeContextParams, addFeature, clear, getFeature, getFeatureBy, getFeatures, utils };
}
declare module "@vladkrutenyuk/game-world" { export=KVY;}