A MetaPost-like approach to running a pen along a path — for Typst 0.15+.
Français · Manual (EN) · Manuel (FR) · Gallery · Changelog
nibart brings the heart of Metafont/MetaPost to Typst: smooth paths described with Hobby’s algorithm (directions, tensions, curls),
and pens — circle, ellipse, broad-edged nib, polygon, or a nib that changes width and angle along the stroke — whose
exact swept outline is computed for you. Calligraphy, lettering, flourishes, hand-drawn diagrams, technical figures in the
MetaPost tradition: all as plain vector shapes.

Installation
From Typst Universe there is nothing to install: #import "@preview/nibart:0.3.0" as nib.
Quick start
#import "@preview/nibart:0.3.0" as nib
// a path in MetaPost syntax, a broad-edged pen
#nib.nib-stroke(
nib.mp-path("(0,0){up}..(25,45)..(60,10)..(95,50)"),
pen: nib.broadnib(10pt, t: 2.5pt, angle: 35deg),
)
// a nib whose width changes along the stroke, and that follows the path
#nib.nib-stroke(
nib.mp-path("(0,0)..(30,40)..(60,0)..(90,40)"),
pen: nib.nibpen(
(at: 0%, width: 3pt), (at: 50%, width: 14pt, thinness: 40%), (at: 100%, width: 3pt),
angle: 40deg,
),
fill: rgb("#7a2e0e"),
)
The axes follow MetaPost (y points up, angles are counter-clockwise). Use nib.xxx rather than import "…": *:
the package exports generic names (draw, cubic, reverse, pressure…).
Features
- Path language —
mp-path("(0,0){up}..tension 1.5..(40,20)--cycle"):..,--,{dir},{curl},tension,controls,cycle; alsomp-path-pts,cubic,straight,polyline,cubics,path-join. - Hobby’s algorithm, checked against
mpost(same control points, max difference < 0.01 pt on 17 test paths). - Pens —
pencircle,penellipse,broadnib,penpoly,pensquare,penrazor, andnibpenwith stops along the arc length and an optional follow-the-tangent mode. - Exact outlines — the swept region is computed as real geometry (no stamping), with a union of all overlaps.
- Calligraphic effects — irregular dashes with jitter, intermittent pressure, layered pieces, outlines, a debug view.
- Path operations —
point-of,direction-of,arclength,arctime,subpath,reverse,closest-time,intersection-times,intersection-point, bounding box, and affine transformations (shifted,scaled,rotated,slanted,reflected,transformed…). - Knots and interlace —
knot(...): automatic crossings (also within one strand), alternating over/under, “gap” or Celtic “weave” style, links, braids. - Calligraphic ornaments —
copperplate(pointed pen),prongs(multi-tine nib),delimiter(braces and parentheses between two points). - Path surgery —
offset(parallel curves),shorten,split-at,remove-intervals,weld,join-smooth,round-corners,frames-along… - Figures —
mp-fig(likebeginfig … endfig) with dots, labels, fills, skeletons and an optional grid; baseline-aware, so figures can be used inline.
![]() |
![]() |
![]() |
![]() |
nibart: knots, braces, pointed pen
Trefoil, Olympic and Borromean rings, braids and Celtic interlace; calligraphic braces; a copperplate pen; offsets, rounded corners and frames along a path — examples/nibart.typ (--input lang=en for English captions).

The unexpected
A score with tapered slurs, knots that weave over and under (computed with intersection-times), a neon sign, embroidery,
a fractal cherry tree, a dry-brush enso, an engraved sphere, guilloché, a map and a hand-drawn sketch — one file,
examples/insolite.typ (--input lang=en for English captions).
![]() |
![]() |
![]() |
The complete sources of these pictures are in examples/ (galerie, exotique, boites, calligraphie, insolite, nibart, demo, chat, ile, ile-chat, podium).
In a clone of the repository, compile them with typst compile --root . examples/galerie.typ.
The examples that the manual does not show are gathered, with a preview, a description, the functions they use and their build command, in an illustrated gallery generated with sh scripts/build-gallery.sh && make gallery. Most examples are bilingual: add --input lang=en or --input lang=fr.
Documentation
The reference manual (English and French; every function with its parameters table and a detailed example, all executed by the package itself) is in docs/:
manual-en.pdf, manual-fr.pdf. Rebuild it with
typst compile --root . docs/manual.typ (add --input lang=fr for French).
Limits
- Not implemented:
atleast,&,buildcycle;...behaves as... drawreturns filled shapes;mp-labelcontent is not part of the automatic bounding box.- The geometry lives in a WebAssembly plugin (
nibart.wasm); it works with the Typst CLI and packages from Universe. - Variable pens, dashes and pressure are slower than fixed pens (see the manual for tuning).
Development
The Rust sources of the plugin are in rust/ in the repository (not part of the published package). make wasm rebuilds nibart.wasm
(target wasm32-unknown-unknown), make test runs the tests, make docs rebuilds the manual, make package produces
and validates the publishable directory in dist/.
Licence
Author: FERGOUS Abdelhak (@fergousA) · repository: https://github.com/fergousA/nibart.
MIT. Third-party crates: see THIRD-PARTY-NOTICES.md.
Inspired by MetaPost (D. Knuth, J. D. Hobby) and by the nibst package (B. Auguie): the calligraphic options reproduce
its described behaviour; no code from either project is included.






