Modules

Modules provide easy integration with components. They can make a lot of complex things much simpler to other developers (such as adding 3D physics).

Articles:

Simple module

Let's create a simple module that will add .alertRandom() method to component, in which this module is used.

export default class SimpleModule {
  integrate() {
    this.alertRandom = function () {
      alert(Math.random());
    }
  }
}
import SimpleModule from './SimpleModule';

const sphere = new WHS.Sphere({
  modules: [
    new SimpleModule()
  ]
});

sphere.alertRandom(); // will alert a random number.

Advanced module

This example demonstrates the power of using modules.

export default class AdvancedModule {
  constructor(params = {}) {
    this.params = Object.assign({
      color: 0xff0000 // red
    }, params); // Polyfill params with default values
  }

  bridge = {
    material(inputMaterial, self) { // self - module scope
      const outputMaterial = inputMaterial.clone(); // You know, it's not required

      outputMaterial.color.setHex(self.params.color);

      return outputMaterial;
    }
  }

  integrate(self) { // self - module scope
    this.checkForColor = function () {
      if (this.material.color.getHex() === self.params.color) {
        alert("color is the same");
      } else {
        alert("???");
      }
    }
  }

  manager(manager) {
    manager.set('usedColor', this.params.color); // other modules can access this
  }
}
import {MeshComponent} from WHS;
import AdvancedModule from './AdvancedModule';

class MyComponent extends MeshComponent {
  build() {
    return new THREE.Mesh(
      new THREE.SphereGeometry(),
      this.applyBridge({material: new THREE.MeshBasicMaterial()}).material
    )
  }
}

const myInstance = new MyComponent({
  modules: [
    new AdvancedModule({color: 0x0000ff}) // blue color
  ]
});

myInstance.checkForColor(); // alerts "color is the same"

API

constructor()

Used to handle input parameters that define module's behavior

.integrate(self)

In this method of any module, this is replaced with component's instance. integrate() is executed once when component instance is created with new keyword.

self - module scope.

.postIntegrate(self)

Same as .integrate(self), but is invoked after .build(), that means you can use .defer(() => {}) inside it. Will be useful for working with models (WHS.Importer) and .native objects.

.manager(manager)

Allows components communicate with each other. manager - is a ModuleManager instance provided by Component or App, where module is used

.bridge

  • Object that handles functions called from component's code with .applyBridge() method.
  • Used to overwrite some parts of component.
  • Functions will be called only if specific component provides API for this "bridge" (using .applyBridge({bridgeName: inputData}).bridgeName).

Module LifeCycle

Module methods are executed in this order:

  1. constructor()
  2. if ModuleManager is provided by component & .manager() exists -> .manager(manager)
  3. if .integrate() exists -> .integrate()
  4. bridges are executed if such API is provided by components.

Only constructor() is executed once when you create a module instance. All other methods are executed once per component, where they are used.

Therefore, you can use one module instance per multiple components in performance reasons (Recommended)

Bridges provided by included components (WHS.Sphere, ...)

Bridge name Value provided
geometry THREE.Geometry instance
material THREE.Material instance
mesh THREE.Mesh instance

> Animation Clips