TypeScript Client

Besides the Python and Rust clients, which add and update objects on the server, the browser-side TypeScript package @voraus/voraus-3d-visu lets a parent web application apply visualization instructions directly to an embedded visualization <iframe>.

The package is framework-agnostic (React, Vue, plain HTML, …) and fully type hinted. It exposes the same visualization instructions as the other clients, so there is no separate instruction set to learn.

Unlike the Python and Rust clients, it is not a server or network client: it opens no connection to the backend and makes no requests. It only sends instructions to the embedded <iframe> via postMessage.

Important

Instructions applied through this client affect the local browser scene of the embedding page only. They are never forwarded to the server, never written to any shared instruction state, and never distributed to other browser clients. Two browser windows can therefore show different local states independently.

The client communicates with the <iframe> through the browser postMessage API, but this transport is fully abstracted away by the package.

Installation

The package is published to the voraus Artifactory npm registry. Point the @voraus scope at that registry once (this writes the setting to a project-local .npmrc):

npm config set "@voraus:registry=https://voraus.jfrog.io/artifactory/api/npm/npm/" --location=project

Then install it like any other dependency:

npm install @voraus/voraus-3d-visu

Usage

Import the entry points you need and connect to the embedded <iframe>. The parent application embeds the iframe itself; a concrete targetOrigin is required and "*" is rejected:

import { connect, material, object } from "@voraus/voraus-3d-visu";
const visu = connect(iframe, { targetOrigin: "https://visu.example.com" });

An object reference addresses an object in the scene by its identifier. It neither creates nor fetches anything; it only builds instructions, which apply merges and sends to the local scene:

const box = object("box");

The snippets below together cover every instruction the client supports.

Transforms

Every object reference can be translated, rotated (as Euler angles or a quaternion) and scaled, either per component or all at once:

visu.apply(
  box.position.xyz(1, 2, 3),
  box.rotation.y(1.57),
  box.quaternion.xyzw(0, 0, 0, 1),
  box.scale.xyz(2, 2, 2),
);

Visibility and hierarchy

Objects can be shown or hidden, attached under another object, and addressed through their nested children:

visu.apply(
  box.visible(true),
  object("gripper").parent(box),
  box.child("wheel").position.x(0.5),
);

Materials

Material instructions target either an object’s own material or a shared material referenced by name. What is available depends on the object type, mirroring the Python and Rust clients:

  • Transparency exists only where the underlying material supports it — geometry objects, lines, point clouds, text panels, models and shared materials. A plain object’s material has none.

  • Recursion: text panels, axes helpers and root models apply their material to all descending children; a regular object’s material does not.

visu.apply(box.material.color.rgb(1, 0, 0), box.material.depthTest(true));
visu.apply(
  material("glass").color.rgb(0, 1, 0),
  material("glass").transparency(0.5),
);

Typed objects

Lines, text panels and point clouds add their own instructions on top of the common object API. Segmented lines require an even number of points:

visu.apply(
  line("trajectory", { segments: true }).points([
    [0, 0, 0],
    [1, 1, 1],
  ]),
  pointCloud("scan").data(new Uint8Array([1, 2, 3])),
);

const label = textPanel("label");
visu.apply(
  label.text("Hello"),
  label.font.visible(true),
  label.background.material.color.rgb(0, 0, 0),
);

Geometry objects (boxes, spheres, cylinders), cameras, axes helpers and models all build on the common object API, with a few specifics:

  • Geometry objects and models expose a transparency-capable material.

  • An axes helper exposes its individual xAxis, yAxis and zAxis.

  • A model applies its material recursively at the root and requires uniqueMaterial to be set before its material can be accessed.

visu.apply(
  sphere("ball").material.transparency(0.5),
  cylinder("pipe").scale.xyz(1, 2, 1),
  camera("cam").position.xyz(0, 0, 5),
);

const gizmo = axes("gizmo");
visu.apply(gizmo.material.color.rgb(1, 1, 1), gizmo.xAxis.visible(true));

const robot = model("robot", { uniqueMaterial: true });
visu.apply(
  robot.material.transparency(0.2),
  robot.child("arm").visible(true),
);

Origin allowlist

For security, the interface is disabled by default. The visualization only applies a message when event.source is the parent window and event.origin is contained in the configured allowlist. Configure it on the server with the V3DVISU_POST_MESSAGE_ALLOWED_ORIGINS environment variable (JSON array of origins):

V3DVISU_POST_MESSAGE_ALLOWED_ORIGINS='["https://app.example.com", "https://admin.example.com"]'

Invalid messages (unknown type, malformed payload, foreign origin, or foreign event.source) are ignored and never modify the scene. No dynamic code execution is performed.

Readiness handshake

The visualization loads its configuration asynchronously, so its postMessage receiver is not attached immediately. Any message a parent sends before that point is lost, and on every (re)load the scene resets to the server defaults. To avoid dropped updates, the visualization emits a one-time readiness signal once its receiver is attached:

{ "type": "v3dvisu:ready" }

It is posted to every configured allowed origin (the parent’s real origin is not yet known); the browser drops the ones whose targetOrigin does not match the actual parent. A parent should listen for this message and (re)send its current local state upon receiving it. The v3dvisu:ready message is sent exactly once per load, not on subsequent updates. The ReadyMessage type is exported from the client package for typing the parent-side handler.