@kognifai/cogsengine
    Preparing search index...

    Introduction to Cogs.js

    Who this is for: TypeScript/JavaScript developers who want to display 3D content in the browser but have no prior experience with 3D graphics engines.

    No prior 3D graphics knowledge is required.

    Cogs uses a right-handed, Z-up world coordinate system:

    Axis Direction Geographic meaning
    X East Easting
    Y North Northing
    Z Up Altitude / elevation

    This matches the UTM (Universal Transverse Mercator) coordinate system directly — no manual axis remapping is needed. Distances have no fixed real-world unit; if you work in UTM the natural unit is metres.

    OpenGL vs Cogs: OpenGL's rendering pipeline is Y-up, but Cogs uses Z-up in world space. Cogs handles the internal rotation between these automatically — you always work in Z-up world coordinates.

    The most common vector types you'll encounter are:

    Type What it is Example
    vec3 3D position or direction (single precision) vec3.fromValues(1, 2, 3)
    dvec3 Double-precision 3D position — for large real-world coordinates dvec3.fromValues(600000, 7000000, 0)
    vec4 Colour (R, G, B, A) or homogeneous position vec4.fromValues(1, 0, 0, 1) — red
    quat Rotation (quaternion — think of it as an angle+axis) quat.create() — no rotation

    All colour values are in the range 0–1, not 0–255.

    For a full explanation of vec3 vs dvec3 precision, UTM setup, and the two-part coordinate system, see Manual — World coordinates.


    An entity is any object in your scene — a cube, a 3D model, a light, the camera. By itself an entity does nothing; it is just a container.

    Components are the building blocks that give an entity behaviour and appearance. Every entity has a set of components attached to it. You read and write component fields (properties) to control the entity.

    Entity "MyCube"
    ├── transformComponentposition, rotation, scale
    ├── materialComponentcolour, texture
    ├── meshRenderComponentwhich mesh to render
    └── sceneComponentvisibility, parent/child

    You never construct these components yourself. When you create an entity via runtime.Cube.create(), all relevant components are created and attached for you. You just set their fields:

    const cube = runtime.Cube.create();
    cube.transformComponent.position = vec3.fromValues(0, 2, 0); // move up 2 units

    All entity factories follow the pattern runtime.EntityName.create("optional name"). The built-in entities available out of the box are:

    Core (no loadExtensionModule needed):

    Category Factories
    Primitives Cube, Sphere, Plane, Cylinder, WireCube
    Mesh / model GenericShape, MeshPart, LineShape, Extrusion, Billboard, ModelEntity, Asset
    Organisation Group, Empty, Lod
    Lighting / sky Light, SkyDome, BasicOcean, BasicTerrain, Fog, Environment
    Camera Camera, CameraArray
    Data / paths Trajectory, Wellbore, MarkerPointSet, DataSet, LookupColorMap

    Extensions (each requires runtime.loadExtensionModule("Name")):

    AxisCube · BadgeSet · Casing · CurtainView · Drilling · HeightMap · HighlightRegion · Image360 · MultiphaseFlow · OGC3DTiles · Potree · ProceduralSky · Reservoir · SeaCurrents · TexAtlas · TwinVisuals · VectorField · WellLog

    For the full component lifecycle, custom entities, and advanced field access, see Manual — Entities and Components and Manual — Entity Reference.


    A material defines how the surface of an object looks — its colour, shininess, and how it responds to light.

    A texture is an image (PNG, JPG, etc.) that is "wrapped" onto a surface. You can think of it like shrink-wrap: the image is stretched to cover the shape.

    The simplest way to colour an object is through its materialComponent.diffuseColor:

    import { vec4 } from "gl-matrix";

    cube.materialComponent.diffuseColor = vec4.fromValues(1, 0.2, 0.2, 1); // red

    For more realistic appearance — shiny metals, rough stone, etc. — you use a StandardMaterial with Physically-Based Rendering (PBR) properties:

    Property What it controls Range
    albedo Base colour vec4 (RGBA 0–1)
    roughness How rough/smooth the surface is (0 = mirror, 1 = chalk) 0–1
    metallic Whether the surface is metallic 0–1
    const material = runtime.resources.loadMaterial("StandardMaterial.material");
    const instance = runtime.resources.loadMaterialInstance(material);
    instance.setProperty("albedo", vec4.fromValues(0.95, 0.64, 0.54, 1)); // copper colour
    instance.setProperty("roughness", 0.1);
    instance.setProperty("metallic", 1.0);

    sphere.meshRenderComponent.material = instance;

    // Release when done
    instance.release();

    Each object needs its own material instance (a copy of the material with its own property values), while the underlying material asset is shared. See Manual — Materials for the full API.


    Without light, everything appears dark or uniformly lit. Cogs has a default headlight (a directional light attached to the camera), so you'll see something even with no explicit lights.

    There are three types of light:

    Type Description
    Directional Like the sun — parallel rays from a direction, no position, infinite range
    Point Like a light bulb — radiates in all directions from a position, limited range
    Spot Like a torch — a cone of light from a position in a direction

    Colours and intensities are physical values: intensity is in candela (point) or lux (directional). Start with values around 1–200 and adjust.

    For the full lighting API including intensity units, headlight control, and how lighting interacts with materials, see Manual — Lighting and materials.


    The camera is what the viewer looks through. It already exists in every scene — you access it via runtime.scene.camera.

    The most important camera properties:

    • position / rotation — where it is and what it looks at (set via transformComponent)
    • field of view — how wide the view is (like a camera lens)
    • near / far clip planes — objects closer than near or farther than far are not rendered

    In practice you rarely set camera properties directly. Instead you use a camera controller such as OrbitingCameraController, which handles mouse/touch input for you automatically.

    For camera controller setup, viewAll(), picking, and input event filters, see Manual — Interaction and navigation.


    Before you can create any entities, you need to initialize Cogs. The essential pattern is:

    import * as Cogs from "@kognifai/cogsengine";

    // 1. Create a Control bound to a <canvas> element
    const control = await Cogs.Control.create({
    parent: canvasElement,
    fetchHandler: fetchHandler,
    onInitialized: () => initScene(),
    });

    // 2. Access the runtime (scene management, entity factories, resources)
    const runtime = control.runtime;

    // 3. Your scene setup goes here
    const cube = runtime.Cube.create();

    // 4. When unmounting, dispose everything
    control.release();

    The fetchHandler is a simple function that the engine uses to load its own internal assets. See Manual — Initializing for the full fetchHandler API, or the Angular based example below for ready-to-use integration boilerplate.


    import { vec3, quat } from "gl-matrix";

    const cube = runtime.Cube.create("MyCube");

    cube.transformComponent.position = vec3.fromValues(3, 1, 0);
    cube.transformComponent.scale = vec3.fromValues(2, 2, 2);

    const rotation = quat.create();
    quat.fromEuler(rotation, 0, 45, 0); // pitch, yaw, roll in degrees
    cube.transformComponent.rotation = rotation;

    runtime.scene.viewAll();

    For all field types including matrices, quaternions, and array fields, see Manual — Working with fields.


    Flat colour:

    cube.materialComponent.diffuseColor = vec4.fromValues(0.2, 0.6, 1.0, 1.0); // blue
    

    Image texture:

    const texture = runtime.resources.loadTextureViaCogs("https://example.com/wood.jpg");
    cube.materialComponent.diffuseMap = texture;
    texture.release(); // release your handle; the texture stays alive while used by the entity

    PBR material:

    const material = runtime.resources.loadMaterial("StandardMaterial.material");
    const instance = runtime.resources.loadMaterialInstance(material);

    instance.setProperty("albedo", vec4.fromValues(1, 0.71, 0.29, 1)); // gold
    instance.setProperty("roughness", 0.1);
    instance.setProperty("metallic", 1.0);

    sphere.meshRenderComponent.material = instance;
    instance.release();

    See Manual — Materials for the full API including transparency, blending, and sharing instances across entities.


    GLB is the binary form of glTF — the most widely supported open 3D format. You can export GLB from Blender, 3ds Max, Maya, and many other tools.

    const model = runtime.ModelEntity.create("MyModel");
    model.modelComponent.model = runtime.resources.loadModel("https://example.com/mymodel.glb");
    model.transformComponent.position = vec3.fromValues(0, 0, 0);
    runtime.scene.viewAll();

    // Cleanup
    runtime.destroy(model);

    Loading is asynchronous — the entity appears immediately, geometry renders once the file has downloaded. You do not need to await anything.

    See Manual — Resources for resource lifecycle, handle ownership, and async loading patterns.


    const light = runtime.Light.create("MyLight");
    light.lightComponent.lightType = Cogs.LightType.Point;
    light.lightComponent.intensity = 100; // candela
    light.lightComponent.range = 20;
    light.lightComponent.lightColor = vec4.fromValues(1, 0.95, 0.8, 1); // warm white
    light.transformComponent.position = vec3.fromValues(0, 5, 5);

    Directional light (sun-like):

    const sun = runtime.Light.create("Sun");
    sun.lightComponent.lightType = Cogs.LightType.Directional;
    sun.lightComponent.intensity = 1.0;
    const dir = quat.create();
    quat.fromEuler(dir, -45, 30, 0);
    sun.transformComponent.rotation = dir;

    See Manual — Lighting and materials for intensity units, light types, and the default headlight.


    const camera = runtime.scene.camera;
    let cameraController = camera.getComponent(runtime.OrbitingCameraController);
    if (!cameraController) {
    cameraController = runtime.OrbitingCameraController.create();
    camera.components.add(cameraController);
    }

    cameraController.cameraTarget = dvec3.fromValues(0, 0, 0);
    cameraController.distance = 20;
    cameraController.horizontalAngle = 0;
    cameraController.verticalAngle = Math.PI / 2;
    cameraController.maxDistance = 10000;

    runtime.scene.viewAll();

    // Focus on a specific entity
    const bb = runtime.scene.getBoundingBoxWorld(myEntity);
    Cogs.CameraUtils.viewAllCamera(runtime.scene.camera, bb, [0, 0]);

    // Cleanup
    camera.components.remove(cameraController);
    runtime.destroy(cameraController);

    See Manual — Interaction and navigation for picking, input event filters, and camera properties.


    const parent = runtime.Cube.create("Parent");
    const child = runtime.Sphere.create("Child");

    child.transformComponent.position = vec3.fromValues(0, 0, 2); // 2 units in front of parent
    parent.sceneComponent.children.add(child);

    // Moving the parent moves the child too
    parent.transformComponent.position = vec3.fromValues(5, 0, 0);
    // child is now at world position [5, 0, 2]

    parent.sceneComponent.visible = false; // hides the whole group

    See Manual — Entities and Components for entity lifetime and ownership rules.


    Cogs holds GPU resourcesthat are not garbage-collected automatically. Always release resources and destroy entities when a view is unmounted.

    runtime.destroy(entity);     // removes from scene
    texture.release(); // release resource handle
    materialInstance.release();
    control.release(); // shut down the engine when unmounting

    See Manual — Resource leaks for leak detection patterns and ownership rules.



    You need Node.js (LTS recommended).

    cd examples
    npm install
    npm run start

    This launches live-server on port 9876. Open http://localhost:9876 in your browser to see the example gallery.

    Each example entry has a title. To find its source, open examples/index.html, locate the title, and note the entry string (e.g. entry: "basicStandardMaterialExample"). Search for that function name in examples/js/Examples/ — that file is the example's source.

    Range Topic
    0001–0010 Initialization, entities, transforms, visibility, parenting, LOD
    0015–0028 Meshes, blending, custom points, draw order
    0040–0041 Lines
    0050–0053 Input, picking, multi-draw
    0060–0074 Cameras, world-to-screen, shadows, ambient occlusion
    0098–0108 Textures (KTX2), billboards, axis cube, extrusion
    0110–0121 Ocean, terrain, sky, video, marker sets, badge sets
    0131–0132 Procedural sky, Potree point clouds
    0200–0210 Model loading (GLB, glTF, Cogs model, asset hierarchies)
    0280–0299 Height maps, tile layers, overlays, tracks
    0310–0360 Oil & gas (casing, drilling, well logs, radial logs, 360° images)
    0500–0505 Reservoir, physics, curtain view, multiphase flow, sea currents, vector field
    1000–1108 Custom components, OGC 3D Tiles, twin visuals, highlight regions
    1338–1351 Debug/visualisation (normals, draw calls, depth, depth-of-field, OIT)

    A few good example files to start with:

    • 0002_EntityExample.js — creating and destroying entities
    • 0003_TransformExample.js — position, rotation, scale
    • 0008_LightExample.js — point lights
    • 0024_BasicStandardMaterialExample.js — PBR materials
    • 0063_OrbitingCameraControllerExample.js — camera navigation
    • 0205_GLBExample.js — loading GLB models

    When playing with examples you may want to add or symlink large custom datasets in the examples folder. In that case you can try live-server's --watch=js to only watch source code changes. A better alternative may be to serve them on a different port, but then adding live-server's --cors is usually needed.


    Here we'll translate into practice all the high-level steps outlined in the introduction, using Cogs.js in the form of a TypeScript module.

    You don't need to learn Angular just to follow this, but of course it is worth investing in learning the framework that you'll use to build your application.

    This guide shows creating an Angular app displaying a Cube from scratch with 3D navigation to rotate and zoom the camera around the cube.

    Cogs.js provides TypeScript Type Declarations for ease of use when developing TypeScript code.

    import * as Cogs from '@kognifai/cogsengine';
    import { dvec3 } from '@kognifai/cogsengine';
    import { vec3, quat } from 'gl-matrix';

    dvec3 is a double precision version of gl-matrix vec3. Imported specially to make it more like gl-matrix objects.

    Some Common classes are:

        // The main Cogs.js GUI control containing graphics.
    class Cogs.Control;
    // Runtime class where Entities are created (= control.runtime).
    class Cogs.Runtime;
    // Functionality for the 3D scene (= runtime.scene or control.scene).
    class Cogs.Scene;
    // Base class for all Cogs Entities. Camera/Cube/...
    class Cogs.Entity;
    // Base class for all Cogs Components.
    class Cogs.Component;

    // Class for resource handling Textures, Models, .
    class Cogs.Resources;

    This file can act as a quick guide to Cogs.js. Note that some of the definitions are a bit unusual for TypeScript code, but required in that context.

    The type definitions can be found in the Path: node_modules/@kognifai/cogsengine/dist/cogs.esm.d.ts in your application.

    • install node.js (typically latest LTS) from nodejs.org which includes Node Package Manager
    • open a console (cmd)
    • npm install -g @angular/cli (Don't need Angular routing, Select CSS style)
    • ng new --skip-git first-app (where you want it)
    • cd first-app
    • ng serve --open
    • check that you see a welcome page for angular
    • press ctrl-c in the console to exit the development server

    This setup shows typical steps for how to add Cogs to an Angular application. Access right file, Packages required to run Cogs, Angular.json config to load Cogs and a very simple Cogs window showing a cube.

    Steps to add Cogs and Angular to your project:

    Required to allow installing KDI packages. See Adding Cogs to your project in Cogs.js Readme.md. Can use an existing copy from Cogs or KDI DigitalTwin.

    npm install @kognifai/cogsengine
    npm install gl-matrix

    Required to make Cogs.js resource files and the WebAssembly binary available to Cogs.

    Find the "assets" section in angular.json and replace it with:

                "assets": [
    "src/favicon.ico",
    "src/assets",
    {
    "glob": "**/*",
    "input": "node_modules/@kognifai/cogsengine/dist/",
    "output": "node_modules/@kognifai/cogsengine/dist/"
    }
    ],

    Put the following in src/app/app.component.css for fixes size canvas. Apply more elaborate layouts for own applications.

    canvas {
    width: 700px;
    height: 600px;
    margin: 20px;
    }

    Replace src/app/app.component.html with:

    <header style="text-align:center">
    <h3>{{ title }}</h3>
    </header>
    <div #myparent class="cogsparent"></div>

    Replace src/app/app.component.ts with the following example code:

    import { Component, ElementRef, DoCheck, ViewChild, OnDestroy, AfterViewInit } from '@angular/core';
    import * as Cogs from '@kognifai/cogsengine';
    import { dvec3 } from '@kognifai/cogsengine';
    import { vec3 } from 'gl-matrix';

    @Component({
    selector: 'app-root',
    standalone: true,
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    })
    export class AppComponent implements AfterViewInit, DoCheck, OnDestroy {
    public title = 'Hello world Cogs!';
    private _cogsControl: Cogs.Control | undefined;

    private cogsReady = false;
    private width = 0;
    private height = 0;

    // Used by Cogs FetchHandler
    private cancellableFetches = new Map<number, XMLHttpRequest>();

    /**
    * View child of app component. Link to HTML def in 'app.component.html'
    */
    @ViewChild('myparent')
    private myparent: ElementRef | undefined;

    /** Gets parent HTML element. Avoids testing undefined. */
    private get parent(): ElementRef {
    return this.myparent!;
    }

    /** Gets the created Cogs Control class. Avoids testing undefined. */
    private get cogsControl() {
    return this._cogsControl!;
    }

    initScene(): void {
    console.log('APP initScene');
    this.initializeNavigation();
    this.cogsControl.runtime.Cube.create();
    this.cogsReady = true;
    }

    /**
    * Cogs does by default not provide any 3D navigation.
    * A simple 3D navigation is included as a Cogs component.
    * More complex application may provide its own navigation.
    * @returns navigation component.
    */
    initializeNavigation(): Cogs.OrbitingCameraController {
    const runtime = this.cogsControl.runtime;
    const camera = runtime.scene.camera;

    // Ensure no existing controller component found.
    // Can normally just create and add controller as next step below.
    let cameraController = camera.getComponent(runtime.OrbitingCameraController);
    if (!cameraController) {
    cameraController = runtime.OrbitingCameraController.create();
    camera.components.add(cameraController);
    }

    cameraController.cameraTarget = dvec3.fromValues(0, 0, 0);
    cameraController.distance = 20;
    cameraController.horizontalAngle = 0;
    cameraController.verticalAngle = Math.PI / 2;
    cameraController.maxDistance = 10000;

    // Scene origin should be set near the centre of the scene.
    // Important for large offsets like UTM coordinates.
    runtime.scene.origin = dvec3.fromValues(0, 0, 0);

    return cameraController;
    }

    /**
    * Called first to initialize Cogs and set to the scene.
    */
    async ngAfterViewInit(): Promise<void> {
    const dataFetchHandler = this.createFetchHandler(this, true);

    this._cogsControl = await Cogs.Control.create({
    extensions: [],
    variant: 'sdk',
    parent: this.parent.nativeElement,
    fetchHandler: dataFetchHandler,
    onInitialized: () => this.initScene(),
    print: function (text) {
    console.log('print', text);
    },
    });
    this.cogsControl.domElement.oncontextmenu = function (e: any) {
    e.preventDefault();
    };
    }

    // Optional cleanup.
    ngOnDestroy(): void {
    this.cogsControl.runtime.clear();
    this.cogsControl.domElement.remove();
    }

    ngDoCheck(): void {
    if (
    this.cogsReady &&
    (this.width !== this.parent.nativeElement.offsetWidth || this.height !== this.parent.nativeElement.offsetHeight)
    ) {
    this.width = this.parent.nativeElement.offsetWidth;
    this.height = this.parent.nativeElement.offsetHeight;
    console.log('width, height', this.width, this.height);
    this.sizeChanged(this.width, this.height);
    }
    }

    sizeChanged(width: number, height: number): void {
    this.cogsControl.domElement.style.width = width + '';
    this.cogsControl.domElement.style.height = height + '';
    this.cogsControl.runtime.resize(width, height);
    }

    /**
    * Creates FetchHandler with request cancellation for Cogs requests
    * @param owner - Angular Application
    * @param logging - TRUE if logging the data requests.
    * @returns Returns FetchHandler to be passed to Cogs Control.create
    */
    private createFetchHandler(owner: AppComponent, logging: boolean): Cogs.IFetchHandler {
    const fetcher: Cogs.IFetchHandler = {
    fetch: function (url: string, offset: number, size: number, handler: Cogs.FetchResponseHandler, fetchId: number): boolean {
    if (logging) {
    cogsPrint(`[Debug] Test Application - fetchHandler.fetcher(${url}, ${fetchId} (${offset}, ${size}))`);
    }
    const xhr = new XMLHttpRequest();
    if (typeof fetchId === 'number') {
    owner.cancellableFetches.set(fetchId, xhr);
    }
    xhr.responseType = 'arraybuffer';
    xhr.onloadend = function () {
    owner.cancellableFetches.delete(fetchId);
    handler(xhr.status === 200 || xhr.status === 206 ? xhr.response : undefined, xhr.status);
    };
    xhr.open('GET', url);
    if (0 < size) {
    const len = offset + Math.max(1, size) - 1;
    const range = `bytes=${offset}-${len}`;
    xhr.setRequestHeader('Range', range);
    }
    xhr.send();
    return true;
    },
    cancel: function (fetchId: number): void {
    if (logging) {
    cogsPrint(`[Info] Test Application - fetchHandler.cancel(${fetchId})`);
    }
    const xhr = owner.cancellableFetches.get(fetchId);
    if (xhr) {
    xhr.abort();
    }
    },
    };

    return fetcher;
    }
    }

    // Cogs Logging Levels= Trace=0, Debug=1, Info=2, Warning=3, Error=4,Fatal=5
    const Category = {
    Trace: 0,
    Debug: 1,
    Info: 2,
    Warning: 3,
    Error: 4,
    Fatal: 5,
    };

    /** Logging level for Tests: 0= Trace+All */
    let logLevel = Category.Trace;

    /**
    * Cogs Logging. Cogs Log entries are of type: [Trace/Debug/Info/Warning/Error/Fatal][module] text
    * Default is skip Debug/Info me
    */
    export function cogsPrint(text: string): void {
    if (text.startsWith('[Trace]')) {
    if (logLevel <= Category.Trace) {
    console.trace(text);
    }
    } else if (text.startsWith('[Debug]')) {
    if (logLevel <= Category.Debug) {
    console.debug(text);
    }
    } else if (text.startsWith('[Info')) {
    if (logLevel <= Category.Info) {
    console.info(text);
    }
    } else if (text.startsWith('[Warn')) {
    if (logLevel <= Category.Warning) {
    console.warn(text);
    }
    } else if (text.startsWith('[Error') || text.startsWith('[Fatal')) {
    console.error(text);
    } else {
    console.log('[Unknown] ' + text);
    }
    }

    The cogsPrint and createFetchHandler functions can typically be reused as a first step.

    Run npm start (defined as "ng serve" in package.json)

    Open link to web-page in browser shown when starting the angular server.


    Document When to read it
    Manual Coordinate systems, picking, precision, resource lifecycle, WebXR