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 code
  • type – "number", "boolean", or "select"
  • label – Human-readable display name
  • default – Initial value
  • featureId – 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:

  • path is workspace-relative—no leading slash or .. segments
  • featureId references a feature that must exist in the STEP metadata
  • The filename .gearbox.step.js matches gearbox.step exactly

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 unit field

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.js and live adjacent to their STEP geometry
  • Discovery helpers in stepSidecars.mjs power automatic detection by the viewer
  • Manifest schema requires schemaVersion: 1, a workspace-relative step.path, and parameter definitions
  • Animation support activates when durationSeconds is 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:

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 →