# Requires .npmrc with a valid access token for the private registry
npm install @kognifai/cogsengine
# Required peer dependency — math types used throughout the API
npm install gl-matrix
# Required if using WebXR, or if TypeScript reports errors in cogs.esm.d.ts
npm install --save-dev @types/webxr
# Optional — extra vector utilities and camera helpers
npm install @kognifai/cogsmatrix
Recommended imports:
import * as Cogs from "@kognifai/cogsengine";
import { dvec3 } from "@kognifai/cogsengine";
import { vec3, vec4, quat } from "gl-matrix";
| Class | Access | Purpose |
|---|---|---|
| Control | Entry point | Owns the canvas, initializes the engine |
| Runtime | control.runtime |
Creates entities and components, owns Resources and Scene |
| Scene | control.runtime.scene |
Picking, scene origin, entity search, bounding box queries |
| Resources | control.runtime.resources |
Loads textures, models and assets; manages resource lifetime |
| RuntimeEntity | Base class | Root type of all scene objects; stored in the engine with GPU-retained state |
| Component | Base class | Unit of functionality attached to an entity |
Commonly used components:
| Component | Purpose |
|---|---|
| TransformComponent | Position, rotation, scale |
| SceneComponent | Visibility, pickability, child hierarchy |
| MaterialComponent | Appearance (colour, texture) |
| MeshComponent | Raw geometry data |
| MeshRenderComponent | How geometry is rendered (primitive type, render state) |
| LodComponent | Level-of-detail switching |
Each Cogs instance renders into an HTMLCanvasElement. Set up your HTML layout and pass the canvas to Cogs — do not call WebGL APIs on the canvas yourself.
See Introduction — Angular based example for a complete integration example. The essential pattern:
const control = await Cogs.Control.create({
parent: canvasElement,
fetchHandler: myFetchHandler,
onInitialized: () => initScene(),
});
const runtime = control.runtime;
The fetchHandler is a small bridge that lets the Cogs WASM module load its own internal assets (shaders, material definitions, textures) via the browser's network stack. Cogs calls fetch() with a URL, byte offset, and size; your handler performs an XMLHttpRequest with a Range header and returns the result. The canonical implementation from Introduction — Angular based example:
const fetchHandler: Cogs.IFetchHandler = {
fetch(url: string, offset: number, size: number,
handler: Cogs.FetchResponseHandler, fetchId: number): boolean {
const xhr = new XMLHttpRequest();
cancellableFetches.set(fetchId, xhr);
xhr.responseType = "arraybuffer";
xhr.onloadend = () => {
cancellableFetches.delete(fetchId);
handler(
xhr.status === 200 || xhr.status === 206 ? xhr.response : undefined,
xhr.status
);
};
xhr.open("GET", url);
if (size > 0) {
xhr.setRequestHeader("Range", `bytes=${offset}-${offset + size - 1}`);
}
xhr.send();
return true;
},
cancel(fetchId: number): void {
const xhr = cancellableFetches.get(fetchId);
if (xhr) xhr.abort();
},
};
cancel is called when Cogs decides a pending fetch is no longer needed (e.g. asset unloaded before download completed). Always implement it to avoid leaking in-flight XHRs.
Cogs defaults to WebGL2, which is supported by all modern browsers.
WebGPU is supported as an opt-in alternative to WebGL2. Enable it with:
await Cogs.Control.create({
parent: canvas,
webgpu: true,
// ...
});
WebGPU is available in Chrome and Edge (stable), Firefox (behind a flag), and Safari (experimental, behind a flag). Check runtime.useWebGPU at runtime to confirm which backend is active.
Cogs uses SharedArrayBuffer for multithreading, which requires cross-origin isolation headers on your server:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: credentialless
Safari note:
credentiallessis not supported on Safari. Userequire-corpinstead, but be aware this restricts which cross-origin resources (images, fonts, scripts) can be loaded without aCross-Origin-Resource-Policyresponse header on those resources.
On startup, check the console for:
[TaskMngr][Info] Concurrency: N ... resourceThreads=3 — multithreading is active[Warning][TaskMngr] Multithreaded cogs, but no threading available. — headers are missing or browser is unsupportedCogs consists of a TypeScript interface layer and a WebAssembly module. To avoid memory leaks you must explicitly release both.
control.release();
canvas.removeEventListener("resize", this.onResize);
control.release() shuts down rendering and drops all internal references to the WASM module. The module itself can only be garbage-collected after the canvas element is also collected. Dangling event listeners prevent the canvas from being collected — always use named functions so they can be removed:
// Wrong — lambda cannot be removed:
canvas.addEventListener("resize", () => this.onResize());
// Correct:
canvas.addEventListener("resize", this.onResize);
// ...on shutdown:
canvas.removeEventListener("resize", this.onResize);
Test early: trigger a browser GC (DevTools → Memory → Collect garbage) before and after shutdown and check that memory drops.
The total WebAssembly memory cap is 2 GB. Browsers may impose stricter limits — iOS devices have been observed to cap at ~384 MB. Test on representative target devices for:
Every entity is reference-counted. Adding an entity as a child gives the parent an additional reference. You must explicitly destroy entities when done.
const group = runtime.Group.create();
const cube = runtime.Cube.create();
group.sceneComponent.children.add(cube);
// A) Destroy child first, then parent:
runtime.destroy(cube); // cube now owned only by parent
runtime.destroy(group); // both released
// B) Destroy parent first:
runtime.destroy(group); // cube reverts to root entity (moved back if parent had a transform)
runtime.destroy(cube); // release the cube
Entities can also be created implicitly by loading a scene graph:
runtime.loadAssetFromString(jsonString);
// Or via an Asset entity:
asset.assetComponent.asset = runtime.resources.loadAsset(path);
Asset-loaded children may be deleted on the next redraw. Do not store references to picked entities — reconstruct from an id instead:
const entity = runtime.Entity.wrap(id as Cogs.EntityId);
When picking returns the base Entity class, access components via getComponent or by casting:
function useComponents(entity: Cogs.Entity, runtime: Cogs.Runtime) {
const tc1 = entity.getComponent(runtime.TransformComponent); // TransformComponent | null
const tc2 = (entity as any).transformComponent; // TransformComponent | undefined
const tc3 = (entity as Group).transformComponent; // TransformComponent | undefined
}
One component of each type per entity. A component may only belong to one entity at a time.
const cameraController = runtime.OrbitingCameraController.create();
camera.components.add(cameraController);
cameraController.distance = 50;
// Cleanup:
camera.components.remove(cameraController);
Both auto-created and manually added components can be removed:
// Remove MaterialComponent to use a MeshRenderComponent MaterialInstance instead
const cube = runtime.Cube.create();
cube.components.remove(cube.materialComponent);
Extensions add entity and component types beyond the core. Load an extension before creating any of its entities:
if (!runtime.loadExtensionModule("Potree")) {
throw new Error("Potree extension not available in this build");
}
const cloud = runtime.PotreeModel.create("PointCloud");
Note:
loadExtensionModulemay be deprecated in a future release. IntelliSense shows which extension each entity belongs to.
See Introduction — Entities and Components for the summary, or Manual — Entity Reference for the full list grouped by extension.
Custom entities can be defined in the Cogs scene asset JSON format:
const entityDef = `{
"templates": {
"MyGroup": {
"description": "Custom Group",
"components": [
"TransformComponent",
"SceneComponent",
"CurvedEarthPositionComponent"
]
}
}
}`;
runtime.Entity.loadDefinitions(entityDef);
const myEntity = (runtime as any).MyGroup.create() as MyGroup;
Not all Cogs components and entities are exposed in the TypeScript API. You can register factories for them at runtime.
Unexposed component:
// TypeScript declaration for type safety
declare class CurvedEarthPositionComponent extends Cogs.Component {
position: vec3;
}
declare class MyGroup extends Cogs.Entity {
get transformComponent(): Cogs.TransformComponent;
get sceneComponent(): Cogs.SceneComponent;
get curvedEarthPositionComponent(): CurvedEarthPositionComponent | undefined;
}
runtime.Component.createRuntimeFactory("CurvedEarthPositionComponent");
const earthComp = (runtime as any).CurvedEarthPositionComponent.create() as CurvedEarthPositionComponent;
Unexposed entity:
declare class Overlay extends Cogs.Entity {
get transformComponent(): Cogs.TransformComponent;
get sceneComponent(): Cogs.SceneComponent;
get overlayComponent(): OverlayComponent;
get spriteRenderComponent(): SpriteRenderComponent;
}
runtime.Entity.createRuntimeFactory("Overlay");
const overlay = (runtime as any).Overlay.create("myOverlay") as Overlay;
Always assign or read the whole field value — never mutate a returned object in place:
component.field = newValue; // write
const value = component.field; // read — treat as read-only
C++ types map to TypeScript as follows:
| C++ type | TypeScript type | Source |
|---|---|---|
float vec2/vec3/vec4/quat/mat4 |
vec2, vec3, vec4, quat, mat4 |
gl-matrix |
double vec3 |
Cogs.dvec3 |
@kognifai/cogsengine |
double vec2/vec4 |
Cogs.dvec2, Cogs.dvec4 |
@kognifai/cogsengine (Float64Array aliases) |
uint32 vec |
Cogs.uvec2/3/4 |
@kognifai/cogsengine (Uint32Array aliases) |
int32 vec |
Cogs.ivec2/3/4 |
@kognifai/cogsengine (Int32Array aliases) |
Do not use
Cogs.vec2,Cogs.vec3, etc. — those are deprecated. Usegl-matriximports instead.
Precision trap: JavaScript number is 64-bit double; Cogs fields are 32-bit float. Comparing a value you set against a value you read back can fail:
const oldPos = vec3.fromValues(1.2345, 2.3456, 3.4567); // Float32Array
cube.transformComponent.position = oldPos;
cube.transformComponent.position[0] === 1.2345; // false — float truncation
cube.transformComponent.position[0] === oldPos[0]; // true — both float
const oldPosArr: vec3 = [1.2345, 2.3456, 3.4567]; // number[] (double)
cube.transformComponent.position = oldPosArr;
cube.transformComponent.position[0] === oldPosArr[0]; // false — float vs double
// Safest pattern: read from Cogs both times
const saved = cube.transformComponent.position;
// ...later:
cube.transformComponent.position[0] === saved[0]; // true
Array fields must be set or read as a whole — you cannot modify the returned array:
// Correct:
light.lightComponent.cameras = [camera];
// Wrong — mutation is not detected:
light.lightComponent.cameras.add(camera);
Fields that hold arrays of vectors (e.g. Mesh.positions) use typed arrays for efficiency:
mesh.positions = new Float32Array([
1, 0, 0,
1, 1, 0,
0, 0, 0,
]);
// Compile error in TypeScript, runtime failure in JavaScript:
mesh.positions = [1, 0, 0, 1, 1, 0, 0, 0, 0];
Both vec3 and dvec3 accept either a typed array or a plain number array literal:
camera.transformComponent.position = vec3.fromValues(1000, 0, 0);
camera.transformComponent.position = [1000, 0, 0];
camera.transformComponent.coordinates = dvec3.fromValues(40000, 0, 0);
camera.transformComponent.coordinates = [40000, 0, 0];
Some component fields hold a reference to another entity:
export class DepthAxisComponent extends Component {
trajectory: Entity | null;
}
The field is typed as the base Entity class, but the system expects that entity to have a specific component (here: TrajectoryComponent). Only root entities (not children of a loaded scene) can be used in reference fields.
Most fields can be read back after being set:
const camera = runtime.scene.camera;
const pos = camera.transformComponent.position; // current position
A few field types cannot be read back if they were set from a loaded scene file rather than by client code:
SceneComponent.children)BufferViewFontResourceTextureResource// OK — set and read back by client:
plane.meshComponent.meshHandle = myMesh;
const m = plane.meshComponent.meshHandle; // works
// ERROR — set internally by Cogs, read returns undefined:
const cameras = headLight.lightComponent.cameras;
Textures, models and other GPU resources are loaded and tracked via runtime.resources. Resources you create must be explicitly released when no longer needed.
const texture = runtime.resources.loadTextureViaCogs(imageUrl);
entity.materialComponent.diffuseMap = texture;
// Release your handle — the texture stays alive while still in use by the entity
texture.release();
// To fully free it, also clear the field and destroy the entity
entity.materialComponent.diffuseMap = null;
runtime.destroy(entity);
The most common leak pattern — loading inline without saving the handle:
// Leaks — no way to release the texture:
entity.materialComponent.diffuseMap = runtime.resources.loadTextureViaCogs(imageUrl);
Always keep a reference so you can release it on cleanup:
this.texture = runtime.resources.loadTextureViaCogs(imageUrl);
entity.materialComponent.diffuseMap = this.texture;
// On cleanup:
runtime.destroy(entity);
this.texture.release();
this.texture = undefined;
Texture note:
TextureResourcemust not be released until the entity is destroyed. Other resource types (materials, meshes, models) can be released immediately after assigning to a field.
All resource loading is asynchronous. An entity appears in the scene immediately but renders without its texture/model until loading completes. There is no automatic smooth transition.
To act when a texture finishes loading, use the textureLoadCallback:
const control = await Cogs.Control.create({
// ...
textureLoadCallback: (id: number, code: number) => {
if (id === this.texture.id && code === 0) {
entity.materialComponent.diffuseMap = this.texture;
}
},
});
// Use ForceUnique to ensure the callback fires even if the URL was loaded before
this.texture = runtime.resources.loadTextureViaCogs(imageUrl, {
textureLoadFlags: Cogs.TextureLoadFlags.ForceUnique,
});
Entities render using one of two material APIs. They can be combined on the same entity.
MaterialComponent is the quick path — a component automatically attached to most entities. Set its fields directly and Cogs handles the rest.
MaterialInstance is a resource you load and configure explicitly. It gives access to the full shader parameter set, blend modes, depth state, and variants. Assign it to meshRenderComponent.material.
Both can coexist: MaterialComponent fields are applied on top of the MaterialInstance when both are present. To use a pure MaterialInstance without interference, remove the MaterialComponent:
const cube = runtime.Cube.create();
cube.components.remove(cube.materialComponent);
cube.meshRenderComponent.material = myInstance;
const sphere = runtime.Sphere.create();
const mc = sphere.materialComponent;
mc.diffuseColor = vec4.fromValues(0.2, 0.6, 1.0, 1.0); // RGBA, range 0–1
mc.emissiveColor = vec4.fromValues(0.1, 0.1, 0.1, 1.0);
mc.transparency = 0.4; // 0 = opaque, 1 = invisible
mc.diffuseMap = texture; // TextureResource from runtime.resources
mc.normalMap = normalTex;
mc.specularMap = specTex;
// Geometry / render state
mc.cullMode = Cogs.CullMode.None; // render both sides
mc.depthWriteEnabled = false; // typical for transparent objects
mc.drawOrder = 2; // draw after opaque geometry
mc.enableLighting = false; // unlit
mc.shadowReceiver = true;
Loading and assigning:
const matRes = runtime.resources.loadMaterial("DefaultMaterial.material");
const matInst = runtime.resources.loadMaterialInstance(matRes);
cube.meshRenderComponent.material = matInst;
// Release your handle when the entity is destroyed
matInst.release();
Setting shader properties and textures:
matInst.setProperty("diffuseColor", vec4.fromValues(1, 0.5, 0, 1));
matInst.setProperty("roughness", 0.3);
matInst.setProperty("metallic", 0.8);
matInst.setTexture("diffuseMap", texture);
matInst.setTexture("normalMap", normalTex);
matInst.setTextureAddressMode("diffuseMap", Cogs.AddressMode.Clamp);
matInst.setTextureFilterMode("diffuseMap", Cogs.FilterMode.MinMagMipLinear);
Render state options:
matInst.setOption("CullMode", "None"); // "Front" | "Back" | "None"
matInst.setOption("DepthWriteEnabled", false);
matInst.setOption("DepthTestEnabled", true);
matInst.setOption("DepthTestAlwaysPass", false);
matInst.setOption("DrawOrder", 4); // positive = draw later
Shader variants (select a code path baked into the material):
skyMaterial.setVariant("Source", "EnvironmentRadiance");
skyMaterial.setVariant("StaticLod", "4");
| Name | Use |
|---|---|
DefaultMaterial.material |
Phong shading — diffuseColor, specularColor |
StandardMaterial.material |
PBR — albedo, roughness, metallic, and matching map textures |
CustomPoints.material |
Point cloud rendering — pointSize, colorMap |
The active graphics backend is logged at startup: renderer.graphicsDevice = WebGPU, OpenGLES30, or OpenGLES20. Some material variants are only available on specific backends.
matInst.setOption("Transparency", "On"); // enable alpha blending
matInst.setOption("BlendMode", "Blend"); // "Blend" | "Add" | "PremultipliedBlend"
matInst.setOption("DepthWriteEnabled", false); // don't occlude geometry behind
matInst.setOption("CullMode", "None"); // show back faces too
matInst.setOption("DrawOrder", 2); // draw after opaques
Common BlendMode values:
| Value | Effect |
|---|---|
"Blend" |
Standard alpha blend (src·α + dst·(1−α)) |
"Add" |
Additive — bright halos, particles |
"PremultipliedBlend" |
Premultiplied alpha |
"AlphaToCoverage" |
MSAA coverage mask — no sort needed |
"None" |
No blending (opaque) |
For MaterialComponent, set transparency (0–1) and blendMode:
mc.transparency = 0.5;
mc.blendMode = Cogs.BlendMode.Blend;
mc.depthWriteEnabled = false;
One MaterialInstance can be assigned to many entities — all will render identically:
const sharedInst = runtime.resources.loadMaterialInstance(matRes);
sharedInst.setProperty("roughness", 0.2);
entityA.meshRenderComponent.material = sharedInst;
entityB.meshRenderComponent.material = sharedInst;
entityC.meshRenderComponent.material = sharedInst;
// On cleanup, release once
sharedInst.release();
To give each entity its own appearance, create a separate instance per entity:
for (let i = 0; i < count; i++) {
const inst = runtime.resources.loadMaterialInstance(matRes);
inst.setProperty("roughness", i / count);
entities[i].meshRenderComponent.material = inst;
}
Materials and lighting are tightly coupled — a material's appearance depends entirely on the lights in the scene.
The headlight: Every scene starts with a built-in directional light attached to the camera (runtime.scene.headLight). It always points where the camera looks, so objects are always visible. Disable it when you want full control:
runtime.scene.headLight.lightComponent.enabled = false;
Light types:
| Type | Description | Key fields |
|---|---|---|
Directional |
Sun-like — parallel rays, no position, infinite range | intensity (lux), rotation |
Point |
Light bulb — radiates in all directions from a position | intensity (candela), range |
Spot |
Torch — a cone from a position in a direction | intensity, range, spotAngle |
// Point light — warm white, 100 candela, 20-unit range
const light = runtime.Light.create("Fill");
light.lightComponent.lightType = Cogs.LightType.Point;
light.lightComponent.intensity = 100;
light.lightComponent.range = 20;
light.lightComponent.lightColor = vec4.fromValues(1, 0.95, 0.8, 1);
light.transformComponent.position = vec3.fromValues(0, 5, 5);
// Directional light — sun at 45° pitch, 30° yaw
const sun = runtime.Light.create("Sun");
sun.lightComponent.lightType = Cogs.LightType.Directional;
sun.lightComponent.intensity = 1.0; // lux
const dir = quat.create();
quat.fromEuler(dir, -45, 30, 0);
sun.transformComponent.rotation = dir;
How materials react to lights:
DefaultMaterial (Phong) — responds to all light types; diffuseColor and specularColor control appearanceStandardMaterial (PBR) — physically based; roughness and metallic determine how light scattersmaterialComponent.enableLighting = false makes an entity render as a flat, unlit colour regardless of scene lightsshadowReceiver = true on a material lets it receive shadows cast by lights that have castShadows enabledSee also Introduction — The 3D world for an introduction to UTM coordinates and the Z-up convention.
Cogs uses four coordinate spaces, each with a specific purpose and precision:
Mesh vertex positions before any entity transform is applied. Single-precision (vec3). Keep local coordinates close to the mesh's own origin — precision lost here cannot be recovered downstream.
In a hierarchy, local coordinates are always relative to the parent entity's transform.
Double-precision (dvec3) absolute coordinates. This is what you work with in the application.
vec3 vs dvec3 — and why it matters for UTMJavaScript numbers are 64-bit floats, but the GPU works in 32-bit (vec3). A 32-bit float has only ~7 significant digits of precision. A UTM easting of 598,742.123 already uses 9 digits — so storing it in a vec3 will lose the last two, causing visible jitter or incorrect geometry.
Cogs solves this with a two-part coordinate system:
transformComponent.coordinates (dvec3) — the large world-space offset, stored in 64-bit. Put your UTM values here.transformComponent.position (vec3) — a small local offset from that anchor, stored in 32-bit. Keep this close to zero.scene.origin (dvec3) — a global reference point subtracted before anything goes to the GPU. Set this near the centre of your area of interest.GPU position = (entity.coordinates − scene.origin) + entity.position
[double, stays small] [float, already small]
Setting up a UTM scene:
import { dvec3 } from "@kognifai/cogsengine";
import { vec3 } from "gl-matrix";
// Pick a reference point near your area of interest (e.g. site centre)
const siteEasting = 598_700;
const siteNorthing = 6_638_000;
const siteAltitude = 0;
// Tell the engine to subtract this before sending anything to the GPU
runtime.scene.origin = dvec3.fromValues(siteEasting, siteNorthing, siteAltitude);
// Place an entity at its full UTM position
const marker = runtime.Sphere.create("SiteCentre");
marker.transformComponent.coordinates = dvec3.fromValues(598_742, 6_638_055, 12.5);
// No need to set .position — it defaults to [0, 0, 0]
// Place another entity with a small local offset from its UTM anchor
const sensor = runtime.Cube.create("Sensor");
sensor.transformComponent.coordinates = dvec3.fromValues(598_700, 6_638_000, 0);
sensor.transformComponent.position = vec3.fromValues(1.5, 0.3, 0.8); // metres from anchor
runtime.scene.viewAll();
World coordinate of a root entity:
const world = dvec3.add(dvec3.create(), entity.transformComponent.coordinates, entity.transformComponent.position);
Keep the scene origin near the camera target. If the user navigates far from the origin, update it in steps — continuous updates stress shadow rendering.
Single-precision (vec3) coordinates relative to scene.origin. Used internally by shaders and returned by older Scene API methods. You should not use engine coordinates directly — set scene.origin appropriately and use the World-suffixed picking and bounding-box methods.
Convert if needed:
// World → engine
const engine = dvec3.subtract(dvec3.create(), worldCoord, runtime.scene.origin);
// Engine → world
const world = dvec3.add(dvec3.create(), engineCoord, runtime.scene.origin);
Keep scene.origin near the camera target. Update it in steps — continuous updates stress shadow rendering.
2D pixel coordinates with origin at the lower-left corner of the canvas. Note: scale by the device pixel ratio when working with high-DPI displays.
2D UV coordinates, typically in [0, 1]. U maps horizontal, V maps vertical (first row of image = V=0). Behaviour outside [0, 1] is controlled by material.setTextureAddressMode.
Camera properties — the default camera is runtime.scene.camera. Direct property access:
const cam = runtime.scene.camera;
// Field of view (perspective camera)
cam.cameraComponent.fieldOfView = 60; // degrees
// Clip planes — geometry outside this range is not rendered
cam.cameraComponent.nearPlane = 0.1;
cam.cameraComponent.farPlane = 10000;
// Switch to orthographic projection
cam.cameraComponent.projectionType = Cogs.ProjectionType.Orthographic;
cam.cameraComponent.orthoWidth = 100; // world units wide
viewAll() — repositions the camera to fit all visible entities in the viewport. Call it after adding objects to the scene:
runtime.scene.viewAll();
OrbitingCameraController — add this component to the camera to enable mouse/touch orbit, zoom and pan:
const cameraController = runtime.OrbitingCameraController.create();
runtime.scene.camera.components.add(cameraController);
runtime.scene.viewAll();
Control the camera programmatically:
cameraController.cameraTarget = dvec3.fromValues(0, 0, 0);
cameraController.distance = 20;
cameraController.horizontalAngle = 0;
cameraController.verticalAngle = Math.PI / 2;
cameraController.maxDistance = 10000;
Utility classes:
// Focus on a specific entity's bounding box
const bb = runtime.scene.getBoundingBoxWorld(entity);
Cogs.CameraUtils.viewAllCamera(runtime.scene.camera, bb, [0, 0]);
// Extract angles from any orientation quaternion
const hor = Cogs.CameraHelper.getHorizontalAngle(orientation);
const vert = Cogs.CameraHelper.getVerticalAngle(orientation);
Picking is handled via runtime.scene. All recommended methods return world coordinates (methods suffixed World). Avoid older methods without the suffix — they return engine coordinates.
// Basic: which entity is under the mouse?
const entity = scene.getPickedEntityWorld(mouseX, mouseY, outWorldCoords);
// Advanced: full pick info at mouse position
const info = scene.getPickInfoWorld(mouseX, mouseY);
// All intersections at mouse position
const infos = scene.getPickInfoAllWorld(mouseX, mouseY);
// Pick from a ray (for VR controllers)
const info = scene.getPickInfoFromRayWorld(rayOrigin, rayDirection);
Make an entity non-pickable:
entity.sceneComponent.pickable = false;
By default, all DOM input events on the canvas (pointer, wheel, keyboard, focus) are forwarded to the Cogs engine. The EventFilters interface (Input.ts) lets you intercept any of these events before they reach Cogs — for example to prevent the built-in camera controller from reacting when the pointer is over an HTML overlay element.
Set filters at any time via the control.eventfilters setter:
import type { EventFilters, PointerPosition } from "@kognifai/cogsengine";
control.eventfilters = {
// Return false to suppress the event — Cogs will not see it
pointerdown(event: PointerEvent, pos: PointerPosition): boolean {
// Ignore clicks on overlay UI elements
const target = document.elementFromPoint(event.clientX, event.clientY);
return target === control.canvas;
},
wheel(event: WheelEvent, pos: PointerPosition): boolean {
// Suppress scroll when a modal is open
return !modalIsOpen;
},
keydown(event: KeyboardEvent): boolean {
// Let the browser handle Escape natively
return event.key !== "Escape";
},
};
All available filter hooks:
| Hook | Event type | Extra arg |
|---|---|---|
focus |
FocusEvent |
— |
blur |
FocusEvent |
— |
pointerdown |
PointerEvent |
PointerPosition |
pointerup |
PointerEvent |
PointerPosition |
pointermove |
PointerEvent |
PointerPosition |
pointerenter |
PointerEvent |
PointerPosition |
pointerleave |
PointerEvent |
PointerPosition |
pointercancel |
PointerEvent |
PointerPosition |
wheel |
WheelEvent |
PointerPosition |
keydown |
KeyboardEvent |
— |
keyup |
KeyboardEvent |
— |
contextmenu |
MouseEvent |
PointerPosition |
PointerPosition coordinates are already scaled by the device pixel ratio and are relative to the canvas origin (lower-left). All hooks are optional — omit any you do not need.
Cogs.js supports WebXR for VR and AR experiences. WebXR support is built directly into @kognifai/cogsengine — no separate package is needed.
The main entry point is Cogs.ControlXR, exported from @kognifai/cogsengine. It manages the XR session lifecycle, reference spaces, virtual position/heading, controller input, and rendering to the headset framebuffer.
import * as Cogs from "@kognifai/cogsengine";
const controlXR = new Cogs.ControlXR(control);
control.setXR(controlXR);
// Request an immersive VR session
await controlXR.startXRRequest("immersive-vr", {
sessionFeatures: { requiredFeatures: ["hand-tracking"] },
});
Key ControlXR members:
| Member | Purpose |
|---|---|
startXRRequest(mode, options) |
Request a new XRSession |
virtualPosition (get/set) |
Viewer position in world space — use for teleporting |
virtualHeading (set) |
Programmatic heading/yaw in degrees |
xrActiveSession |
Current XRSession and options |
Event callbacks (passed via options.clientCallbacks: ControlXREventMap):
| Callback | Triggered on |
|---|---|
buttonDown / buttonReleased |
Controller button press/release |
thumbstick / thumbstickDirection |
Thumbstick movement |
triggerDown / triggerReleased |
Trigger press/release |
gripPressed / gripReleased |
Grip press/release |
pinchPressed / pinchReleased |
Hand-tracking pinch gesture |
Working examples are in examples/js/XRExamples/. The Cogs bridge (Cogs.Bridge) is an internal class that communicates with the WASM module — do not call it from application code.
Cogs is structured in three layers:
┌──────────────────────────────────────────┐
│ Cogs.Core │
│ Engine · Systems · Renderer · Scene │
├──────────────────────────────────────────┤
│ Cogs.Rendering │
│ Graphics API abstraction │
│ (WebGL · D3D11/12 · Vulkan · WebGPU) │
├──────────────────────────────────────────┤
│ Cogs.Foundation │
│ Component model · Memory pools │
│ Reflection · Collections │
└──────────────────────────────────────────┘
Each layer only depends on the one below it, keeping the codebase modular and the per-platform adaptation surface small.
Everything in Cogs is a component stored in a typed pool — a flat, contiguous block of memory holding all instances of one component type, like a tightly-packed array of structs.
malloc. The pool uses a free-list over pre-allocated slots.ComponentHandle = index + generation counter. Stale handles detect slot recycling instead of accessing garbage memory.ComponentDataPool so the hot data stays compact.Every frame, the Engine iterates over all registered Systems in strict priority order:
PreDynamicComponents → DynamicComponents
→ PreTransform → Transform → PostTransform
→ View / Camera
→ Geometry / LOD
→ Rendering
Change tracking keeps the loop cheap. Each component carries a bitmask of which fields changed since last frame — the first 24 fields each get their own bit, with an overflow bit for the rest. A system skips a component entirely if no relevant bits are set. Setting a field from TypeScript propagates a changed flag to C++; only what changed gets processed.
The renderer uses a task-based pipeline:
RenderItem structs (mesh + material + transform + flags)IGraphicsDevice abstraction; bucket ordering minimises GPU state changesSwapping the backend (e.g. WebGL → WebGPU) requires no change to the pipeline or scene code above it.
The Cogs engine is written in C++ and compiled to WebAssembly via Emscripten. A flat, C-compatible API (extern "C") in Cogs.Core/Source/Bridge/ exposes engine functionality through opaque handles (BridgeContext, EntityId, ComponentId, FieldId, ResourceId). On the TypeScript side, three layers turn those raw functions into the classes you use in application code:
Application code
↓
Public API (Control, Runtime, Scene, Entity, Component, Resources)
↓
Bridge.ts (typed wrapper — resolves Entity→EntityId, manages WASM buffers)
↓
NativeBridge.ts (Emscripten cwrap wrappers — ~260 functions)
↓
C++ WASM (flat extern "C" functions compiled to WebAssembly)
Field reads and writes use byte-offset-based access — cube.transformComponent.position = v resolves to a direct memory write at a pre-computed offset inside WebAssembly linear memory, with no runtime reflection lookup. This is as fast as a typed array write.
The TypeScript wrappers and field offsets are generated automatically by the Cogs code generator from C++ reflection metadata, so the bindings are always in sync with the engine.
For Cogs engine developers: see Readme-developers.md § Native C Bridge Architecture for the full internal documentation including C API signatures,
cwrappatterns, WASM memory management, and the type-generation pipeline.
| Technique | Benefit |
|---|---|
| Component pools (contiguous arrays) | CPU cache locality — no pointer chasing |
O(1) alloc / free without malloc |
No GC pressure, deterministic timing |
| Per-field change bitmasks | Systems skip unchanged components entirely |
| Render bucket sorting | Minimises GPU state changes per frame |
| Frustum culling before draw | Unseen geometry costs nothing |
| LOD system | Distant objects use fewer triangles |
| WebAssembly | Near-native C++ performance in the browser |
| Direct memory write for field access | No marshalling cost at the JS/WASM boundary |
All entity factories follow the pattern runtime.EntityName.create("optional name"). They return a fully configured entity with all necessary components already attached.
No loadExtensionModule() call needed.
| Factory | Description | API |
|---|---|---|
runtime.Cube.create() |
Unit cube primitive | Cube |
runtime.Sphere.create() |
Unit sphere primitive | Sphere |
runtime.Plane.create() |
Flat plane (useful as a floor or backdrop) | Plane |
runtime.Cylinder.create() |
Cylinder primitive | Cylinder |
runtime.WireCube.create() |
Wireframe cube (useful for bounding box visualisation) | WireCube |
runtime.BasicMeshGeneratorEntity.create() |
Procedural shape — set meshGeneratorComponent.shape to a Cogs.ShapeType |
BasicMeshGeneratorEntity |
runtime.GenericShape.create() |
Custom mesh from raw vertex/index arrays | GenericShape |
runtime.MeshPart.create() |
Generic mesh rendering entity | MeshPart |
runtime.MeshPartWithMaterial.create() |
Mesh with an explicit material component | MeshPartWithMaterial |
runtime.LineShape.create() |
Line rendering (polylines, paths) | LineShape |
runtime.Extrusion.create() |
Extrudes a 2D profile along a Trajectory |
Extrusion |
runtime.Billboard.create() |
Flat quad always facing the camera — for labels and icons | Billboard |
runtime.ModelEntity.create() |
Container for a loaded 3D model (GLB, glTF, OpenGEX, etc.) | ModelEntity |
runtime.Asset.create() |
Instantiates a Cogs .asset file (hierarchical model with metadata) |
Asset |
runtime.Lod.create() |
Level-of-detail container; switches child entities by camera distance | Lod |
runtime.Group.create() |
Empty transform container for grouping objects in the hierarchy | Group |
runtime.Empty.create() |
Bare entity with no components — attach your own | Empty |
runtime.Light.create() |
Light source — set lightComponent.lightType to Point, Directional, or Spot |
Light |
runtime.Camera.create() |
Additional camera (perspective or orthographic) | Camera |
runtime.CameraArray.create() |
Multi-view camera array for VR/stereo rendering | CameraArray |
runtime.SkyDome.create() |
Skybox / environment sphere | SkyDome |
runtime.BasicOcean.create() |
Procedural ocean with waves and reflections | BasicOcean |
runtime.BasicTerrain.create() |
Terrain rendered from elevation and colour data | BasicTerrain |
runtime.Trajectory.create() |
3D path/well-path data used by Extrusion, Wellbore, etc. | Trajectory |
runtime.Wellbore.create() |
Wellbore visualisation along a Trajectory |
Wellbore |
runtime.MarkerPointSet.create() |
Set of 3D marker icons at arbitrary positions | MarkerPointSet |
runtime.LookupColorMap.create() |
Colour lookup map for data-driven colouring | LookupColorMap |
runtime.DataSet.create() |
Generic scalar/vector data container | DataSet |
runtime.Environment.get() |
Global environment settings (ambient light, IBL reflections) | Environment |
runtime.Fog.create() |
Global fog effect | Fog |
Each extension must be loaded before any of its entities or components can be created:
runtime.loadExtensionModule("ExtensionName");
| Factory | Description | API |
|---|---|---|
runtime.AxisCube.create() |
Interactive orientation cube with labelled faces (like the viewport gizmo in 3D apps) | AxisCube |
runtime.CubeMarker.create() |
Named marker dot placed on an AxisCube face |
CubeMarker |
runtime.DepthAxis.create() |
Depth scale axis for well trajectory visualisations | DepthAxis |
| Factory | Description | API |
|---|---|---|
runtime.BadgeSet.create() |
Set of 2D icon/number badges rendered at 3D positions | BadgeSet |
| Factory | Description | API |
|---|---|---|
runtime.Casing.create() |
Casing string visualisation for oil & gas wells | Casing |
runtime.BoreHole.create() |
Open bore hole rendered along a Trajectory |
BoreHole |
runtime.TrajectoryCylinder.create() |
Cylinder swept along a Trajectory |
TrajectoryCylinder |
| Factory | Description | API |
|---|---|---|
runtime.CurtainView.create() |
Vertical curtain slice through volumetric data along a path | CurtainView |
| Factory | Description | API |
|---|---|---|
runtime.DrillBit.create() |
Animated drill bit aligned to a trajectory | DrillBit |
runtime.DrillingRiserJoint.create() |
Standard riser joint segment | DrillingRiserJoint |
runtime.DrillingRiserFlexJoint.create() |
Flexible riser joint at the base of the riser | DrillingRiserFlexJoint |
runtime.DrillingRiserTelescopicJoint.create() |
Telescopic (slip) joint in a riser stack | DrillingRiserTelescopicJoint |
runtime.DrillingRiserTensioner.create() |
Riser tensioner element | DrillingRiserTensioner |
runtime.TensionRing.create() |
Tension ring component for the riser | TensionRing |
runtime.RadialLog.create() |
Radial log data visualised around a wellbore trajectory | RadialLog |
| Factory | Description | API |
|---|---|---|
runtime.HeightMap.create() |
Terrain surface rendered from a height-map image or data array | HeightMap |
runtime.DataSet2D.create() |
2D grid dataset — feeds data into HeightMap and similar |
DataSet2D |
| Factory | Description | API |
|---|---|---|
runtime.HighlightRegion.create() |
Highlights a region of the scene with a coloured overlay | HighlightRegion |
| Factory | Description | API |
|---|---|---|
runtime.Image360.create() |
Equirectangular 360° panorama rendered inside a sphere | Image360 |
| Factory | Description | API |
|---|---|---|
runtime.MultiphaseFlow.create() |
Animated multiphase (oil/gas/water) flow visualisation in a pipe | MultiphaseFlow |
| Factory | Description | API |
|---|---|---|
runtime.OGC3DTiles.create() |
Streams and renders an OGC 3D Tiles dataset (large city models, point clouds, etc.) | OGC3DTiles |
| Factory | Description | API |
|---|---|---|
runtime.PotreeModel.create() |
Streams and renders a Potree point cloud dataset | PotreeModel |
| Factory | Description | API |
|---|---|---|
runtime.ProceduralSky.create() |
Physically-based sky model with sun position and atmospheric scattering | ProceduralSky |
| Factory | Description | API |
|---|---|---|
runtime.Reservoir.create() |
Reservoir grid (Eclipse/RESQML) with per-cell property colouring | Reservoir |
| Factory | Description | API |
|---|---|---|
runtime.SeaCurrents.create() |
Animated sea-current vector field visualisation | SeaCurrents |
| Factory | Description | API |
|---|---|---|
runtime.TexAtlas.create() |
Texture atlas tile system used with large terrain assets | TexAtlas |
| Factory | Description | API |
|---|---|---|
runtime.TwinVisuals.create() |
Container for digital-twin visual configuration (highlighting, transparency, etc.) | TwinVisuals |
runtime.TwinCadModel.create() |
CAD model optimised for digital-twin use (streaming, tagging, selection) | TwinCadModel |
runtime.HighlightRegion.create() |
Region-based highlight overlay (also available standalone via the HighlightRegion extension) |
HighlightRegion |
| Factory | Description | API |
|---|---|---|
runtime.VectorField.create() |
3D vector field rendered as animated arrows or streamlines | VectorField |
| Factory | Description | API |
|---|---|---|
runtime.WellLog.create() |
Well log curves (GR, resistivity, etc.) visualised in 3D along a trajectory | WellLog |
Open the built-in debug GUI (frame rate, entity counts, draw calls, resource stats):
runtime.setVariable("gui.enabled", true);
Log shader source when a shader fails to compile:
runtime.setVariable("effects.logShaderInfo", true); // failed shaders only
runtime.setVariable("effects.logShaderSource", true); // all shaders (verbose)
These are logged at DEBUG level — enable that level in the browser DevTools console filter.
Cogs renders on demand by default — a frame is only drawn when something in the scene has changed. Some features (animations, streaming data) enable continuous rendering automatically, but a static scene should not keep the GPU busy.
Check and control continuous rendering at runtime:
// Check current state
console.log(control.continuousRendering); // true = rendering every frame
// Disable if set unexpectedly
control.setContinuousRendering(false);
To verify: open the browser's GPU process monitor (Chrome: chrome://gpu, Task Manager → GPU) and confirm that GPU usage drops when the scene is idle and the camera is not moving.
If components does not properly check their state the component may for example copy same data to the Mesh at each frame.
Checking this is best done in a Cogs native code (alternatively temporary logging in Cogs.js or GPU debuggers for browser). Mentioned here as CPU and GPU resources are wasted at each frame.
Note that a component can be in many states depending on fields and option fields state. Testing not only static setups, but also state transitions an application may apply is important (at least the most used).
Cogs prints diagnostic messages to the browser console. Control verbosity via a URL parameter when loading your page:
?loglevel=0 Trace — everything (very verbose)
?loglevel=1 Debug
?loglevel=2 Info
?loglevel=3 Warning (default)
?loglevel=4 Error and Fatal only
Example: http://localhost:9876/?loglevel=0#myExample
Key messages to look for on startup:
| Message | Meaning |
|---|---|
[TaskMngr][Info] Concurrency: N ... resourceThreads=3 |
Multithreading active |
[Warning][TaskMngr] Multithreaded cogs, but no threading available. |
Cross-origin isolation headers missing |
[Info] useWebGPU: true |
WebGPU backend active |
Cogs holds GPU and WASM heap memory that is not garbage-collected automatically. Improper cleanup causes leaks that accumulate across view mounts and unmounts.
Quick check with Chrome DevTools:
control.release() explicitly).Lifecycle stress test (using the Cogs examples):
http://localhost:9876/lifeCycleTest.html?retries=2&gui&canvas
r to release the current Cogs control instance.s to restart the current test.The most common causes of leaks are unreleased resource handles (texture.release(), materialInstance.release()) and entities that are destroyed but whose resource handles are still held by application code. See Resource leaks for ownership rules.
If developing an example or a demo test that Cogs cleanup works. In example type 'r' to release Cogs instance.
Can start an example directly using URL. Navigate to example using menu, then copy url to go directly.
http://localhost:9876/?webgl2&loglevel=0#multiphaseFlowExample
`Auto play all examples`
http://localhost:9876/?webgl2&autoplay=4000&loglevel=3
webgl2 Use the WebGL 2 Cogs Rendering engine.
autoplay[=msDelay] Enable auto-play with optional delay (neg to disable).
loglevel=level 0=All, 1=Debug, 1=Info, 3=Warning, 4+=Error+Fatal
The example gallery (examples/index.html) is the interactive showcase for Cogs.js features. Each example is a self-contained JavaScript module that creates and manipulates a Cogs scene inside a shared host page.
Each example lives in its own file under examples/js/Examples/. Files are numbered for ordering (e.g. 0002_EntityExample.js) and export one or more named example functions. The registry that maps display names to files and entry-point function names is the demos array at the top of Main.js:
{ name: "Basic Entity Example", file: "0002_EntityExample.js", entry: "entityExample" }
Before the example function is called, Main.js and ExampleRunner together provide a fully initialised environment:
Cogs.Control is created with a WebGL/WebGPU canvas attached to the page, engine configuration (log level, thread counts, pixel ratio, etc.), and all engine callbacks wired up.ExampleRunner is constructed, giving the example access to control, runtime, scene, and resources. It also registers a mouse-pick handler on the canvas.runtime.clear() is called to reset all Cogs scene state left over from any previous example run in the same page session.OrbitingCameraController looking at the origin from a distance of 50 units.The example function is then called with (control, runtime, exampleRunner). After it returns, ExampleRunner calls example.initialize() (if provided) and wires up a setInterval at approximately 60 Hz that forwards elapsed time (in seconds) to example.update().
Navigating to a different example triggers a full page reload — Cogs is torn down completely and restarted fresh for the new example. This means example code does not need to perform full engine teardown. The optional cleanup() callback in ExampleReturn is called during in-page transitions only (e.g. when recompiling via the Source Code panel or during the XR autoplay test suite), not on normal example navigation.
Install dependencies and start the dev server from the examples/ folder:
cd examples
npm ci
npm run start
This launches live-server on port 9876 with middleware.js applied. Open http://localhost:9876 in your browser.
Cogs.js developers who want to test examples against a local build of @kognifai/cogsengine instead of the published package can use npm link:
# From the repo root — registers the local package globally
npm link
# From examples/ — wires the local package into the examples
cd examples
npm link @kognifai/cogsengine
npm run start
The convenience script start-local does all three steps at once:
cd examples
npm run start-local
To revert to the published package version:
cd examples
npm unlink @kognifai/cogsengine
npm ci
examples/middleware.js is a live-server middleware that injects HTTP response headers required for SharedArrayBuffer support, which is used by the Cogs WebAssembly threading model:
Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp are set on the root page (/).Cross-Origin-Embedder-Policy: require-corp is also set on responses for the Cogs engine JS files served from node_modules/@kognifai/cogsengine/dist/.These headers enable cross-origin isolation, which is a browser prerequisite for SharedArrayBuffer and therefore for multi-threaded WebAssembly execution.
Select an example from the Examples menu in the top navigation bar. The active example is encoded in the URL fragment — for instance:
http://localhost:9876/#entityExample
Navigate between examples with keyboard shortcuts:
| Key | Action |
|---|---|
n or + |
Next example |
p or - |
Previous example |
S |
Restart the current example (useful for checking resource leaks) |
r |
Cleanup the current example and shut down Cogs (useful for checking memory release) |
g |
Toggle the debug GUI overlay (keyboard input is disabled while the GUI is shown) |
h |
Print the list of keyboard shortcuts to the browser console |
The Example Settings menu in the navigation bar provides run-time controls:
| Option | Description |
|---|---|
| Controls | Toggle the draggable Controls panel (shown when the example defines GUI elements) |
| Source Code | Toggle the draggable Source Code panel, which displays — and lets you live-edit — the running example |
| Debug UI | Toggle the built-in Cogs debug overlay |
| Set pixelratio=0.5 | Lower canvas resolution for performance testing |
| Set pixelratio=1.0 | Restore default canvas resolution |
The Source Code panel lets you modify example code and click Compile to reload it without refreshing the page. Reset Code restores the panel to the original file; Reset Example clears any locally stored edits.
URL query parameters configure the example host at startup. Combine them as needed:
http://localhost:9876/?webgl2&loglevel=3#entityExample
| Parameter | Value | Description |
|---|---|---|
controls |
(flag) | Open the Controls panel on startup |
sourcecode |
(flag) | Open the Source Code panel on startup |
debugui |
(flag) | Enable the Cogs debug overlay on startup |
webgl2 |
(flag) | Use WebGL 2 as the rendering backend (default) |
webgpu |
(flag) | Use WebGPU as the rendering backend |
pixelratio |
number | Set the canvas device pixel ratio (e.g. pixelratio=0.5) |
loglevel |
0–4 | Minimum log level passed to the Cogs engine: 0=All, 1=Debug, 2=Info, 3=Warning, 4=Error+Fatal |
globalQueueThreadCountFactor |
number | Fraction of logical CPU cores allocated to the global worker queue (e.g. 0.3) |
globalQueueThreadCountMax |
number | Hard ceiling on global worker queue thread count |
resourceQueueThreadCountFactor |
number | Fraction of logical CPU cores allocated to the resource-loading queue |
resourceQueueThreadCountMax |
number | Hard ceiling on resource-loading queue thread count |
stutter |
(flag) | Batch all engine responses and flush them once per second — stress-tests response-handling code |
Example — disable threading (useful when debugging or profiling single-threaded behaviour):
http://localhost:9876/?resourceQueueThreadCountMax=0#entityExample
Each Cogs.js example can define a custom Controls panel that lets the user interact with the example at runtime. The Controls panel has a predefined set of supported element types, parsed and rendered by index.html.
For an example to have a Controls panel, define an array of GUI entry objects and return it as gui from the example function:
// See complete example below for correct import + TypeScript defs.
const myExampleGUI = [/*gui specification here*/];
export function someExample(control, runtime, exampleRunner)
{
/* example creation code here */
return {
initialize: initFunc, /* optional: ran after creation */
gui: myExampleGUI, /* optional: must be returned if gui wanted */
update: function (t) { /* optional: called at 60 Hz. t = seconds since last call */
/* example update callback */
},
cleanup: cleanupFunc /* optional: ran on cleanup */
};
}
Each entry in the array must have at least three properties: type, name, and callback.
// @ts-check
import * as Cogs from "@kognifai/cogsengine";
import { mat4, quat, vec2, vec3, vec4 } from "gl-matrix";
import { dvec3 } from "@kognifai/cogsengine";
/**
* Skeleton example. Scales a Cube using Example GUI
* Add Example to: examples\index.html:
* { name: "Some Example", file: "9991_someExample.js", entry: "someExample" },
*/
let someSizeChanged = false;
let someSize = 1;
/** @type {import("../ExampleRunner/ExampleRunner").ExampleGuiEntry[]} */
const myExampleGUI = [
{
type: "slider",
name: "Change some size",
min: 1,
max: 2000,
value: someSize,
callback: function (e) {
someSizeChanged = true;
someSize = e.target.value;
},
},
];
/**
* @param {Cogs.Control} control
* @param {Cogs.Runtime} runtime
* @param {import("../ExampleRunner/ExampleRunner").ExampleRunner} exampleRunner
* @returns {import("../ExampleRunner/ExampleRunner").ExampleReturn|void}
*/
export function someExample(control, runtime, exampleRunner) {
const cube = runtime.Cube.create("SomeCube");
return {
gui: myExampleGUI,
update: function (t) {
if (someSizeChanged) {
someSizeChanged = false;
cube.transformComponent.scale = vec3.fromValues(someSize, someSize, someSize);
}
},
};
}
Note: The
updatefunction can be omitted if the GUI callbacks update Cogs state directly.
| type | Description | name | Extra properties | callback |
|---|---|---|---|---|
| button | A clickable button | Displayed inside the button | — | No params |
| slider | A draggable slider | Used as label and id | min (number), max (number), value (number, start value) |
e.target.value = current slider value |
| check | A checkbox | Used as label and id | checked (boolean, default state) |
checked (boolean) = current state |
| select | A dropdown menu | Used as label | items (array of {text, value} objects) |
e.target.value = selected item value |
| divider | A horizontal rule separator | Not used | — | Not used |