implicitjs
implicitjs is a standalone JavaScript runtime for browser-native implicit CAD
models. It defines the .implicit.js model schema, builds GLSL raymarch
shaders, renders models with Three.js, evaluates SDFs on the CPU, produces
headless PNG/GIF snapshots, samples meshes, checks mesh quality, and exports
STL, 3MF, and GLB artifacts.
The package is UI-framework agnostic. Applications provide their own editor,
catalog, sidebar, persistence, and product workflow; implicitjs provides the
model, rendering, snapshot, and export logic.
Install
npm install implicitjs
Peer usage expects a modern ESM JavaScript environment. Rendering APIs require Three.js-compatible WebGL support. The headless snapshot CLI uses Playwright.
Model Format
An implicit model is an ES module that exports an implicit.js/0.1.0 object.
The glsl string must provide float sdf(vec3 p). It may also provide
vec3 color(vec3 p, vec3 normal) for procedural color.
const GLSL = `
float sdf(vec3 p) {
return implicit_sphere(p, vec3(0.0), radius);
}
vec3 color(vec3 p, vec3 normal) {
return mix(vec3(0.0, 0.65, 1.0), vec3(1.0, 0.3, 0.8), normal.z * 0.5 + 0.5);
}
`;
export default {
schema: "implicit.js/0.1.0",
name: "parametric sphere",
units: "mm",
params: {
radius: { type: "number", label: "Radius", min: 5, max: 50, default: 22, unit: "mm" }
},
bounds: ({ params }) => {
const r = params.radius + 2;
return [[-r, -r, -r], [r, r, r]];
},
render: { steps: 192 },
glsl: GLSL
};
Number, boolean, color, and button params automatically become GLSL uniforms
with matching names. Use param names directly in GLSL; a separate uniforms
object is not needed.
bounds is optional and can be estimated from the SDF, but explicit bounds are
recommended for unusual fields, thin features, periodic models, animated size
changes, or export-heavy workflows.
Authored GLSL can use built-in helpers in the implicit_* namespace, such as
implicit_sphere, implicit_box_centered, implicit_cylinder_capped,
implicit_line_segment2, implicit_union_round, and
implicit_intersect_round.
Public APIs
Common imports:
import {
loadImplicitModuleFromSource,
normalizeImplicitModel,
renderImplicitToDataUrl,
snapshotImplicitCadModel,
exportImplicitModel,
exportImplicitAnimatedGlb
} from "implicitjs";
Useful subpath exports:
implicitjs/model: schema normalization and parameterized runtime models.implicitjs/loader: loading.implicit.jsmodules or source strings.implicitjs/render: Three.js shader and camera helpers.implicitjs/snapshot: browser PNG snapshot helpers.implicitjs/mesh: SDF mesh sampling.implicitjs/meshQuality: mesh quality checks.implicitjs/export: STL/3MF/GLB export APIs.implicitjs/sdfEvaluator: CPU SDF evaluator for compatible GLSL.
Rendering
import * as THREE from "three";
import { loadImplicitModuleFromSource, renderImplicitToDataUrl } from "implicitjs";
const model = await loadImplicitModuleFromSource(source);
const pngDataUrl = await renderImplicitToDataUrl(THREE, model, {
width: 1200,
height: 900,
camera: "iso",
render: { frameMargin: 1.45 },
graphics: { modelColors: true, detail: 1.2 }
});
Camera presets include iso, front, back, left, right, top, and
bottom. Cameras can also be JSON objects with position, target, up,
direction, preset, and zoom.
Snapshots
From a package checkout:
npm run snapshot -- --input examples/model.implicit.js --output /tmp/model.png
npm run snapshot -- --input examples/model.implicit.js --output /tmp/model.gif --mode orbit
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 in JSON jobs when needed.
The snapshot CLI also accepts JSON jobs. A single job can include multiple
outputs, and --job can load one job, an array of jobs, or { "jobs": [...] }.
Prefer one multi-output job when rendering review packets because the browser,
module, and runtime model can be reused.
npm run snapshot -- --job - <<'JSON'
{
"input": "examples/model.implicit.js",
"render": { "frameMargin": 1.55 },
"outputs": [
{ "path": "/tmp/model-iso.png", "camera": "iso" },
{ "path": "/tmp/model-front.png", "camera": "front" },
{ "path": "/tmp/model-top.png", "camera": "top" }
]
}
JSON
Each output path receives a UTC timestamp before its extension.
Exports
import { exportImplicitModel, exportImplicitAnimatedGlb } from "implicitjs/browser";
const glb = await exportImplicitModel(model, {
format: "glb",
resolution: 96,
params: { radius: 24 }
});
const animated = await exportImplicitAnimatedGlb(model, {
animationId: "breathe",
params: { radius: 24 },
frames: 24,
resolution: 72
});
From a package checkout:
npm run export -- --input examples/model.implicit.js --format glb --output /tmp/model.glb
npm run export -- --input examples/model.implicit.js --format stl --resolution 96
npm run export -- --input examples/model.implicit.js --format 3mf --params '{"radius":24}'
Exports sample the model's SDF inside its bounds. Higher resolutions produce denser meshes and take longer.
Package Layout
src/index.js: public package entrypoint.src/browser.js: browser-oriented entrypoint.src/common/: shared camera, parameter, theme, render-option, and headless snapshot helpers.src/lib/implicitCad/: schema, model normalization, loading, shader rendering, CPU evaluation, mesh sampling, mesh quality, and exporters.src/lib/viewer/: internal render presentation defaults used by shaders.scripts/: snapshot, export, export-verification, and test CLIs.
Tests live beside the modules they cover as *.test.js.
Development
npm test
npm run verify:exports -- --input examples/model.implicit.js
Keep the package reusable and UI-independent. Runtime behavior that applies to model normalization, rendering, snapshots, CPU sampling, mesh export, graphics settings, parameters, and animations belongs here. Product-specific UI state, catalogs, editors, file sheets, routing, and persistence should live in the consuming application.