Getting started
cadjoint is code-first CAD in which sketches, constraints, SDF geometry, meshing and finite-element simulation compose into one function JAX can differentiate end to end. This page installs it, builds one model, takes one gradient, and links to the guide for each stage.
The API is not stable. Expect breaking changes.
Install
From PyPI, pinned because the API moves:
pip install "cadjoint==<version>"
From a checkout, with uv:
git clone https://github.com/andrinr/cadjoint
cd cadjoint
uv sync # CPU JAX: macOS, Linux, Windows
uv sync --extra cuda # Linux + NVIDIA GPU instead
uv sync creates .venv and installs cadjoint into it in editable mode. Run commands through it with uv run <cmd>, or activate it with source .venv/bin/activate. Everything beyond the geometry core is an extra, one --extra per name (uv sync --extra fem --extra tesseract --extra viewer); the extras table lists what each pulls in.
fem is the one extra that compiles. petsc4py publishes no wheels, so uv sync --extra fem builds PETSc from source and needs a C compiler, gfortran and BLAS/LAPACK headers (apt install build-essential gfortran libopenblas-dev on Debian/Ubuntu). Without that toolchain, run the solvers as Tesseracts instead: their images get PETSc from conda-forge and are published prebuilt to GHCR for amd64 and arm64, so Docker is the only requirement (see prebuilt images).
Supported platforms
| Platform | uv sync |
uv sync --extra fem |
|---|---|---|
| Linux x86_64 | yes | compiles PETSc |
| Linux ARM64 | yes | no: gmsh has no Linux ARM wheel |
| macOS arm64 | yes | compiles PETSc |
| macOS x86_64 (Intel) | no: jaxlib has no Intel-Mac wheel for Python 3.11+ | no |
| Windows x86_64 | yes | no: PETSc does not build natively |
Every “yes” is a fresh uv sync --locked and import cadjoint in install.yml, run on each push. Where the fem column says no, the prebuilt solver Tesseracts run the same solvers in Docker.
A first model
A four-vertex sketch with one distance constraint, extruded by a free depth and dual-contoured into a mesh:
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, save_stl
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)
save_stl(mesh, "block.stl")
Parameters, sketches, features and constraints are covered in Modelling; the mesher and its exporters in Meshing.
Gradients
extract_parameters splits the tree into free and fixed parameter dicts, and functionalize turns it into a pure function of them. jax.grad of anything downstream reaches every free parameter:
import jax
import jax.numpy as jnp
from cadjoint import extract_parameters, functionalize
free, fixed, _ = extract_parameters(block)
field = functionalize(block)
probe = jnp.array([0.5, 0.5, 0.5])
grads = jax.grad(lambda params: field(params, fixed)(probe))(free)
grads["depth"] # -0.5: the top cap sits at depth/2
The probe lies above the top cap, so only depth moves its distance; the vertex gradients there are zero.
Optimization runs this gradient through a mesh and a finite-element solve.
Playground
The browser app ships in the package and needs the viewer extra (editor adds lint and completion):
uvx --from "cadjoint[viewer,editor]" cadjoint-viewer --open # nothing installed
uv run --extra viewer --extra editor cadjoint-viewer --open # from a checkout
It opens on a parametric heat sink that declares a mesh, a thermal study and an optimization. See the playground.
Scripts
Run from the repository root with python examples/<name>.py.
fem_bracket_optimization.py: shape optimization of an L-bracket through SDF, hex mesh and linear elastic solve (jax-fem or CalculiX), minimizing compliance and mass with Adam; writes a convergence CSV, a plot and VTK files toexamples/output/. Requires thefemextra andoptax.rendering_gallery.py: renders the lighting-mode and quality-preset comparison images in Rendering todocs/assets/.
Next
- Modelling: parameters, sketches, features, SDF solids, faces and constraints.
- Meshing: dual contouring, sharp features, export and mesh checks.
- Simulation: simulation meshes, thermal and elastic studies, solver backends.
- Materials: the
Materialclass, the catalogue, material fields and mass. - Optimization: declared descents, objectives, gradient paths and constraints.
- Rendering: the JAX raymarcher, quality presets and WGSL compilation.
- Plugins: the plugin contract,
plugins.toml, and writing and serving a plugin. - Flow solver (prototype): lattice-Boltzmann flow and conjugate heat transfer on the SDF.