Koru JavaScript API

Koru lets you do simple scene manipulation using JavaScript. It provides API for nodes, snapshots and camera - just enough to build custom scene tree, snapshots buttons and even simple animations or interactive pages.

Koru JavaScript Object

Each Koru scene on the page has its own JavaScript object of type Koru. You can get it using the code below:

var el = document.getElementById("my-object");
var my_object_koru = el.koru;

Where my-object is the id of the koru-viewport <div>. This way you can have many Koru scenes on the same page and control them independently.

Here are the list of Koru object properties you can use:

Property Type Description
root Koru.Node the root node of the scene
snapshots [Koru.Snapshot] the array of snapshots objects
materials {Koru.Material} the dictionary of scene materials, names are the keys
camera Koru.Camera the camera object of the scene
createSnapshotButtons boolean flag which is true by default, but you can set it to false if you want to create snapshots buttons yourself
showProgressBar boolean flag which is true by default, but can be set to false if you don’t want to see the default loading progress bar

Here is the list of methods that Koru object has:

  • draw(frames : integer) - forces the immediate drawing of frames samples, waits until the drawing ends;
  • invalidate(frames : integer) - tells Koru that frames samples need to be drawing, do not wait until it ends.

Koru object also provides some events you can add listeners to:

  • loadstart - notifies that scene loading has started. Use this to display your own custom loading progress indicator;
  • progress - notifies about loading progress;
  • loadend - lets you know that the loading is over. Use to hide custom loading progress indicator and access snapshots;
  • update - this one is sent every frame and you can use it to animate scene;
  • visibilitychange - notifies about node visibility changes.

Each event gets a dictionary as a parameter. The dictionary contains important information regarding the event. Here are the list of keys of the dictionary:

Key Type Description
koru Koru contains Koru object
progress number a floating point value from 0 to 1, defining the current loading progress (only in progress event)
deltaTime number time in seconds from the previous scene update (only in update event)
idleTime number time in seconds that the scene is left idle (only in update event)
node Koru.Node contains node that has changed (only in visibilitychange event)

Here’s how you can be notified about end of loading scene:

function koruInit(koru) {
    koru.addEventListener('loadend', onKoruLoaded);
}

function onKoruLoaded(event)
{
    var which_koru = event.koru;
    // do something
}

Function koruInit() is called by the Koru core when the scene is loaded. You can setup flags and subscribe to events here. The second function is called when the scene is loaded. You get Koru object from the event’s parameters and use it to access scene API.

Snapshots

The best way to see what you can do with snapshots API is to have a look at the built-in Snapshots export template code. Basically, there are two things you can do:

  • Replace snapshots buttons with your own;
  • List and activate snapshots when needed.

Here’s how to override snapshots buttons creation:

function koruInit(koru) {
    koru.createSnapshotButtons = false;
    koru.addEventListener('loadend', onKoruLoaded);
}

function onKoruLoaded(event)
{
    var k = event.koru;

    for (var i in k.snapshots)
    {
        var snapshot = k.snapshots[i];
        if (!snapshot.visible) continue;
        console.log(snapshot.name);
    }
}

Here we tell Koru that we’ll handle snapshots button creation ourselves, then start listening for loadend event. Once we get the event, we run through the scene snapshots and log the names of the visible ones.

Here’s what you can do with snapshots in Koru API:

  • Enumerate them using snaphots property - this is a simple array of snapshot objects;
  • Check their visibility using visible property of snapshot;
  • Get their names using name property of snapshot;
  • Activate them using apply() method.

Once again, the best way to learn snapshots API is to have a look at snapshots export template which features everything discussed above.

Nodes

Each scene node in Koru JavaScript API has following properties:

Property Type Description
name string lets you get the name of the node
metadata object the metadata dictionary of the node
userData object the user defined data of the node
visible boolean lets you show and hide nodes by settings true or false values
position Koru.Vec3 the position of the node
rotation Koru.Vec3 the Euler rotation angles of the node
scale Koru.Vec3 the scale of the node
matrix Koru.Mat4 the local transformation matrix of the node, read-only
matrixWorld Koru.Mat4 the world transformation matrix of the node, read-only
boundingBox Koru.Box3 the oriented bounding box of the node’s meshes, read-only
highlightColor Koru.Color the highlight color of the node
parent Koru.Node the parent node (or null if the node is root), read-only
children [Koru.Node] returns the array of the children nodes of this one
meshes [Koru.Mesh] return the array of meshes that this node contains

Here is the list of node methods:

  • traverse(callback : function) : any - executes the callback function on this node and its descendants, returns the first positive callback result or undefined;
  • traverseVisible(callback : function) : any - like traverse, but the callback will only be executed for visible nodes, returns the first positive callback result or undefined;
  • traverseAncestors(callback : function) : any - executes the callback function on node descendants, returns the first positive callback result or undefined;
  • getNodesByName(name : string) : [Koru.Node] - finds child nodes with the specified name;
  • updateMatrix() - updates the local transformation matrix;
  • intersect(ray : Koru.Ray) : boolean - intersects the ray with the node meshes;

For examples of using node API, have a look at scene-tree export template which uses most of the properties mentioned above. Also try clock snippet in Script Editor (Scene->Script Editor) which shows how to make animated clock model by rotating clock hands using node rotation API.

Meshes

Here is the list of mesh properties:

Property Type Description
material Koru.Material the material of the mesh, read only
highlightColor Koru.Color the highlight color of the mesh
boundingBox Koru.Box3 the oriented bounding box of the mesh, read only
userData object the user defined data of the mesh

Each mesh in Koru JavaScript API has material parameter that contains a Material object described below. Here’s how you can access meshes of a node:

var n = koru.root.getNodesByName("node")[0]
var meshes = n.meshes;
for (var i = 0; i < meshes.length; i++)
    console.log(meshes[i].material);

Mesh objects also have the intersect(ray : Koru.Ray) : boolean method that checks the intersection of a ray with the mesh.

Materials

You can get the list of materials using koru.materials property or by enumerating all the nodes, meshes in them and getting their materials. Each Material object has the following properties and methods:

Name Type Description
layers [Koru.MaterialLayer] the array of Layer objects (see below)
transparent boolean true or false, depending on the materials parameters
doubleSided boolean true or false, depending on the materials parameters
userData object the user defined data of the material
update() - updates internal parameters of the material - call this after changing the material

You can get all the layers from the array returned by the layers property. Each layer has the following properties and methods:

Name Type Description
diffuseEnabled boolean returns if the diffuse block is enabled
diffuseColor Koru.Color gets or sets the diffuse tint color. Use either unsigned int or Koru.Color object
diffuseMap Koru.Texture gets or sets the diffuse texture. The layer needs to have this texture in the original scene, as otherwise Koru ignores this property
specularEnabled boolean returns if the specular block is enabled
specularColor Koru.Color same as diffuseColor, but for the specular one
specularMap Koru.Texture same as diffuseMap, but for the specular map
emissiveEnabled boolean returns if the emissive block is enabled
emissiveColor Koru.Color same as diffuseColor, but for emissive color
emissiveMap Koru.Texture same as diffuseMap, but for emissive map
mask Koru.Texture controls layer’s mask
opacity number opacity level of this layer
update() - call this after changing layer’s parameters, except for the maps

All the maps you want to update using API need to have a texture when the scene is exported. Otherwise Koru exports a simpler shader and assigning texture will be ignored.

The maps are of the Koru.Texture type and can be either assigned directly (using the standard Image object), or using the following methods:

  • setFromImage(image : Image/Canvas) - updates texture with HTML Image object or with HTML Canvas object;
  • = - you can also assign image, canvas or url directly to the property and Koru will handle that, as well.

A sample code that modifies the diffuse map of the very first layer of the material of the very first mesh of the first node:

var layer = koru.root.children[0].meshes[0].material.layers[0];
layer.diffuseColor.setRGBA(1, 0.5, 0, 0.5);
layer.diffuseMap.set(koru.canvas);
layer.update();

The first line is long, but simple: it gets a “very first” layer. The second line modifies the diffuse tint, the third line assigns the current preview as a texture and the last line updates the layer.

Texture

Koru Texture object has just one method setFromImage(image : Image/Canvas) : this, which updates texture with HTML Image object or with HTML Canvas object.

Camera

You can also manipulate the scene camera with JavaScript. Here’s how to get the camera object:

function koruInit(koru) {
    koru.addEventListener('loadend', onKoruLoaded);
}

function onKoruLoaded(event)
{
    var k = event.koru;
    var cam = k.camera;

    // access camera properties here
}

Here is the list of camera properties:

Property Type Description
target Koru.Vec3 the rotation center of the camera
position Koru.Vec3 the camera position. If camera position is changed, it automatically rotates to see its target
rotation Koru.Vec3 the Euler angles of camera rotation: z - yaw, y - pitch and x - roll
distance number the camera distance from its center of rotation
matrixWorld Koru.Mat4 the camera world matrix, read only
matrixView Koru.Mat4 the camera view matrix, read only
matrixProj Koru.Mat4 the camera projection matrix, read only
matrixViewProj Koru.Mat4 the camera view projection matrix, read only

You can create complex animations by combining node and camera transformations.

Camera object also has the following methods:

  • lookAt(targetPosition : Koru.Vec3) - set the camera target to the specified position;
  • getRay(x : number, y : number) : Koru.Ray - make a ray through the screen, where x is in the range [-1, 1] from left to right, and y is in the range [-1, 1] from bottom to top.

Ray

Ray object is used for tracing through the scene and compute hit points. This is useful for custom scene objects selection, for instance to display methadata and so on.

Here’s how to construct a Ray object:

var ray = new Koru.Ray(origin : Koru.Vec3, direction : Koru.Vec3, tfar : number)

Ray objects have the following properties:

Property Type Description
origin Koru.Vec3 the origin of the ray
direction Koru.Vec3 the direction of the ray
tfar number the maximum distance from the ray origin

Ray objects also have these methods:

  • getPoint(distance : number) : Koru.Vec3 - returns a point along the ray at the distance from the beginning;
  • hitPoint() : Koru.Vec3 - returns the hit point of the ray, same as above, but uses tfar as distance.

Vec3

Vec3 object holds three floating point numbers and used for position, rotation and scale parameters. Here’s how to make one:

var v1 = new Koru.Vec3();
var v2 = new Koru.Vec3(x : number, y : number, z : number);

Vec3 objects have three properties:

Property Type Description
x number x component
y number y component
z number z component

They also have quite a lot of methods:

  • copy(vector : Koru.Vec3) : this - copies another vector to this one;
  • clone() : Koru.Vec3 - clones this vector and returns a copy;
  • setXYZ(x : number, y : number, z : number) : this - inits this vector with three numbers;
  • setScalar(value : number) : this - sets all the components of this vector with the same scalar value;
  • setFromArray(array : [ number ]) : this - inits this vector from array of numbers;
  • toArray() : [ number ] - converts this vector to array of numbers;
  • add(vector : Koru.Vec3) : this - adds another vector to this one;
  • sub(vector : Koru.Vec3) : this - subtracts another vector from this one;
  • mul(vector : Koru.Vec3) : this - multiplies this vector to another one (per-component);
  • mul(value : number) : this - multiplies this vector to a scalar number;
  • div(vector : Koru.Vec3) : this - divides this vector to another one (per-component);
  • div(value : number) : this - divides this vector to a scalar number;
  • lerp(vector : Koru.Vec3, f : number) : this - finds an intermediate vector between this one and another using a parameter;
  • dot(vector : Koru.Vec3) : number - computes dot product of this vector and another;
  • cross(vector : Koru.Vec3) : this - computes cross product of this vector and another;
  • length() : number - computes the length of this vector;
  • normalize() : this - normalizes this vector;
  • transform(matrix : Koru.Mat4) : this - transforms this vector as a position vector using a matrix (moves it);
  • transformNormal(matrix : Koru.Mat4) : this - transforms this vector as a normal vector using a matrix (doesn’t move it);
  • equals(vector : Koru.Vec3) : boolean - compares this vector with another.

Quaternion

Here’s how to make a Quaternion object in Koru:

var q1 = new Koru.Quaternion();
var q2 = new Koru.Quaternion(x : number, y : number, z : number, w : number);

Quaternion objects have these properties:

Property Type Description
x number x component
y number y component
z number z component
w number w component

They also have the following methods:

  • copy(vector : Koru.Quaternion) : this - copies other Quaternion to this one;
  • clone() : Koru.Quaternion - clones this quatenion and returns a copy;
  • setFromMatrix(matrix : Koru.Matrix) : this - inits this quaternion from a matrix;
  • setFromArray(array : [ number ]) : this - inits this quaternion from an array of four numbers;
  • toArray() : [ number ] - converts this quaternion to array of numbers;
  • slerp(quaternion : Koru.Quaternion, f : number) : this - finds an intermediate quaternion between this one and another using a parameter;
  • equals(quaternion : Koru.Quaternion) : boolean - compares this quaternion with another.

Mat4

Mat4 object represents a 4x4 matrix and is used for local transformations. Here’s how to make one:

var m1 = new Koru.Mat4();
var m2 = new Koru.Mat4(elements : [ number ])

These object have just one property: m : [number] - an array of 16 numbers, representing the matrix. There are also methods:

  • copy(matrix : Koru.Mat4) : this - copies another matrix to this one;
  • clone() : Koru.Mat4 - clones this matrix and returns a copy;
  • setIdentity() : this - sets this matrix to the identity one;
  • setFromQuaternion(quaterion : Koru.Quaternion) : this - inits this matrix from a Quaternion object;
  • setPosition(position : Koru.Vec3) : this - inits this matrix as a translation one;
  • setRotation(rotation : Koru.Vec3) : this - inits this matrix as a rotation one;
  • setTransformation(position : Koru.Vec3, rotation : Koru.Vec3, scale : Koru.Vec3) : this - inits this matrix with offset, rotation and scale parameters;
  • setFrustum(left : number, right : number, bottom : number, top : number, near : number, far : number) : this - inits this matrix as a frustum one;
  • setFromArray(array : [ number ]) : this - inits this matrix from an array of 16 numbers;
  • toArray() : [ number ] - converts this matrix to array of numbers;
  • mulMatrices(matrixA : Koru.Mat4, matrixB : Koru.Mat4) : this - multiply two matrices;
  • mul(matrix : Koru.Mat4) : this - mutltiply this matrix to another one;
  • invert(matrix : Koru.Mat4) : this - invert this matrix.

Box3

Box3 object represets a bounding box - two vectors, defining minimum and maximum points in the space. Here’s how to create one:

var bb = new Koru.Box(min : Koru.Vec3, max : Koru.Vec3)

Box3 objects have two properties:

Property Type Description
min Koru.Vec3 the “minimum” point of the box
max Koru.Vec3 the “maximum” point of the box

They also have the following methods:

  • copy(box : Koru.Box3) : this - copies another Box3 object to this one;
  • clone() : Koru.Box3 - clones this bounding box and returns a copy;
  • center() : Koru.Vec3 - returns the center of this bounding box;
  • size() : Koru.Vec3 - returns the size of this bounding box (max - min);
  • intersect(ray : Koru.Ray) : boolean - checks if a ray intersects this bounding box and modifies the ray’s tfar if it does;
  • occluded(ray : Koru.Ray) : boolean - tests if the ray intersects the box, but don’t modify any of them.

Color

Color object represents a RGBA color, defined by 4 floating point numbers. Here’s how to create a Color oject:

var c1 = new Koru.Color();
var c2 = new Koru.Color(red : number, green : number, blue : number, alpha : number);

Here are the properties of Color object:

Property Type Description
r number the red component of the color
g number the green component of the color
b number the blue component of the color
a number the alpha component of the color

Color objects also have the following methods:

  • copy(vector : Koru.Color) : this - copies another color to this object;
  • clone() : Koru.Color - clones this object and returns a copy;
  • setRGBA(red : number, green : number, blue : number, alpha : number) : this - inits this color with the provided parameters;
  • setHex(hex : number) : this - inits this color with an integer number in the form of 0xAARRGGBB;
  • setScalar(value : number) : this - sets red, green and blue components of the color to the provided parameter, sets alpha to 1;
  • setFromArray(array : [ number ]) : this - inits the color from array of numbers;
  • toArray() : [ number ] - returns this color as array of numbers;
  • lerp(color : Koru.Color, f : number) : this - finds an intermediate Color between this one and another using a parameter.

Progress Bar

For overriding progress bar you need to set showProgressBar property to false once the window is loaded and Koru object is created, then handle loadstart, progress and loadend events yourself. Then you can create/show your own progress indicator, update it and hide when the scene is loaded.

See progress export template for a complete example of overriding loading progress bar.