Skip to content
andrinrPublic

About

Differentiable implicit CAD in the browser: edit via GUI or code, solve constraints, render with WebGPU raymarching, optimize shapes end-to-end.

Topics

Resources

Stars

66 stars

Watchers

2 watching

Forks

Repository files navigation

cadjoint

PyPI Python License

Differentiable code-first CAD: sketches, constraints, SDF geometry, meshing and FEM simulation composed into one function JAX can differentiate end to end.

Warning

The API is not stable. Expect breaking changes.

The bracket in the playground's vertex mode, with the rib's distance constraint removed. The camera turns half way around the part; the pointer drags the free handle at the tip of the gusset rib up and out, the rib and its smooth-union blend follow the drag, and on release the rib_tip Vector2 literal in the editor is rewritten. The handle is dragged back, and the camera finishes the turn.

Dragging the rib_tip handle updates the shader's parameter buffer each frame and rewrites the Vector2 literal in scene.py on release.

Pipeline

sketch vertices ─► constraints ─► SDF ─► mesh ─► FEM solve ─► objective
       └─────────────────────────── ∂J/∂θ ◄───────────────────────────┘

One Python program declares every stage, and JAX differentiates through each:

  • A sketch profile is a list of named Vector2 parameters.
  • Constraints are residuals on those parameters, solved by Newton projection onto the constraint manifold.
  • Extruding or revolving the profile gives an SDF that shares the parameter objects.
  • Dual contouring extracts a surface, TetGen or Gmsh fills it, and jax-fem or CalculiX solves on it.
  • A study and an Optimization are declared in the scene beside the geometry. Each optimization step is a mesh, a solve and an adjoint, projected back onto the constraints.
  • No boundary representation is stored; every surface is extracted from the SDF at a chosen resolution.

The end cap's cap-conduction thermal study in the Simulate desk. Clicking Solve meshes and solves the study, shown time-lapsed; the temperature field then appears on the part, and the Results panel shows its legend and the minimum, mean and maximum temperature.

The end cap's ThermalStudy is meshed and solved with one click.

The heat sink's cool-sink optimization in the Optimize panel, time-lapsed. Clicking Run takes eight Adam steps while the objective trace is drawn; the viewport then replays the trajectory, and the fins slim and taper as the peak temperature objective falls from 1.612 to 1.465.

The heat sink starts overbuilt; its declared Optimization slims it by descending on the gradient of peak temperature with respect to the sketch.

The heat sink in Sketch mode. Selecting the fin comb in the Objects tree shows its sketch plane with the move gizmo; dragging the gizmo's Z arrow lifts the plane and the comb with it, and the ORIGIN field in the Properties window updates to the rewritten SketchPlane origin. The plane is then dragged back down.

In Sketch mode, dragging a literal work plane by its gizmo rewrites its SketchPlane(origin=...); a plane taken from a face (SketchPlane.on(body.cap("+"))) is instead an expression over the parent feature's parameters, so it is differentiable.

Features

  • Geometry: SDF primitives, smooth booleans, transforms, patterns; sketches on work planes extruded, revolved or lofted into solids that share their parameters; reference planes from faces, offsets and midplanes
  • Constraints: distance, angle, coincident, horizontal, vertical, parallel, perpendicular, equal-length, point-on-line, fixed
  • Materials: a sourced catalogue of density, conductivity, elastic constants and yield strength in SI, sampled per element by the solver
  • Meshing: dual contouring with sharp-feature vertices; TET4/TET10 through TetGen, second-order tets through Gmsh, a voxelize-and-snap HEX8 path, or cut cells with no volume mesh; OBJ, STL and faceted STEP export
  • Simulation: thermal and linear-elastic studies with programmatic node selections, solved by jax-fem or CalculiX 2.23; a lattice-Boltzmann flow prototype
  • Optimization: declared in the scene, descended with optax, every step projected back onto the constraints
  • Plugins: every non-JAX component (meshers, solvers) behind one apply/vjp interface, implemented as a Tesseract and run in-process, in a container or remotely
  • Rendering: a forward raymarcher in JAX, and a WGSL shader emitter for the browser
  • Playground: a WebGPU app in which every edit rewrites the Python source that produced it

Install

pip install cadjoint         # pin an exact version: the API is not stable

Everything beyond the geometry core is an extra (pip install "cadjoint[fem]", or uv sync --extra fem in a checkout, one --extra per name):

Extra Pulls in
cuda GPU JAX (Linux + NVIDIA only; no macOS wheels, so avoid --all-extras on a Mac)
fem jax-fem finite-element stack (basix, meshio, petsc4py, gmsh); compiles PETSc
tesseract tesseract-core + tesseract-jax, the plugin runtime
gmsh Gmsh in-process for the tet10 mesher (GPL, hence its own extra)
viewer the playground server (pydantic), the Jupyter widget (anywidget) and the process monitor (psutil)
editor playground lint, completion and signature help (ruff, jedi)
stepcheck OCCT validation of STEP exports (dev)
docs Quarto API reference (quartodoc)

Installing from a checkout, the platforms CI verifies, and the toolchain the fem extra needs are in Getting started.

Playground

uvx --from "cadjoint[viewer,editor]" cadjoint-viewer --open      # no checkout
uv run --extra viewer --extra editor cadjoint-viewer --open      # from a checkout

The editor holds scene.py and the viewport shows the compiled field. Vertex handles, gizmos, material swatches, face picks, constraint chips, solver runs and the properties window all write back into the source.

The properties window: clicking the fin comb's extrude row in the Objects tree shows its profile, its depth (the named parameter fin_depth) and its material. Typing 1.8 into the depth field deepens the comb, typing 1.2 restores it, and follow selection clears the window.

The properties window edits the arguments of the selected call: here the comb's extrusion depth.

The server listens only on localhost but executes the scene's Python on your machine; only run code you trust. The playground guide covers every window, the scenes directory and browser support.

Python example

from cadjoint.construction import PolygonProfile, SketchPlane, extrude
from cadjoint.constraints import DistanceConstraint, satisfy_constraints
from cadjoint.geometry import Scalar, Vector2
from cadjoint.meshing import GridSpec, extract_mesh

a = Vector2([0.0, 0.0], free=True, name="a")
b = Vector2([1.0, 0.0], free=True, name="b")
c = Vector2([1.0, 1.0], free=True, name="c")
d = Vector2([0.0, 1.0], free=True, name="d")
DistanceConstraint(a, b, 1.2)

depth = Scalar(0.5, free=True, name="depth")
block = extrude(PolygonProfile([a, b, c, d], plane=SketchPlane()), depth=depth)
satisfy_constraints(block)          # projects a and b onto the constraint, in place

grid = GridSpec.from_bounds((-0.5, -0.5, -0.5), (2.0, 2.0, 1.5), 32)
mesh = extract_mesh(block, grid)

functionalize(block) returns a pure function of the parameter values, so jax.grad of anything downstream reaches a, b, c, d and depth. Modelling covers sketches, features and constraints, and the guides continue to meshing, a thermal study and an optimization; examples/fem_bracket_optimization.py runs the full chain from the command line, with the adjoint checked against finite differences at every boundary.

Documentation

Developing

uv run pytest tests -q --ignore=tests/fem   # fast gate
uv run pytest tests/fem -q                  # needs the fem extra; CalculiX via CADJOINT_CCX
uv run pre-commit install                   # ruff on commit

The playground UI is a Solid + TypeScript app in frontend/, built into cadjoint/viewer/static and committed, so installing cadjoint needs no Node toolchain; its workflow is in developing the UI. Docs need Quarto and the docs extra: uv run quartodoc build, then quarto preview. benchmarks/jax_compile_profile.py splits a worker request into trace, lower, XLA compile and cache time per program; research/performance.md records what each optimization bought.

Acknowledgements

Inspired by Fidget and Inigo Quilez's distance functions.

License

Apache License 2.0.

About

Differentiable implicit CAD in the browser: edit via GUI or code, solve constraints, render with WebGPU raymarching, optimize shapes end-to-end.

Topics

Resources

Stars

66 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages