CoreContext

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.

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as KVY from "@vladkrutenyuk/three-kvy-core";

const ctx = KVY.CoreContext.create(THREE);

const mesh = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshNormalMaterial());
ctx.root.add(mesh);

const controls = new OrbitControls(ctx.three.camera, ctx.three.renderer.domElement);

ctx.three.mount(document.querySelector("#canvas-container"));
ctx.run();

What is ctx.three?

The ThreeContext instance. Utility to initialize the core three.js entities, manage their setup and rendering.
Inside of CoreContext, it is linked so that starting the animation loop with ctx.run() triggers rendering.

ctx.three.on("mount", (container) => console.log("mount!", container));
ctx.three.on("resize", (width, height) => console.log("resize!", width, height));
ctx.three.on("renderbefore", () => console.log("render!"));

ctx.three.mount(document.querySelector("#canvas-container"));
// >>> "mount!", [HTMLElement]
// >>> "resize!", [number], [number]
// >>> "render!"

ctx.run();
// >>> "render!"
// >>> "render!"
// ... each frame until `stop`

ctx.stop();

All of this (mount/unmount and run/stop) can be called in any order, separately from each other, and as many times as needed.

What is ctx.root?

The THREE.Object3D instance that plays the role of entry point of context propagation for objects features aka Object3DFeature. By default ctx.root is THREE.Scene (ctx.root === ctx.three.scene). You can specify any other root if you initialize through the constructor.

const grid = new THREE.GridHelper();
ctx.root.add(grid);

class MyFeature extends KVY.Object3DFeature {
  useCtx(ctx) {
    console.log("ctx was attached", ctx);
    return () => console.log("ctx was detached", ctx);
  }
}

const feature = KVY.addFeature(grid, MyFeature);
// >>> "ctx was attached", [CoreContext]

ctx.root.remove(grid);
// >>> "ctx was detached", [CoreContext]

For features to work, their objects must be in the hierarchy of ctx.root.
Read more about this in the API section "Object3DFeatures" under "Context Propagation. Attach and Detach."

What are context modules?

You can read more about modules in the API section CoreContextModule.

There is a wonderful opportunity to extend CoreContext functionality through pluggable modules (CoreContextModule). Modules are assigned to ctx and provide services to features (Object3DFeature) and enable clean separation of concerns.

class MyModule extends KVY.CoreContextModule {
  constructor(label) {
    this.label = label;
  }

  useCtx(ctx) {
    console.log(`[${this.label}] assigned to ctx`, ctx)
    return () => console.log(`[${this.label}] removed from ctx`, ctx)
  }

  whoAmI() {
    console.log(`I am ${this.label}!`);
  }
}
const ctx = KVY.CoreContext.create(THREE, { cucumber: new MyModule("super") });
// >>> "[super] assigned to ctx", [CoreContext]

ctx
  .assignModule("tomato", new MyModule("turbo"))
// >>> "[turbo] assigned to ctx", [CoreContext]
  .assignModules({ orange: new MyModule("nitro"), apple: new MyModule("mega") });
// >>> "[nitro] assigned to ctx", [CoreContext]
// >>> "[mega] assigned to ctx", [CoreContext]

ctx.modules.cucumber.whoAmI();
// >>> "I am super!"
ctx.modules.tomato.whoAmI();
// >>> "I am turbo!"
ctx.modules.orange.whoAmI();
// >>> "I am nitro!"
ctx.modules.apple.whoAmI();
// >>> "I am mega!"

Assign modules to context

  1. When initializing CoreContext as a dictionary of instances of implementations of CoreContextModule.
  2. After initialization through the methods assignModules, assignModule.

Access to context modules

You can access the modules through the dictionary (.modules)(#modules) where the modules are located by the keys that were specified.

Propagating into features

//TODO: описать вкратце

API

Extends EventEmitter.

Constructor

new CoreContext( three: ThreeContext, root: Object3D, clock: Clock, modules?: Object )

  • three - An instance of ThreeContext. Utility to manage Three.js setup.
  • modules? - (optional) Custom dictionary of any your modules CoreContextModules.
  • 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 ThreeContext will be taken as root.
import * as THREE from "three";
import * as KVY from "@vladkrutenyuk/three-kvy-core";

const three = KVY.ThreeContext.create(THREE, { renderer: { antialias: true } })

const modules = {
    moduleA: new MyModuleA(),
    moduleB: new MyModuleB(),
};

const myCustomRoot = new THREE.Group();
three.scene.add(myCustomRoot);

const ctx = new KVY.CoreContext(three, modules, myCustomRoot);

Static Methods

create( Three: Object, modules?: Object, params?: Object ): CoreContext

Initialization shortcut. Creates and returns a new CoreContext instance.

  • Three - Object containing Three.js class constructors WebGLRenderer, Scene, PerspectiveCamera, Clock, Raycaster. In short, just use imported THREE Three.js module.
  • modules - (optional) Custom dictionary of CoreContextModule implementations instances.
  • params - (optional) Object parameters
  • params.renderer - (optional) Object parameters for Three.js WebGLRenderer.
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 } });

Properties

.isCoreContext: Boolean

(readonly) Flag to mark that it is an instance of CoreContext.

.three: ThreeContext

(readonly) Instance of ThreeContext. Utility to manage Three.js setup.

.root: Object3D

(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.

.modules: Object;

(readonly) Dictionary of assigned modules to this.

.deltaTime: Float

(readonly) The seconds passed since the last frame.

.time: Float

(readonly) The seconds passed since the context loop started (run).

.isCoreContext: Boolean

(readonly) Flag to mark that it is an instance of CoreContext.

.isDestroyed: Boolean

(readonly) Flag to check if this instance is destroyed.

.isRunning: Boolean

(readonly) Flag to check if this instance loop is running.

Methods

.run(): void

Run animation loop and Three.js rendering through. Stoppable as many times as you need by stop().

.stop(): void

Stop animation loop and Three.js rendering. Resumable as many times as you need by run().

.assignModules( modules: Object ): this

Assigns the given dictionary of modules to this instance. It will be merged with the existing dictionary of modules.
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.

  • modules - Dictionary of module instances to assign to this context.

.assignModule( key: String, module: CoreContextModule ): this

Assign module by key to this instance. It will be added to the existing dictionary of modules by the given key.
Note that if the given key is already assigned, it will be skipped, and a warning message will be fired.

  • key - The key by which to assign the module to the context in the dictionary.
  • module - An instance of CoreContextModule implementation.

.removeModule( key: String ): this

Remove a module by key that was specified when it was assigned.

  • key - key by which a module was assigned.

.findModule( predicate: Function ): CoreContextModule | undefined

.findModuleKey( predicate: Function ): string | undefined

Finds the key of a module in this context using a predicate function.
Returns the key of the first matching instance of CoreContextModule if found, otherwise undefined.

  • predicate - A predicate function that receives a module instance and returns true if it matches the search criteria.

.destroy(): this

Destroy this instance.

  • Sets .isDestroyed to true permanently.
  • Stops this animation loop permanently.
  • Destroys its ThreeContext permanently.
  • Fires the "destroy" event.
  • Cleans up .root from the assigned logic when it was designated as root in the given CoreContext.
  • Removes all assigned modules.
  • Removes all listeners from its events.

Events

destroy

Fires when the context has been destroyed.

looprun

Fires when the context loop has been run.

loopstop

Fires when the context loop has been stopped.

Source

src/core/CoreContext.ts

three-kvy-core ...