Files
cadSet/text-to-cad/packages/cadjs/docs/render-pipeline.md
2026-07-22 19:38:36 +08:00

363 lines
10 KiB
Markdown

# Render Pipeline
`cadjs` exposes a staged render pipeline for shared viewer, docs, and generated
snapshot browser-runtime work:
```js
const source = await loadSource(input, sourceOptions);
const model = buildModel(THREE, source, modelOptions);
const viewport = renderModel(THREE, model, viewportOptions);
const result = await captureModel(viewport, captureOptions);
```
The stages keep ownership narrow:
- `loadSource` owns source and sidecar loading plus file-kind validation.
- `buildModel` owns the CAD object graph, records, selection, clipping,
materials, topology/display edges, and STEP parameter effects.
- `renderModel` owns renderer, scene, camera, lighting, background, floor,
framing, resizing, and render loop concerns.
- `captureModel` owns deterministic snapshot outputs without filesystem writes.
The CAD skill's Python snapshot CLI remains responsible for job parsing, path
resolution, Playwright routing, and writing returned outputs to disk.
## Modules
### `common/source.js`
```js
import {
loadSource,
stepParameterFrameRuntime
} from "cadjs/common/source.js";
```
`loadSource(input, options)` returns a normalized render source:
```js
{
kind,
meshData,
selectorRuntime,
displayEdgeRuntime,
stepParameterSource,
resolved,
url,
glbUrl,
cadPath
}
```
Accepted input fields:
- `kind`: `step`, `stp`, `glb`, `stl`, `3mf`, or inferred from a URL.
- `meshData`: already-loaded mesh data. If present, no mesh URL fetch is needed.
- `url`: source URL for non-STEP GLB loading.
- `glbUrl` or `resolved.glbUrl`: STEP/STP hidden GLB sidecar URL.
- `cadPath` or `resolved.inputPath`: CAD path used by STEP selectors.
- `selectorRuntime` and `displayEdgeRuntime`: preloaded runtimes when a caller
already owns sidecar loading.
- `stepParameters`: raw STEP render values or animation envelope.
- `stepParameterUrl` or `resolved.stepParameterUrl`: `.step.js`/`.stp.js`
parameter sidecar URL.
STEP-only options are rejected for non-STEP sources. The old shared `params`
field is rejected; use `stepParameters`.
Use `stepParameterFrameRuntime(stepParameterSource, frameIndex)` to turn the
loaded STEP parameter source into the runtime object accepted by `buildModel`
for a still or animation frame.
### `common/cadScene.js`
```js
import {
buildModel,
fitCameraToModel
} from "cadjs/common/cadScene.js";
```
`buildModel(THREE, source, settings)` returns a model API:
```js
{
source,
meshData,
root,
modelGroup,
edgesGroup,
displayRecords,
records,
bounds,
radius,
runtime,
update(nextSettings),
dispose()
}
```
`source` can be a `loadSource()` result or raw mesh data. The model owns the
Three.js object graph and its mutable state.
Common settings:
- `theme`: normalized or raw theme settings.
- `displayMode`: `solid`, `rendered`, `transparent`, `hidden_edges`,
`hidden_lines_removed`, `unshaded`, or `wireframe`.
- `scale`/`sceneScale`: CAD or robot scene scale.
- `selection`: internal selection/filtering state. `focus`, `refs`, and `hide`
filter rendered parts before records are built. Viewer-only fields such as
`selectedPartIds`, `hiddenPartIds`, and `showEdges` affect visual state.
- `clip`: normalized clip-plane settings.
- `stepParameters`: STEP parameter runtime object, usually from
`stepParameterFrameRuntime()`.
- `parameterSetup`: set `false` to skip sidecar setup lifecycle calls.
- `renderPartsIndividually`: build per-part records instead of a whole mesh.
- `edgeRendering`: declarative edge rendering configuration.
Declarative screen-space edge rendering:
```js
buildModel(THREE, source, {
edgeRendering: {
mode: "screen-space",
Line2,
LineGeometry,
LineSegments2,
LineSegmentsGeometry,
LineMaterial,
wireframeEdgeColor: "#111827"
}
});
```
The model keeps screen-space line material bookkeeping internal through
`runtime.screenSpaceLineMaterials` and `runtime.syncScreenSpaceLineMaterials()`.
Callers should not provide callbacks that create edge objects.
`model.update(nextSettings)` merges mutable settings, rebuilds geometry only
when needed, reapplies material/selection/clip/STEP parameter state, and returns
the same model API. `model.dispose()` releases model-owned scene objects and
STEP parameter cleanup hooks.
`fitCameraToModel(THREE, camera, bounds, options)` is the shared orthographic
camera framing helper used by interactive rendering.
### `common/renderModel.js`
Use this module for interactive browser canvases, including the docs hero.
```js
import { renderModel } from "cadjs/common/renderModel.js";
```
`renderModel(THREE, model, options)` returns an interactive viewport API:
```js
{
THREE,
model,
renderer,
scene,
camera,
ready,
resize(),
render(),
start(),
stop(),
capturePng(),
dispose()
}
```
Common options:
- `canvas`: existing canvas for the renderer.
- `hostElement`/`container`: element used for responsive sizing.
- `renderer`: caller-owned renderer. If omitted, one is created.
- `scene` and `camera`: caller-owned scene/camera. If omitted, defaults are
created.
- `theme`/`themeSettings`: background and lighting settings.
- `alpha`, `antialias`, `powerPreference`, `preserveDrawingBuffer`,
`logarithmicDepthBuffer`, `shadows`: renderer controls.
- `direction`, `up`, `padding`, `scale`/`sceneScale`: framing controls.
- `pixelRatio`, `maxPixelRatio`: output density controls.
- `autoResize`: set `false` to disable `ResizeObserver`.
- `autoStart`: set `true` to start an animation loop.
- `autoRender`: set `false` to prevent the initial render.
- `beforeRender({ deltaSeconds, viewport })`: per-frame hook for animation.
- `disposeModel`: set `false` when the caller will dispose the model.
`dispose()` stops animation, disconnects resize observation, removes the model
root from the scene, and disposes the created renderer/model unless ownership
was explicitly retained by options.
### `common/renderMeshScene.js`
Use this module for deterministic headless snapshot rendering.
```js
import {
renderJobContext,
modelOptionsForRenderJob,
renderModel,
captureModel,
renderMeshJob
} from "cadjs/common/renderMeshScene.js";
```
`renderJobContext(meshData, job)` normalizes snapshot-owned render policy:
appearance, display, scene scale, outputs, STEP topology edge visibility, and
warnings.
`modelOptionsForRenderJob(context, job)` converts that policy into
`buildModel()` settings.
Snapshot `renderModel(THREE, model, { job, context })` returns a headless
viewport:
```js
{
THREE,
model,
scene,
renderer,
orthographicCamera,
perspectiveCamera,
context,
sceneBuildStarted,
ready,
dispose()
}
```
This `renderModel` is intentionally separate from `common/renderModel.js`.
It uses snapshot sizing, theme environment, floor, orthographic/perspective
camera presets, and deterministic renderer settings.
`captureModel(viewport, { job })` returns data only:
- `mode: "view"`: PNG data URLs in `outputs`.
- `mode: "orbit"`: the caller composes frames into GIF output.
- `mode: "section"`: PNG data URLs or SVG text in `outputs`.
- `mode: "list"`: part list and bounds.
It does not write files. The CAD skill snapshot CLI writes the returned data to
disk. Source checkouts use `packages/cadjs`; generated snapshot browser assets
bundle this entrypoint into `skills/cad/scripts/snapshot/runtime`.
`renderMeshJob(meshData, job)` is a compatibility wrapper that builds a context,
builds a model, renders/captures it, and disposes owned resources.
## STEP Parameters
Shared render APIs use the name `stepParameters`.
Raw render values can be direct parameter values:
```json
{
"drive": 180,
"ringVisible": false
}
```
Or an animation envelope:
```json
{
"values": {
"ringVisible": true
},
"animate": {
"drive": { "from": 0, "to": 1260 }
},
"durationSeconds": 6,
"fps": 18,
"loop": true
}
```
`common/stepParameters.js` validates these values against the loaded STEP
parameter sidecar schema, normalizes defaults, and computes per-frame values.
`loadSource()` uses it to populate `source.stepParameterSource`; callers can
then use `stepParameterFrameRuntime()` when passing parameters into
`buildModel()`.
## Examples
Interactive viewer/docs usage:
```js
import * as THREE from "three";
import { loadSource, stepParameterFrameRuntime } from "cadjs/common/source.js";
import { buildModel } from "cadjs/common/cadScene.js";
import { renderModel } from "cadjs/common/renderModel.js";
const source = await loadSource({
kind: "step",
glbUrl: "/models/.part.step.glb",
stepParameterUrl: "/models/.part.step.js",
cadPath: "models/part.step",
stepParameters: { drive: 180 }
});
const model = buildModel(THREE, source, {
theme,
displayMode: "solid",
stepParameters: stepParameterFrameRuntime(source.stepParameterSource, 0)
});
const viewport = renderModel(THREE, model, {
canvas,
hostElement: canvas.parentElement,
theme,
autoStart: true
});
```
Headless snapshot usage:
```js
import * as THREE from "three";
import { loadSource } from "cadjs/common/source.js";
import { buildModel } from "cadjs/common/cadScene.js";
import {
captureModel,
modelOptionsForRenderJob,
renderJobContext,
renderModel
} from "cadjs/common/renderMeshScene.js";
const source = await loadSource(job);
const context = renderJobContext(source.meshData, job);
const model = buildModel(THREE, source, modelOptionsForRenderJob(context, job));
const viewport = renderModel(THREE, model, { job, context });
try {
const result = await captureModel(viewport, { job });
// Write result.outputs in the CAD skill snapshot CLI or another caller-owned layer.
} finally {
viewport.dispose();
}
```
Orbit GIF jobs default to 6 fps over 12 seconds for a calmer review spin
without increasing default render frame count.
Override with `orbit.fps` and `orbit.durationSeconds` when a shorter or denser
render is needed.
## Ownership Rules
- Do not write files from shared render APIs. Return data to the owning CLI or
application layer.
- Do not expose object-construction callbacks for edges. Use declarative
`edgeRendering`.
- Keep STEP-only options explicitly STEP-named and reject them for non-STEP
sources.
- Dispose viewports and models that you create.
- Prefer `loadSource -> buildModel -> renderModel -> captureModel` for new
shared render code instead of loading assets or constructing render scenes
inline.