How to Parameterize STEP Models with .step.js Sidecar Modules in text-to-cad
Create a hidden JavaScript sidecar file next to your STEP geometry to add interactive UI controls, animations, and parameter-driven features without regenerating the underlying CAD model.
The text-to-cad repository supports .step.js sidecar modules—JavaScript files that live alongside STEP geometry files and export declarative manifests describing how the geometry should behave in the CAD Viewer. This pattern lets you transform static STEP artifacts into live, configurable components while keeping geometry and logic cleanly separated.
What Is a .step.js Sidecar Module?
A sidecar module is a JavaScript file that pairs with a STEP file using a strict naming convention. The sidecar contains no geometry itself; instead, it exports a manifest object that tells the viewer:
- Where to find the STEP file
- What UI controls to render (sliders, toggles, selects)
- Which geometric features those controls manipulate
- Optional animation timing and keyframes
The viewer loads the STEP once, then applies parameter changes dynamically through the sidecar—no re-export required.
Sidecar Naming and Discovery
Sidecars must follow a dot-prefix naming pattern to be automatically detected.
Naming Convention
| STEP File | Sidecar File |
|---|---|
gearbox.step |
.gearbox.step.js |
robot_arm.stp |
.robot_arm.step.js |
The stem must match exactly. The leading dot makes the file hidden on Unix systems, keeping your model directories clean.
Discovery Implementation
In packages/cadjs/src/common/stepSidecars.mjs, the helper isInlineStepParameterPath validates sidecar paths:
// stepSidecars.mjs lines 13-16
export function isInlineStepParameterPath(path) {
const basename = path.split('/').pop();
return basename.startsWith('.') && basename.endsWith('.step.js');
}
To compute a sidecar path from a STEP source, use stepParameterPathForStepSource:
// stepSidecars.mjs lines 40-43
export function stepParameterPathForStepSource(sourcePath) {
const dir = dirname(sourcePath);
const base = basename(sourcePath);
const stem = base.replace(/\.(step|stp)$/i, '');
return join(dir, `.${stem}.step.js`);
}
The viewer's directory scanner (viewer/src/server/catalog/cadDirectoryScanner.mjs) uses these helpers to find and serve sidecars at runtime URLs like /models/<folder>/.<stem>.step.js?v=<hash>.
The Manifest Contract
Every sidecar must export a default object with a manifest key. The manifest structure is versioned and strictly validated.
Required Fields
| Field | Type | Description |
|---|---|---|
manifest.schemaVersion |
number |
Always 1 in current versions |
manifest.step.path |
string |
Workspace-relative path to the STEP file |
manifest.parameters |
array |
UI control definitions |
Parameter Definition Schema
Each parameter in the parameters array needs:
id– snake_case identifier used in codetype–"number","boolean", or"select"label– Human-readable display namedefault– Initial valuefeatureId– Stable reference to a STEP feature (prefixed with#)
Optional fields include min, max, step, and unit for numeric controls.
Minimal Sidecar Example
Create .gearbox.step.js next to gearbox.step:
// models/mechanisms/.gearbox.step.js
export default {
manifest: {
schemaVersion: 1,
step: {
path: "models/mechanisms/gearbox.step"
},
parameters: [
{
id: "gear_ratio",
type: "number",
label: "Gear Ratio",
default: 2,
min: 1,
max: 10,
step: 0.1,
featureId: "#gear_pair"
}
]
}
};
Critical details:
pathis workspace-relative—no leading slash or..segmentsfeatureIdreferences a feature that must exist in the STEP metadata- The filename
.gearbox.step.jsmatchesgearbox.stepexactly
Animation-Enabled Sidecars
Add durationSeconds to enable timeline controls in the viewer:
// models/robots/.arm.step.js
export default {
manifest: {
schemaVersion: 1,
step: { path: "models/robots/arm.step" },
durationSeconds: 4,
parameters: [
{
id: "joint_travel",
type: "number",
label: "Elbow Travel",
unit: "deg",
default: 0,
min: -90,
max: 90,
step: 1,
featureId: "#elbow_joint"
}
]
}
};
When durationSeconds is present, the viewer renders a playback bar with play/pause and scrub functionality. Parameters can be keyed to animation time or remain as manual overrides.
Accessing Sidecar Manifests Programmatically
Python skills in the repository can consume sidecars by evaluating them through Node.js:
from pathlib import Path
import json
import subprocess
def load_step_manifest(step_path: Path):
sidecar_path = step_path.with_name(f".{step_path.stem}.step.js")
if not sidecar_path.is_file():
raise FileNotFoundError(f"No sidecar for {step_path}")
# Evaluate the JS module and extract the manifest
result = subprocess.check_output([
"node", "-e",
f"import('{sidecar_path}').then(m=>console.log(JSON.stringify(m.default.manifest)))"
], text=True)
return json.loads(result)
# Usage
manifest = load_step_manifest(Path("models/mechanisms/gearbox.step"))
print(manifest["parameters"][0]["id"]) # → "gear_ratio"
Production skills use the snapshot pipeline rather than direct subprocess calls, but the evaluation pattern remains: import the module, access default.manifest, and operate on the resulting JSON.
Parameter Naming Conventions
Per skills/cad/references/parameters.md, follow these rules for maintainable sidecars:
- Use snake_case for all parameter IDs
- Prefix related parameters with a common noun (
motor_speed,motor_torque) - Keep IDs stable—changing them breaks saved configurations
- Document physical units explicitly in the
unitfield
Feature IDs in manifest.features (referenced by featureId) should use descriptive names tied to the CAD model's semantic structure.
Summary
- Sidecar files use the pattern
.<stem>.step.jsand live adjacent to their STEP geometry - Discovery helpers in
stepSidecars.mjspower automatic detection by the viewer - Manifest schema requires
schemaVersion: 1, a workspace-relativestep.path, and parameter definitions - Animation support activates when
durationSecondsis present in the manifest - Zero regeneration—the viewer manipulates loaded geometry rather than re-exporting CAD
Frequently Asked Questions
What happens if I rename my STEP file?
You must rename the sidecar to match. The viewer uses stepParameterPathForStepSource to compute the expected sidecar name, and isInlineStepParameterPath will reject files that don't follow the dot-prefix convention. Mismatched pairs are ignored during directory scanning.
Can a single STEP file have multiple sidecars?
No. The one-to-one naming convention enforces a single sidecar per STEP file. For alternative configurations, create separate model directories or use conditional logic within one sidecar's manifest.
How do I reference features that don't exist yet in my STEP?
Feature IDs must be stable identifiers embedded in the STEP metadata during generation. If using build123d or similar tools, assign explicit labels to geometric entities; these become the #-prefixed feature IDs available to sidecar parameters.
Does the sidecar support TypeScript?
The current implementation expects JavaScript modules. TypeScript sidecars would require a build step or on-the-fly transpilation, which the viewer's dynamic import loader does not currently perform. Write plain JavaScript with JSDoc comments for type hints if needed.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →