This document describes the input data format accepted by three-cad-viewer. The viewer
expects a single hierarchical Shapes object that represents a CAD model as a tree of
groups and parts, each carrying tessellated geometry, appearance, and transformation data.
The data is a recursive tree. Every node is a Shapes object. Each node is either a
group (has parts) or a leaf (has shape), never both. A group's parts array
freely mixes leaves and nested groups at the same level:
hexapod (group)
+-- parts[]
+-- bottom (leaf -- has shape)
+-- top (leaf -- has shape)
+-- front_stand (leaf -- has shape)
+-- left_front_leg (group -- has parts)
| +-- parts[]
| +-- upper_leg (leaf -- has shape)
| +-- lower_leg (group -- has parts)
| +-- parts[]
| +-- lower_leg (leaf -- has shape)
+-- right_front_leg (group -- has parts)
| +-- parts[]
| +-- ...
...
The top-level object and every node in the tree share the same Shapes interface.
| Field | Type | Description |
|---|---|---|
version |
number |
Protocol version. Must be 2 or 3. |
name |
string |
Display name shown in the navigation tree. |
id |
string |
Unique slash-separated path, e.g. "/Group/Part". |
| Field | Type | Description |
|---|---|---|
parts |
Shapes[] |
Child nodes (mix of leaves and groups). Present on group nodes. |
shape |
Shape |
Tessellated geometry. Present on leaf nodes. |
A node has either parts (group) or shape (leaf), never both.
| Field | Type | Description |
|---|---|---|
loc |
[[x, y, z], [qx, qy, qz, qw]] |
Position as a 3D vector and orientation as a quaternion. Applied hierarchically from root to leaf. Set to null or omit for identity. |
Example:
"loc": [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0]]| Field | Type | Description |
|---|---|---|
bb |
BoundingBoxFlat | null |
Axis-aligned bounding box of the entire model. Typically set on the root node only. |
"bb": {"xmin": -0.5, "xmax": 0.5, "ymin": -0.5, "ymax": 0.5, "zmin": -0.5, "zmax": 0.5}| Field | Type | Default | Description |
|---|---|---|---|
color |
string | string[] |
- | CSS hex color ("#e8b024") or array of hex colors for multi-colored edges. |
alpha |
number |
1.0 |
Opacity, 0 (transparent) to 1 (opaque). |
renderback |
boolean |
false |
Whether to render the back face of triangles. |
texture |
Texture | null |
null |
Optional encoded texture (see Texture). |
material |
string |
- | Optional tag for Studio mode material lookup. References a key in the root-level materials table or a builtin preset name (e.g. "stainless-steel"). Ignored in CAD mode. |
| Field | Type | Description |
|---|---|---|
state |
[VisibilityValue, VisibilityValue] |
Initial visibility as [faces, edges]. |
VisibilityValue is one of:
| Value | Meaning |
|---|---|
0 |
Hidden |
1 |
Shown |
2 |
Mixed (some children shown, some hidden) |
3 |
Not applicable (e.g. edges on a vertex-only object) |
Common combinations:
[1, 1]-- faces and edges both visible (typical for solids)[3, 1]-- no faces, edges visible (edge-only or vertex-only objects)[1, 3]-- faces visible, no edges (face-only objects)
| Field | Type | Description |
|---|---|---|
type |
"shapes" | "edges" | "vertices" | "polygon" |
Kind of geometry this leaf carries. |
subtype |
"solid" | "faces" | "face" |
Distinguishes closed solids from open faces. Only meaningful when type is "shapes". |
| Field | Type | Description |
|---|---|---|
accuracy |
number | null |
Tessellation accuracy of the CAD kernel. |
normal_len |
number |
Length of normal helper vectors. 0 to hide. |
width |
number |
Edge line width in pixels (for "edges" type). |
size |
number |
Vertex point size in pixels (for "vertices" type). |
The shape field on a leaf node contains the actual tessellated mesh. There are three
geometry variants depending on the type of the leaf node.
Contains triangulated surface mesh plus edges and vertices:
| Field | Type | Description |
|---|---|---|
vertices |
number[] | Float32Array |
Flat array of 3D vertex positions: [x0, y0, z0, x1, y1, z1, ...]. |
normals |
number[] | number[][] | Float32Array |
Per-vertex normals, same length as vertices. Can be flat or nested per-face. |
triangles |
number[] | number[][] | Uint32Array |
Triangle indices into vertices. See Serialization Formats. |
edges |
number[] | number[][] | Float32Array |
Edge line segments as coordinate pairs. See Serialization Formats. |
obj_vertices |
number[] | Float32Array |
Original CAD topology vertices: [x0, y0, z0, ...]. Used for vertex display. |
face_types |
number[] | Uint32Array |
One integer per face classifying the OCP face type. |
edge_types |
number[] | Uint8Array | Uint32Array |
One integer per edge classifying the OCP edge type. |
triangles_per_face |
number[] | Uint32Array |
Required when triangles is flat. Number of triangles belonging to each face. Not needed when triangles is nested (number[][]). |
segments_per_edge |
number[] | Uint32Array |
Required when edges is flat. Number of line segments belonging to each edge. Not needed when edges is nested (number[][]). |
uvs |
number[] | Float32Array |
Optional per-vertex UV coordinates: [u0, v0, u1, v1, ...]. Same vertex count as vertices. Used for texture mapping in Studio mode. When absent, the viewer uses triplanar or box projection as fallback. |
Only the edges (and optionally obj_vertices) fields are populated. All other arrays
are empty.
Only the obj_vertices field is populated. All other arrays are empty.
All array fields accept plain number[] or TypedArrays (Float32Array, Uint32Array,
Uint8Array). The viewer converts plain arrays to TypedArrays internally for GPU
rendering.
The triangles, normals, and edges fields additionally accept nested arrays
(number[][]), where each inner array corresponds to one topological face or edge.
The viewer flattens these automatically.
All data is in flat arrays. The triangles_per_face and segments_per_edge
count arrays are required so the viewer knows which triangles belong to which face
and which segments belong to which edge.
shape: {
vertices: [x0,y0,z0, x1,y1,z1, ...],
normals: [nx0,ny0,nz0, nx1,ny1,nz1, ...],
triangles: [0, 1, 2, 2, 3, 0, 4, 5, 6, ...],
triangles_per_face: [2, 1, ...], // face 0 has 2 triangles, face 1 has 1, ...
edges: [x0,y0,z0, x1,y1,z1, ...],
segments_per_edge: [1, 3, ...], // edge 0 has 1 segment, edge 1 has 3, ...
obj_vertices: [x0, y0, z0, ...],
face_types: [0, 0, ...],
edge_types: [0, 0, ...],
}triangles, normals, and edges can alternatively be provided as arrays of
arrays, one inner array per topological face or edge. In this case
triangles_per_face and segments_per_edge are not needed because the grouping is
implicit in the nesting.
shape: {
vertices: [x0, y0, z0, x1, y1, z1, ...], // always flat
normals: [[nx, ny, nz, ...], [...]], // nested per face
triangles: [[0, 1, 2, 2, 3, 0], [4, 5, 6, ...]], // nested per face
edges: [[x0,y0,z0, x1,y1,z1], [...]], // nested per edge
obj_vertices: [x0, y0, z0, ...], // always flat
face_types: [0, 0, ...],
edge_types: [0, 0, ...],
}Given triangles_per_face = [2, 3]:
- Face 0 owns the first
2 * 3 = 6indices intriangles(2 triangles, 3 indices each). - Face 1 owns the next
3 * 3 = 9indices (3 triangles).
Given segments_per_edge = [1, 4]:
- Edge 0 owns the first
1 * 6 = 6floats inedges(1 segment = 2 endpoints * 3 coords). - Edge 1 owns the next
4 * 6 = 24floats (4 segments).
An optional encoded image that is mapped onto a face.
{
"height": 256,
"width": 256,
"image": {
"data": "<base64-encoded image data>",
"format": "png"
}
}For GDSII semiconductor layouts, the viewer supports an alternative geometry representation using extruded 2D polygons instead of tessellated meshes.
Set on the root Shapes node:
| Field | Type | Description |
|---|---|---|
format |
"GDS" |
Enables polygon rendering mode. |
instances |
Record<string, number[]> | number[][] |
Shared polygon vertex data. Keys (or indices) are referenced by leaf nodes. Each value is a flat array of 2D coordinates: [x0, y0, x1, y1, ...]. |
Leaf nodes with type: "polygon" use a PolygonShape instead of a Shape:
| Field | Type | Description |
|---|---|---|
refs |
number[] |
Indices into the root-level instances table. |
height |
number |
Extrusion height for the 2D polygon. |
matrices |
number[] |
Optional affine transformation matrices (6 values per matrix: [a, b, c, d, tx, ty, ...]). When empty, the identity transform is used. |
The polygon vertices from instances[ref] are transformed by the matrix, converted
to THREE.Shape objects, and extruded to height to produce 3D geometry.
A unit cube centered at the origin:
{
version: 3,
name: "Group",
id: "/Group",
loc: [[0, 0, 0], [0, 0, 0, 1]],
normal_len: 0,
bb: {xmin: -0.5, xmax: 0.5, ymin: -0.5, ymax: 0.5, zmin: -0.5, zmax: 0.5},
parts: [
{
version: 3,
id: "/Group/Box",
name: "Box",
type: "shapes",
subtype: "solid",
state: [1, 1],
color: "#e8b024",
alpha: 1.0,
renderback: false,
texture: null,
accuracy: null,
bb: null,
loc: [[0, 0, 0], [0, 0, 0, 1]],
shape: {
vertices: [
// 24 vertices (4 per face, 6 faces) as flat [x, y, z, ...]:
-0.5,-0.5,-0.5, -0.5,-0.5,0.5, -0.5,0.5,-0.5, -0.5,0.5,0.5,
0.5,-0.5,-0.5, 0.5,-0.5,0.5, 0.5,0.5,-0.5, 0.5,0.5,0.5,
-0.5,-0.5,-0.5, 0.5,-0.5,-0.5, -0.5,-0.5,0.5, 0.5,-0.5,0.5,
-0.5,0.5,-0.5, 0.5,0.5,-0.5, -0.5,0.5,0.5, 0.5,0.5,0.5,
-0.5,-0.5,-0.5, 0.5,-0.5,0.5, -0.5,-0.5,0.5, 0.5,-0.5,-0.5,
-0.5,0.5,-0.5, 0.5,0.5,0.5, -0.5,0.5,0.5, 0.5,0.5,-0.5,
],
normals: [
-1,0,0, -1,0,0, -1,0,0, -1,0,0,
1,0,0, 1,0,0, 1,0,0, 1,0,0,
0,-1,0, 0,-1,0, 0,-1,0, 0,-1,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0,
0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1,
0,0,1, 0,0,1, 0,0,1, 0,0,1,
],
triangles: [
1,2,0, 1,3,2, // face 0: 2 triangles
5,4,6, 5,6,7, // face 1: 2 triangles
11,8,9, 11,10,8, // face 2: 2 triangles
15,13,12, 15,12,14, // face 3: 2 triangles
19,16,17, 19,18,16, // face 4: 2 triangles
23,21,20, 23,20,22, // face 5: 2 triangles
],
triangles_per_face: [2, 2, 2, 2, 2, 2],
edges: [
-0.5,-0.5,-0.5, -0.5,-0.5,0.5, // edge 0
-0.5,-0.5,0.5, -0.5,0.5,0.5, // edge 1
-0.5,0.5,-0.5, -0.5,0.5,0.5, // edge 2
-0.5,-0.5,-0.5, -0.5,0.5,-0.5, // edge 3
0.5,-0.5,-0.5, 0.5,-0.5,0.5, // edge 4
0.5,-0.5,0.5, 0.5,0.5,0.5, // edge 5
0.5,0.5,-0.5, 0.5,0.5,0.5, // edge 6
0.5,-0.5,-0.5, 0.5,0.5,-0.5, // edge 7
-0.5,-0.5,-0.5, 0.5,-0.5,-0.5, // edge 8
-0.5,-0.5,0.5, 0.5,-0.5,0.5, // edge 9
-0.5,0.5,-0.5, 0.5,0.5,-0.5, // edge 10
-0.5,0.5,0.5, 0.5,0.5,0.5, // edge 11
],
segments_per_edge: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
obj_vertices: [
-0.5,-0.5,0.5, -0.5,-0.5,-0.5, -0.5,0.5,0.5, -0.5,0.5,-0.5,
0.5,-0.5,0.5, 0.5,-0.5,-0.5, 0.5,0.5,0.5, 0.5,0.5,-0.5,
],
face_types: [0, 0, 0, 0, 0, 0],
edge_types: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
},
},
],
}The same unit cube, encoded in the instanced buffer format. The geometry is stored
once in instances[0] as base64-encoded buffers, and the leaf references it via
{ ref: 0 }:
{
instances: [
{
// Instance 0: unit cube geometry (same data as above, base64-encoded)
vertices: { shape: [24, 3], dtype: "float32",
buffer: "AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAL8AAAC/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAC/",
codec: "b64" },
normals: { shape: [24, 3], dtype: "float32",
buffer: "AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/",
codec: "b64" },
triangles: { shape: [12, 3], dtype: "uint32",
buffer: "AQAAAAIAAAAAAAAAAQAAAAMAAAACAAAABQAAAAQAAAAGAAAABQAAAAYAAAAHAAAACwAAAAgAAAAJAAAACwAAAAoAAAAIAAAADwAAAA0AAAAMAAAADwAAAAwAAAAOAAAAEwAAABAAAAARAAAAEwAAABIAAAAQAAAAFwAAABUAAAAUAAAAFwAAABQAAAAWAAAA",
codec: "b64" },
edges: { shape: [24, 3], dtype: "float32",
buffer: "AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/",
codec: "b64" },
obj_vertices: { shape: [8, 3], dtype: "float32",
buffer: "AAAAvwAAAL8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAC/",
codec: "b64" },
face_types: { shape: [6], dtype: "uint32",
buffer: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
codec: "b64" },
edge_types: { shape: [12], dtype: "uint32",
buffer: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
codec: "b64" },
triangles_per_face:{ shape: [6], dtype: "uint32",
buffer: "AgAAAAIAAAACAAAAAgAAAAIAAAACAAAA",
codec: "b64" },
segments_per_edge: { shape: [12], dtype: "uint32",
buffer: "AQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAA",
codec: "b64" },
},
],
shapes: {
version: 3,
name: "Group",
id: "/Group",
loc: [[0, 0, 0], [0, 0, 0, 1]],
normal_len: 0,
bb: {xmin: -0.5, xmax: 0.5, ymin: -0.5, ymax: 0.5, zmin: -0.5, zmax: 0.5},
parts: [
{
version: 3,
id: "/Group/Box",
name: "Box",
type: "shapes",
subtype: "solid",
state: [1, 1],
color: "#e8b024",
alpha: 1.0,
renderback: false,
texture: null,
accuracy: null,
bb: null,
loc: [[0, 0, 0], [0, 0, 0, 1]],
shape: { ref: 0 }, // references instances[0]
},
],
},
}Multi-part models use nested parts arrays. Each group can carry its own loc
transform, which is applied on top of its parent's transform.
{
version: 3,
name: "assembly",
id: "/assembly",
loc: [[0, 0, 0], [0, 0, 0, 1]],
bb: {xmin: -10, xmax: 10, ymin: -10, ymax: 10, zmin: -10, zmax: 10},
parts: [
{
// A leaf part
version: 3,
id: "/assembly/box",
name: "box",
type: "shapes",
subtype: "solid",
state: [1, 1],
color: "#ff0000",
alpha: 1.0,
loc: [[3, 3, 3], [0, 0, 0, 1]],
shape: { /* ... */ },
},
{
// A nested sub-group
version: 3,
name: "sub-assembly",
id: "/assembly/sub-assembly",
loc: [[-3, 0, 0], [0, 0, 0, 1]],
parts: [
{
version: 3,
id: "/assembly/sub-assembly/cone",
name: "cone",
type: "shapes",
subtype: "solid",
state: [1, 1],
color: "#00ff00",
loc: [[0, 0, 0], [0, 0, 0, 1]],
shape: { /* ... */ },
},
],
},
],
}Objects that consist only of edges (wireframes, curves):
{
version: 3,
name: "Group",
id: "/Group",
loc: [[0, 0, 0], [0, 0, 0, 1]],
bb: { /* ... */ },
parts: [
{
id: "/Group/curves",
name: "curves",
type: "edges",
state: [3, 1],
color: "#ba55d3",
loc: [[0, 0, 0], [0, 0, 0, 1]],
width: 3,
shape: {
edges: [
// Each line segment is 6 floats: x0,y0,z0, x1,y1,z1
-5,8,-13, -3,10,-15,
5,8,13, 3,10,15,
],
segments_per_edge: [1, 1],
vertices: [],
normals: [],
triangles: [],
obj_vertices: [-5,8,-13, -3,10,-15, 5,8,13, 3,10,15],
edge_types: [0, 0],
face_types: [],
},
},
],
}Objects that consist only of points:
{
version: 3,
name: "Group",
id: "/Group",
loc: [[0, 0, 0], [0, 0, 0, 1]],
bb: { /* ... */ },
parts: [
{
id: "/Group/points",
name: "points",
type: "vertices",
state: [3, 1],
color: "#ba55d3",
loc: null,
size: 6,
shape: {
obj_vertices: [
-5, 8, 13,
-5, 5, 7,
5, 8, 4,
],
vertices: [],
normals: [],
triangles: [],
edges: [],
edge_types: [],
face_types: [],
},
},
],
}As an alternative to plain arrays or TypedArrays, any geometry field in a Shape
object can be provided as a base64-encoded buffer. This is the format used by
ocp-tessellate for efficient binary transfer (e.g. over Jupyter comms).
An encoded buffer has this structure:
{
shape: [dim1, dim2, ...], // array shape (informational, not used for decoding)
dtype: "float32", // "float32", "int32", or "uint32"
buffer: "AAAA...", // base64-encoded raw bytes (little-endian)
codec: "b64" // must be "b64"
}Any field that normally accepts number[] or Float32Array can instead be an
EncodedBuffer. The viewer decodes them to TypedArrays before rendering.
Example -- an edge-only object with encoded buffers:
{
id: "/Group/wire",
name: "wire",
type: "edges",
state: [3, 1],
color: "#ff0000",
shape: {
edges: { shape: [2, 6], dtype: "float32", buffer: "AAAA...", codec: "b64" },
segments_per_edge:{ shape: [2], dtype: "uint32", buffer: "AQAA...", codec: "b64" },
obj_vertices: { shape: [6, 3], dtype: "float32", buffer: "AAAA...", codec: "b64" },
vertices: [],
normals: [],
triangles: [],
edge_types: { shape: [2], dtype: "uint32", buffer: "AAAA...", codec: "b64" },
face_types: [],
},
}Encoded buffers can be mixed freely with plain arrays in the same Shape --
only fields that have the { buffer, dtype, codec } structure are decoded.
For models with repeated geometry (e.g. fasteners, connectors), the data can use
an instanced format that deduplicates shared shapes. Instead of embedding the
full Shape on every leaf, shared geometry is stored once in a top-level
instances array, and leaves reference it by index.
The instanced format wraps the standard Shapes tree:
{
instances: [
// Instance 0: a complete Shape with all fields as encoded buffers
{
vertices: { shape: [...], dtype: "float32", buffer: "...", codec: "b64" },
triangles: { shape: [...], dtype: "uint32", buffer: "...", codec: "b64" },
normals: { shape: [...], dtype: "float32", buffer: "...", codec: "b64" },
edges: { shape: [...], dtype: "float32", buffer: "...", codec: "b64" },
obj_vertices: { shape: [...], dtype: "float32", buffer: "...", codec: "b64" },
face_types: { shape: [...], dtype: "uint32", buffer: "...", codec: "b64" },
edge_types: { shape: [...], dtype: "uint32", buffer: "...", codec: "b64" },
triangles_per_face:{ shape: [...], dtype: "uint32", buffer: "...", codec: "b64" },
segments_per_edge: { shape: [...], dtype: "uint32", buffer: "...", codec: "b64" },
uvs: { shape: [...], dtype: "float32", buffer: "...", codec: "b64" }, // optional
},
// Instance 1: ...
],
shapes: {
// Standard Shapes tree, but leaf nodes use { ref: N } instead of inline Shape
version: 3,
name: "Assembly",
id: "/Assembly",
bb: { /* ... */ },
parts: [
{
id: "/Assembly/Bolt1",
name: "Bolt1",
type: "shapes",
shape: { ref: 0 }, // references instances[0]
color: "#aaaaaa",
loc: [[10, 0, 0], [0, 0, 0, 1]],
// ...
},
{
id: "/Assembly/Bolt2",
name: "Bolt2",
type: "shapes",
shape: { ref: 0 }, // same geometry, different position
color: "#aaaaaa",
loc: [[20, 0, 0], [0, 0, 0, 1]],
// ...
},
],
}
}The viewer detects the instanced format by the presence of both instances and
shapes keys. It decodes all instance buffers from base64 to TypedArrays, then
walks the tree replacing { ref: N } with the decoded Shape. The result is a
standard Shapes tree identical to the non-instanced format.
Leaves that don't reference an instance (e.g. edge-only objects) can still embed their geometry directly using encoded buffers -- the viewer decodes those inline.
The viewer accepts configuration at three levels:
- Display options -- passed to
new Display(container, displayOptions)for UI layout - Render/Viewer options -- passed to
viewer.render(shapes, renderOptions, viewerOptions)for rendering and camera - Data-level configuration -- embedded in the
Shapesobject itself (materials, textures, studio settings)
This section documents all three levels.
Passed as the second argument to new Display(container, options). Controls UI layout and
tool visibility.
| Field | Type | Default | Description |
|---|---|---|---|
cadWidth |
number |
800 |
Width of CAD canvas in pixels. |
height |
number |
600 |
Height of CAD canvas in pixels. |
treeWidth |
number |
260 |
Width of tree navigation panel in pixels. |
treeHeight |
number |
400 |
Height of tree navigation panel in pixels. |
theme |
"light" | "dark" | "browser" |
"light" |
UI theme. "browser" follows system setting. |
pinning |
boolean |
false |
Enable pin-as-PNG button. |
glass |
boolean |
false |
Enable glass mode (compact overlay UI). |
tools |
boolean |
true |
Show/hide all toolbar tools. |
keymap |
Keymap |
See below | Custom keyboard shortcuts. |
newTreeBehavior |
boolean |
true |
Use new tree navigation behavior. |
measureTools |
boolean |
true |
Show measurement tools in toolbar. |
selectTool |
boolean |
true |
Show select tool in toolbar. |
explodeTool |
boolean |
true |
Show explode/animation tool in toolbar. |
zscaleTool |
boolean |
false |
Show z-scale tool in toolbar. |
zebraTool |
boolean |
true |
Show zebra tool in toolbar. |
studioTool |
boolean |
true |
Show Studio mode tool in toolbar. |
externalMeasurementBackend |
boolean |
false |
Use an external (Python/ocp_vscode) measurement backend. When false, the built-in TypeScript mesh-based backend computes measurements locally. |
canvas |
HTMLCanvasElement |
— | External canvas for shared WebGL context. |
gl |
WebGLRenderingContext |
— | External WebGL context (use with canvas). |
Passed as the second argument to viewer.render(shapes, renderOptions, viewerOptions).
Controls CAD mode material appearance and lighting.
| Field | Type | Default | Description |
|---|---|---|---|
edgeColor |
number |
0x707070 |
Default edge color (hex). |
ambientIntensity |
number |
1.0 |
Ambient light intensity. |
directIntensity |
number |
1.1 |
Directional light intensity. |
metalness |
number |
0.3 |
Default metalness factor (0--1). |
roughness |
number |
0.65 |
Default roughness factor (0--1). |
defaultOpacity |
number |
0.5 |
Opacity level when transparency is enabled. |
normalLen |
number |
0 |
Length of normal display vectors. 0 to hide. |
Passed as the third argument to viewer.render(shapes, renderOptions, viewerOptions).
Controls camera, grid, clipping, and controls.
| Field | Type | Default | Description |
|---|---|---|---|
control |
"orbit" | "trackball" |
"orbit" |
Camera control type. |
axes |
boolean |
false |
Show X/Y/Z axes. |
axes0 |
boolean |
false |
Show axes at origin instead of object center. |
grid |
[boolean, boolean, boolean] |
[false, false, false] |
Show grid planes [XY, XZ, YZ]. |
ortho |
boolean |
true |
Use orthographic camera (false = perspective). |
transparent |
boolean |
false |
Render object as transparent. |
blackEdges |
boolean |
false |
Render edges in black. |
collapse |
number |
0 |
Tree collapse level (0=collapsed, 1=root, 2=all, -1=smart). |
clipIntersection |
boolean |
false |
Use intersection clipping mode. |
clipPlaneHelpers |
boolean |
false |
Show clipping plane helpers. |
clipObjectColors |
boolean |
false |
Use object colors for clipping caps. |
clipNormal0 |
[number, number, number] |
[-1, 0, 0] |
Clipping plane 0 normal direction. |
clipNormal1 |
[number, number, number] |
[0, -1, 0] |
Clipping plane 1 normal direction. |
clipNormal2 |
[number, number, number] |
[0, 0, -1] |
Clipping plane 2 normal direction. |
clipSlider0 |
number |
-1 |
Clipping plane 0 slider position. |
clipSlider1 |
number |
-1 |
Clipping plane 1 slider position. |
clipSlider2 |
number |
-1 |
Clipping plane 2 slider position. |
holroyd |
boolean |
true |
Holroyd non-tumbling rotation for trackball. |
up |
"Z" | "Y" | "legacy" |
"Z" |
World up direction. |
ticks |
number |
10 |
Grid tick count hint. |
gridFontSize |
number |
10 |
Font size for grid labels. |
centerGrid |
boolean |
false |
Center grid on object instead of origin. |
position |
[number, number, number] | null |
null |
Camera position. |
quaternion |
[number, number, number, number] | null |
null |
Camera rotation quaternion [x, y, z, w]. |
target |
[number, number, number] | null |
null |
Camera look-at target. |
zoom |
number |
1.0 |
Camera zoom level. |
panSpeed |
number |
1.0 |
Pan speed multiplier. |
rotateSpeed |
number |
1.0 |
Rotation speed multiplier. |
zoomSpeed |
number |
1.0 |
Zoom speed multiplier. |
timeit |
boolean |
false |
Log render timings to console. |
zebraCount |
number |
9 |
Number of zebra stripes. |
zebraOpacity |
number |
1.0 |
Zebra stripe opacity (0--1). |
zebraDirection |
number |
0 |
Stripe direction (0--360 degrees). |
zebraColorScheme |
"blackwhite" | "colorful" | "grayscale" |
"blackwhite" |
Zebra color scheme. |
zebraMappingMode |
"reflection" | "normal" |
"reflection" |
Zebra mapping mode. |
studioEnvironment |
string |
"studio" |
Studio environment preset or custom HDR URL. See Environment Presets. |
studioEnvIntensity |
number |
1.0 |
Studio environment map intensity (0--3). |
studioBackground |
StudioBackground |
"environment" |
Studio background mode. |
studioToneMapping |
"neutral" | "ACES" | "none" |
"neutral" |
Studio tone mapping algorithm. |
studioExposure |
number |
1.0 |
Studio tone mapping exposure (0--2). |
studio4kEnvMaps |
boolean |
false |
Use 4K environment maps. |
studioTextureMapping |
"triplanar" | "parametric" |
"triplanar" |
Studio texture mapping mode. |
studioEnvRotation |
number |
0 |
Studio environment rotation (0--360 degrees). |
studioShadowIntensity |
number |
0.5 |
Studio shadow intensity (0--1). 0 = off. |
studioShadowSoftness |
number |
0.2 |
Studio shadow softness (0--1). |
studioAOIntensity |
number |
0.5 |
Studio ambient occlusion intensity (0--3). 0 = off. |
Conceptual split: Viewer Options describe the studio (lighting, backdrop, camera processing) — things independent of the objects being viewed. Shape data describes the objects (geometry, hierarchy, color, material) — physical properties of the parts.
The studioEnvironment field accepts these values:
| Value | UI Label | Description |
|---|---|---|
"studio" |
Procedural Studio | Built-in procedural studio (no network required). |
"studio_small_08" |
Soft Light | Soft light, neutral, backlight. |
"studio_small_03" |
High Contrast Studio | High-contrast, softbox + ceiling lamp. |
"white_studio_05" |
Bright Neutral | White, product, bright, neutral lighting. |
"white_studio_03" |
Clean Softbox | White, softbox, reflection, clean. |
"photo_studio_01" |
Spotlit Setup | Lighting setup, spotlights. |
"studio_small_09" |
Controlled Light | Product lighting, controlled, soft reflections. |
"cyclorama_hard_light" |
Hard Contrast Light | Cyclorama, hard light, contrast. |
"canary_wharf" |
Urban Overcast | Urban, city, overcast. |
"kiara_1_dawn" |
Outdoor Warm | Dawn, warm, nature, sunrise. |
"empty_warehouse_01" |
Neutral Industrial | Warehouse, neutral, big space. |
"san_giuseppe_bridge" |
San Giuseppe Bridge | Bridge, outdoor. |
"none" |
— | No environment map. |
| Custom URL | — | Any .hdr file URL (loaded via HDRLoader). |
These fields are set on the root Shapes node alongside parts, name, etc.
They configure which materials and textures are available for objects in Studio mode.
Note: Studio environment settings (lighting, background, shadows, AO, tone mapping) are not part of the shape data. They describe the physical studio, not the objects, and are configured via Viewer Options (
studioEnvironment,studioBackground, etc.).
A dictionary mapping material tag names to material definitions. Leaf nodes
reference entries by name via their material field.
materials: {
// Builtin preset (with optional overrides)
"chrome": { builtin: "chrome" },
"blue-acrylic": { builtin: "acrylic-clear", color: "#0000ff" },
// MaterialXMaterial format: full PBR definition with textures
"aluminum": {
properties: {
color: { value: [1.0, 1.0, 1.0], texture: "data:image/png;base64,..." },
roughness: { value: 0.35, texture: "data:image/png;base64,..." },
metalness: { value: 1.0 },
normal: { texture: "data:image/png;base64,..." },
},
textureRepeat: [0.25, 0.25],
},
}Value types:
| Value Form | Description |
|---|---|
MaterialAppearance object |
Builtin preset with optional overrides (detected by builtin key). See Material Appearance below. |
MaterialXMaterial object |
threejs-materials format (detected by properties key). See MaterialX Material below. |
31 presets organized by category:
| Category | Presets |
|---|---|
| Polished Metals | chrome, polished-steel, polished-aluminum, gold, copper, brass |
| Matte/Brushed Metals | stainless-steel, brushed-aluminum, cast-iron, titanium, galvanized |
| Plastics | plastic-glossy, plastic-matte, abs-black, nylon |
| Glass & Transparent | acrylic-clear, glass-clear, glass-tinted, glass-frosted |
| Rubber & Elastomers | rubber-black, rubber-gray, rubber-red |
| Painted Surfaces | paint-matte, paint-glossy, paint-metallic, car-paint |
| Natural & Other | ceramic-white, carbon-fiber, concrete |
The MaterialXMaterial format is produced by the threejs-materials Python library,
which catalogs PBR materials from GPUOpen, ambientCG, PolyHaven, and PhysicallyBased.
{
// Required: property dict
properties: {
color: { value: [0.8, 0.2, 0.1] }, // linear RGB
roughness: { value: 0.4, texture: "data:image/..." }, // scalar + texture
metalness: { value: 1.0 },
normal: { texture: "data:image/png;base64,..." }, // texture only
},
// Optional: texture tiling
textureRepeat: [0.25, 0.25],
}Detected by the presence of the properties key. Extra keys from threejs-materials
(id, name, source, url, license) pass through harmlessly.
| Field | Type | Default | Description |
|---|---|---|---|
properties |
Record<string, { value?: unknown; texture?: string }> |
required | Property dict. Keys are simplified names ("color", "roughness", "normal", etc.). Each entry has optional value (scalar or linear RGB array) and/or texture (data URI). |
textureRepeat |
[number, number] |
[1, 1] |
Texture tiling factor [u, v], applied to all textures. |
A builtin preset reference with optional property overrides.
Field names follow Three.js MeshPhysicalMaterial naming.
All fields except builtin are optional. Only provided fields override the
preset defaults. Texture string fields are either a data URI or a URL resolved
against the HTML page.
| Field | Type | Default | Description |
|---|---|---|---|
name |
string |
— | Display name. |
builtin |
string |
— | Built-in preset reference (e.g., "stainless-steel"). |
color |
[r, g, b, a] or "#rrggbb" |
— | sRGB base color. RGBA tuple (0--1) or CSS hex. |
map |
string |
— | Base color texture reference. |
metalness |
number |
0.0 |
Metalness factor (0--1). |
roughness |
number |
0.5 |
Roughness factor (0--1). |
metalnessMap |
string |
— | Metalness map texture reference. |
roughnessMap |
string |
— | Roughness map texture reference. |
normalMap |
string |
— | Normal map texture reference. |
aoMap |
string |
— | Ambient occlusion texture reference. |
| Field | Type | Default | Description |
|---|---|---|---|
emissive |
[r, g, b] |
— | Emissive color (linear RGB). |
emissiveMap |
string |
— | Emissive map texture. |
emissiveIntensity |
number |
1.0 |
Emissive intensity. |
| Field | Type | Default | Description |
|---|---|---|---|
transmission |
number |
— | Transmission factor (0--1). |
transmissionMap |
string |
— | Transmission map texture. |
| Field | Type | Default | Description |
|---|---|---|---|
clearcoat |
number |
— | Clearcoat intensity (0--1). |
clearcoatRoughness |
number |
— | Clearcoat roughness. |
clearcoatMap |
string |
— | Clearcoat intensity texture. |
clearcoatRoughnessMap |
string |
— | Clearcoat roughness texture. |
clearcoatNormalMap |
string |
— | Clearcoat normal map texture. |
| Field | Type | Default | Description |
|---|---|---|---|
thickness |
number |
— | Thickness for volume effects. |
thicknessMap |
string |
— | Thickness map texture. |
attenuationDistance |
number |
— | Attenuation distance. |
attenuationColor |
[r, g, b] |
— | Attenuation color (linear RGB). |
| Field | Type | Default | Description |
|---|---|---|---|
ior |
number |
1.5 |
Index of refraction. |
specularIntensity |
number |
— | Specular intensity (0--1). |
specularColor |
[r, g, b] |
— | Specular tint color (linear RGB). |
specularIntensityMap |
string |
— | Specular intensity texture. |
specularColorMap |
string |
— | Specular color texture. |
sheen |
number |
— | Sheen intensity (0--1). |
sheenColor |
[r, g, b] |
— | Sheen tint color (linear RGB). |
sheenRoughness |
number |
— | Sheen roughness. |
sheenColorMap |
string |
— | Sheen color texture. |
sheenRoughnessMap |
string |
— | Sheen roughness texture. |
anisotropy |
number |
— | Anisotropy strength (0--1). |
anisotropyRotation |
number |
— | Anisotropy rotation (radians). |
anisotropyMap |
string |
— | Anisotropy direction texture. |
| Field | Type | Default | Description |
|---|---|---|---|
alphaMode |
"OPAQUE" | "MASK" | "BLEND" |
— | Alpha blending mode. |
alphaCutoff |
number |
0.5 |
Alpha cutoff for MASK mode. |
unlit |
boolean |
— | Use unlit material (no shading). |
doubleSided |
boolean |
— | Render both sides of faces. |
Both material formats in one model -- a builtin preset with overrides, and a MaterialX material from threejs-materials:
{
version: 3,
name: "Lamp",
id: "/Lamp",
loc: [[0, 0, 0], [0, 0, 0, 1]],
bb: { xmin: -5, xmax: 5, ymin: -5, ymax: 5, zmin: 0, zmax: 12 },
materials: {
// 1. Builtin preset (with overrides)
"arm": { builtin: "chrome" },
"shade": {
builtin: "glass-clear",
color: "#eeddcc",
thickness: 2.0,
attenuationColor: [0.95, 0.9, 0.8],
attenuationDistance: 10.0,
},
// 2. MaterialX material (threejs-materials format, detected by `properties` key)
"base": {
properties: {
color: { value: [0.9, 0.9, 0.9], texture: "data:image/png;base64,..." },
roughness: { value: 0.35 },
metalness: { value: 1.0 },
normal: { texture: "data:image/png;base64,..." },
},
textureRepeat: [0.5, 0.5],
},
},
parts: [
{
version: 3,
id: "/Lamp/Arm",
name: "Arm",
type: "shapes",
subtype: "solid",
state: [1, 1],
color: "#cccccc",
material: "arm", // → builtin chrome preset
shape: { /* ... */ },
},
{
version: 3,
id: "/Lamp/Base",
name: "Base",
type: "shapes",
subtype: "solid",
state: [1, 1],
color: "#888888",
material: "base", // → MaterialX with textures
shape: { /* ... */ },
},
{
version: 3,
id: "/Lamp/Shade",
name: "Shade",
type: "shapes",
subtype: "solid",
state: [1, 1],
color: "#eeddcc",
material: "shade", // → Material Appearance (glass)
shape: { /* ... */ },
},
],
}In CAD mode, material tags are ignored and objects render with standard
MeshStandardMaterial using their color and alpha values. In Studio mode,
the material library is resolved and MeshPhysicalMaterial instances are created
with the full PBR property set.
Objects without a material tag use the plastic-glossy preset in Studio mode.
Objects with alpha < 1 and no explicit material tag automatically use the
acrylic-clear preset with transmission = 1 - alpha, simulating glass/acrylic
appearance.
When viewer.render(shapes) is called:
- If the data is in instanced format, all instance buffers are decoded and
{ ref: N }references are resolved to produce a standardShapestree. - Any remaining inline encoded buffers in
shapeobjects are decoded. - Plain arrays are converted to TypedArrays; nested arrays are flattened.
- The tree is passed to
NestedGroupwhich builds the Three.js scene graph with appropriate materials, transformations, and clipping planes. - A navigation tree is extracted for the sidebar tree view UI.