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,yAxisandzAxis.A model applies its material recursively at the root and requires
uniqueMaterialto 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.