CeTZ compiles a Rust geometry core to WebAssembly, which is why installing it needs just and cargo
CeTZ: ein Typst Zeichenpaket - A library for drawing stuff with Typst.
At a glance
- What is it?
- CeTZ is a Typst drawing package with a TikZ-like API that computes real geometry in a Rust core shipped as WebAssembly. That design gives accurate paths and 3D projections, and it means the package cannot be dropped into a document without a build step if you install it locally.
- Who is it for?
- Adopt CeTZ for Typst documents that need real geometry, 3D projection or node-based diagrams, and plan for the local install path with git clone --recursive, just and cargo, or take the @preview package which needs neither. Do not adopt it if your diagrams are simple enough for Typst's own drawing primitives, since the WebAssembly core buys you accuracy you would not use.
- Can I use it commercially?
- Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Typst, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The Rust core: a wasm32 target built before anything else
The single most useful fact about CeTZ is in the justfile. Every target depends on build, and build compiles a Rust crate to WebAssembly:
cd cetz-core; \
cargo build --release \
--target wasm32-unknown-unknown; \
cp target/wasm32-unknown-unknown/release/cetz_core.wasm cetz_core.wasmSo the geometry is not computed in Typst code. A wasm32-unknown-unknown build of cetz-core is copied next to the package as cetz_core.wasm, and the Typst side calls into it.
That explains several things about working with the project. It explains why the repository has a.gitmodules file and why the clone must be recursive. It explains why the install step needs cargo. And it explains why the package is a compiled artefact as much as a source package.
For local development, this introduces a Rust toolchain requirement. It also means you need a Rust toolchain for any local workflow, not just for the library code.
Drawing code: a canvas, a draw import, and your code in between
The public entry point is cetz.canvas, and the template shown in the README is short:
#import "@preview/cetz:0.5.2"
#cetz.canvas({
import cetz.draw: *
// Your drawing code goes here
})The import line inside the canvas closure pulls in the drawing primitives with a wildcard, which is what lets subsequent lines use short names. The version is part of the import string, so a document pins the package version the same way Typst pins anything from the package registry.
The API is described as inspired by TikZ and Processing. The gallery reflects that, covering a right triangle on the unit circle, Pacioli's construction of the icosahedron, a plate capacitor, a tree layout, a periodic table, sine waves in 3D and a torus.
Clicking any gallery image opens the corresponding.typ source, and a larger gallery of scientific diagrams is hosted separately at janosh.github.io/diagrams.
Local install changes the import prefix, not the code
Installing under the local Typst package directory is done with a script, and the clone has to be recursive first because of the submodules:
# to fetch a clean clone:
git clone --recursive https://github.com/cetz-package/cetz.git
# or if you forgot the `--recursive` flag before:
git submodule update --initAfter that you need just and cargo installed, then run the install target, which defaults to the @local target:
just installThe only difference in your document is the prefix. A locally installed package is imported with @local rather than @preview:
#import "@local/cetz:0.5.2"
#cetz.canvas({
import cetz.draw: *
// Your drawing code goes here
})Everything else, including the version number in the import string, stays the same. That symmetry is a deliberate convenience: you can develop against a local checkout and swap the prefix back when you publish.
For Nix users the README documents enabling flakes and entering a dev shell with nix --extra-experimental-features 'nix-command flakes' develop. On Windows, just can come from cargo install just or Chocolatey, but it must be run from an sh compatible shell such as git-bash.
The justfile also builds the docs and the manual, both through Typst
The same file documents how the project produces its own reference material, which is useful for understanding what the maintainers consider the public surface.
The manual target compiles manual.typ with typst compile --root ., producing manual.pdf. The docs target is more involved: it runs typst query against manual.typ for the metadata field, pipes the result through a Python script at docs/genhtml.py, and writes into docs/_generated. So the online manual at cetz-package.github.io/docs is generated from the Typst manual source by a query and a Python generator, not written by hand in HTML.
Two other targets are worth noting. The gallery target renders every .typ file in the gallery directory to PNG with typst c in a shell loop, which is how the example images in the README are produced. The zip target packages into a temporary directory and tars it as cetz.tar.bz2, which is the distribution route rather than a build for consumption.
Every one of these depends on build, so even rendering the manual requires the WebAssembly core to compile first.
Testing depends on tytanic and on a build step you might not expect
Unit tests live under the tests directory and run through the tytanic tool, invoked as tt in the justfile:
test *filter: build
tt run {{filter}}
update-test *filter: build
tt update {{filter}}tytanic is a Rust tool installed with cargo install tytanic, and it has to be on your PATH. The test target takes an optional filter, so tt run with an argument narrows the run.
The update-test target regenerates expected outputs, which is the workflow for image comparison testing: you render, inspect, and accept the new baseline. Note that both targets depend on build, so running tests requires a working Rust and wasm32 toolchain even though the tests exercise Typst output.
You can also run everything without just installed by reading the justfile, as the README suggests, since each target is a short shell command.
A package with an ecosystem sitting on top of it
The README lists a substantial set of downstream Typst packages built with CeTZ, and they cluster by domain. Diagram types have fletcher for commutative diagrams, chronos for sequence diagrams, rivet for instruction and register diagrams, and plotsy-3d for 3D objects. Circuit and technical drawing has circuiteria, zap for standard electronic circuits, and bone for structural analysis and kinematic diagrams.
Domain-specific uses include finite for rendering finite automata, alchemist for skeletal formulae from a human-readable format, conchord for lyrics with chords and fretboard diagrams, gribouille for the Grammar of Graphics, magic-cubes for Rubik's cubes of arbitrary size, deckz for poker-style playing cards and neural-netz for network architecture diagrams. VisualCeTZ is an adoption of VisualTikZ.
The same organisation maintains two sibling libraries: cetz-plot for plotting and charts, and cetz-venn for two- or three-set Venn diagrams.
That list is the best available evidence about what CeTZ handles well. It is a general drawing substrate that other people have specialised on top of, not a charting package.
Where CeTZ is the wrong choice
For very simple diagrams, compare CeTZ's build requirements with the complexity of the drawing. The WebAssembly core is not free: it is a build toolchain, a wasm artefact and a runtime call boundary. If your drawing never needs intersection, projection or layout computation, you pay for it anyway.
There is also a documentation split to be aware of. The API reference is a manual.pdf generated from Typst source, plus an online manual built by a Python generator from a metadata query. The README itself is examples and install steps, not an API listing. If you are working offline, the PDF is the copy that matters.
Version discipline matters too. Recent tags are v0.5.0 on 2026-04-12, then v0.5.1 and v0.5.2 both on 2026-05-06, so two releases landed on one day and the import string carries a version that must match what the local install produced.
The repository is not archived, the last push was on 2026-09-25, and the licence is LGPL-3.0. For a package intended to be imported by others, review the LGPL-3.0 licence against your distribution model.
Editorial conclusion
Adopt CeTZ for Typst documents that need real geometry, 3D projection or node-based diagrams, and plan for the local install path with git clone --recursive, just and cargo, or take the @preview package which needs neither. Do not adopt it if your diagrams are simple enough for Typst's own drawing primitives, since the WebAssembly core buys you accuracy you would not use. Before pinning a version, check the manual.pdf in the repository against the version you import, since v0.5.2 and v0.5.1 were both tagged on 2026-05-06 and API reference documentation can lag a patch release.
Frequently asked questions
How do I install the CeTZ Typst package locally?
Clone the repository with git clone --recursive, or run git submodule update --init if the --recursive flag was missed, then make sure just and cargo are installed and run just install. Locally installed packages are imported with the @local prefix instead of @preview.
Why does CeTZ require Rust and cargo to build?
The geometry core is a Rust crate compiled with cargo build --release --target wasm32-unknown-unknown, and the resulting cetz_core.wasm is copied into the package. Every justfile target, including tests and the gallery, depends on that build step.
How do I run the CeTZ unit tests?
Run the just test target, which calls tt run with an optional filter. You need tytanic installed with cargo install tytanic and available on your PATH.
Which packages are built on top of CeTZ?
The README lists fletcher for commutative diagrams, chronos for sequence diagrams, circuiteria, zap and bone for circuits and structural diagrams, finite for finite automata, alchemist for skeletal formulae, gribouille and magic-cubes among others. Sibling libraries from the same organisation are cetz-plot and cetz-venn.
Where can I find the CeTZ API reference?
The API reference is a manual.pdf in the repository, generated by compiling manual.typ with typst compile. An online manual is published at cetz-package.github.io/docs, generated from the same Typst source through docs/genhtml.py.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/cetz-package-cetz)Was this useful?