Understanding the Display Record Transform API in cadjs: A Complete Guide

The display record transform API in cadjs provides pure functions that compose per-part effect matrices and exploded-view offsets, then apply the combined transforms to three.js mesh, edge, and silhouette objects every frame.

The display record transform API is the low-level runtime engine inside the earthtojake/text-to-cad repository that manages how CAD parts move, rotate, and appear in the viewer. Located in the cadjs package, this API encapsulates all matrix mathematics into three atomic operations, keeping the rendering pipeline clean of raw three.js boilerplate while handling step-module effects, exploded views, and visibility toggles.

What the Display Record Transform API Does

At its core, the API transforms abstract display records—plain JavaScript objects that store the visual state of individual CAD parts—into updated three.js scene objects. Each display record contains mesh, edges, and silhouette objects, along with optional effectMatrix and explodedViewMatrix properties that represent temporary visual modifications.

The Three-Stage Transformation Pipeline

The API processes every visual change through a strict three-stage pipeline:

  1. Compose Effect Matrix: Merges any step-module effect matrices with the exploded-view matrix stored on the record.
  2. Compose Final Object Matrix: Multiplies the effect matrix with the part’s base transform (derived from STEP or URDF pose data).
  3. Apply to Scene Objects: Writes the final calculated matrix directly to the three.js objects and updates visibility flags.

This design ensures that step-module effects, exploded views, and base CAD geometry all converge through a single, consistent mathematical path before hitting the GPU.

Core Functions and Implementation Details

All functions live in packages/cadjs/src/common/displayRecordTransform.js and operate as pure functions accepting a THREE context and a display record.

composeDisplayRecordEffectMatrix

composeDisplayRecordEffectMatrix(THREE, record) returns a combined THREE.Matrix4 representing the accumulation of record.effectMatrix and record.explodedViewMatrix. If neither matrix exists, the function returns null, allowing the pipeline to skip unnecessary calculations.

Source: displayRecordTransform.js:16-31

composeDisplayRecordObjectMatrix

composeDisplayRecordObjectMatrix(THREE, record) builds the final transformation by first generating the base part matrix via buildPartTransformMatrix (defined in stepModuleEffects.js), then multiplying it with the effect matrix from the previous step.

Source: displayRecordTransform.js:34-38

applyDisplayRecordTransform

applyDisplayRecordTransform(THREE, record) performs the actual scene update. It takes the composed matrix and applies it to record.mesh, record.edges, and record.silhouette, then forces three.js to recalculate the world matrix via updateMatrixWorld(). This is the function called every frame by the viewer.

Source: displayRecordTransform.js:40-48

Helper: buildPartTransformMatrix

The pipeline relies on buildPartTransformMatrix(THREE, transform) from packages/cadjs/src/common/stepModuleEffects.js to convert raw 16-element array data into proper THREE.Matrix4 instances. This utility bridges the gap between STEP/URDF geometric data and three.js math objects.

Source: stepModuleEffects.js:18-43

Integration with the Rendering Pipeline

Understanding where the API sits in the data flow clarifies why it remains stateless and pure:

  1. Model Loading: cadjs/lib/cadScene initializes a displayRecord for every part, attaching the three.js objects and a baseTransform derived from the original CAD file.
  2. Effect Injection: The Step-Module Effects API (createStepModuleEffectsApi) writes to effectsByPartId, storing temporary effectMatrix values on specific records.
  3. Exploded View: The exploded-view controller writes translation matrices directly to record.explodedViewMatrix.
  4. Frame Rendering: Before each render, CadViewer.js (line 842) iterates through runtime.displayRecords and calls applyDisplayRecordTransform(THREE, record), ensuring every visual modification appears in the final frame.

Edge-line objects reuse this same pipeline via applyRecordEffectMatrix in topologyDisplayEdgeLine.js, guaranteeing that topology highlights and wireframes move in perfect sync with their parent meshes.

Working Code Examples

Applying a Step-Module Effect

Use the Step-Module Effects API to rotate a specific part, then apply the transform:

import { createStepModuleEffectsApi } from 'cadjs/lib/stepModuleEffects';
import { applyDisplayRecordTransform } from 'cadjs/lib/viewer/modelRuntime';

const api = createStepModuleEffectsApi(runtime.THREE, {
  meshData,
  features,
  runtime,
  effectsByPartId: new Map(),
  onTransformEffect: ({ target, matrix }) => {
    console.log('Effect applied to', target);
  },
});

// Apply 45-degree rotation around Z-axis to part "001"
api.transform('001', { rotate: { axis: [0, 0, 1], angleDeg: 45 } });

// Update the scene (normally called per frame by the viewer)
runtime.displayRecords.forEach(record => {
  applyDisplayRecordTransform(runtime.THREE, record);
});

This stores the rotation in record.effectMatrix, which applyDisplayRecordTransform composites with the base transform before updating the three.js mesh.

Implementing Exploded-View Translations

Apply a uniform translation to all parts to simulate an exploded assembly view:

import { applyDisplayRecordTransform } from 'cadjs/lib/viewer/modelRuntime';

// Create a translation matrix (20mm along X-axis)
const translation = new runtime.THREE.Matrix4().makeTranslation(20, 0, 0);

// Assign to each record and immediately apply
runtime.displayRecords.forEach(record => {
  record.explodedViewMatrix = translation.clone();
  applyDisplayRecordTransform(runtime.THREE, record);
});

The explodedViewMatrix integrates seamlessly with any existing effectMatrix, demonstrating how the API composes multiple transform sources into a single final matrix.

Key Source Files

File Role Direct Link
packages/cadjs/src/common/displayRecordTransform.js Core API implementation (compose & apply functions) displayRecordTransform.js
packages/cadjs/src/common/stepModuleEffects.js Matrix builders and effect composition helpers stepModuleEffects.js
viewer/src/client/components/CadViewer.js Frame loop caller at line 842 CadViewer.js
viewer/packages/cadjs/src/lib/viewer/modelRuntime.js Public API exposure to runtime modelRuntime.js
viewer/packages/cadjs/src/lib/viewer/topologyDisplayEdgeLine.js Edge-line transform reuse topologyDisplayEdgeLine.js

Summary

  • The display record transform API in cadjs abstracts three.js matrix math into three pure functions: composeDisplayRecordEffectMatrix, composeDisplayRecordObjectMatrix, and applyDisplayRecordTransform.
  • It processes effect matrices (from step modules) and exploded-view matrices separately, then composites them with base CAD transforms before writing to the scene.
  • The API is invoked every frame by CadViewer.js (line 842) to ensure all visual states remain synchronized with the underlying three.js objects.
  • Edge lines and topology highlights reuse the same transformation logic, maintaining visual consistency across the entire viewport.

Frequently Asked Questions

What is a display record in cadjs?

A display record is a plain JavaScript object that represents the runtime visual state of a single CAD part. It stores references to the three.js mesh, edges, and silhouette objects, along with baseTransform (the original pose from the CAD file), and optional effectMatrix or explodedViewMatrix properties for temporary visual modifications.

How does the display record transform API handle step-module effects?

Step-module effects call createStepModuleEffectsApi, which writes transformation matrices into effectsByPartId. These matrices are stored on the relevant display record's effectMatrix property. When applyDisplayRecordTransform runs, it calls composeDisplayRecordEffectMatrix to merge this effect matrix with any exploded-view matrix before applying the result to the three.js objects.

What is the difference between effectMatrix and explodedViewMatrix?

The effectMatrix stores temporary transformations generated by step-module interactions (such as highlighting, rotation, or translation effects), while the explodedViewMatrix stores offsets used specifically for exploded-view assemblies. Both matrices are optional; the API composites them together with the base transform, allowing both effects to operate simultaneously without interfering with each other.

Where does applyDisplayRecordTransform get called in the rendering loop?

According to the source in viewer/src/client/components/CadViewer.js at line 842, applyDisplayRecordTransform is invoked once per display record during every animation frame. This ensures that any changes to effect matrices or exploded-view states are immediately reflected in the three.js scene before the next render pass.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →