Consketcher
April 30, 2026 · View on GitHub
Consketcher is a Typst package for drawing control-system sketches with fletcher.
It provides:
- ready-to-use block and control-system templates
- reusable nodes, labels, junctions, and edge helpers
- small utilities for Chinese labels and automatic spacing
Installation
If you are using a published release, import it from @preview:
#import "@preview/consketcher:0.2.0": *
For local development, import it from @local:
#import "@local/consketcher:0.1.0": *
Quick Start
Open-loop block
#block-open(
transfer: $G(s)$,
input: $R(s)$,
output: $Y(s)$,
)
Closed-loop block
#block-closed(
transfer: $D(s)G(s)$,
transfer2: $H(s)$,
input: $V(s)-X(s)H(s)$,
output: $X(s)$,
output2: $X(s)H(s)$,
loss: "Loss",
reference: $V(s)$,
)
Closed-loop control system
#sys-closed(
controler: ctext("控制器"),
actuator: ctext("执行器"),
sensor: ctext("传感器"),
input: ctext("指令信号"),
output: ctext("执行信号"),
output2: ctext("传感信号"),
loss: ctext("损失函数"),
reference: ctext("校正信号"),
)


For complete examples, see examples/example.typ.
API Overview
Consketcher exports everything from 0.1.0/src/lib.typ.
The public API is organized into a few focused modules:
src/charts.typ: high-level block and control-system templatessrc/nodes.typ: nodes, labels, references, and marker helperssrc/edges.typ: connectors, arrows, and feedback pathssrc/utils.typ: text helpers and automatic spacing utilitiessrc/components.typ: compatibility barrel that re-exportsnodes.typandedges.typ
In other words, lib.typ is the entrypoint, charts.typ is where the
ready-made diagrams live, and the lower-level drawing primitives are split by
responsibility into nodes.typ and edges.typ.
Diagram Templates
These are the highest-level entry points.
#block-open(
transfer: none,
input: none,
output: none,
width: 2,
height: 2em,
line: -2,
start: 1,
node-maker: rnode,
edge-maker: arrow,
)
#block-closed(
transfer: none,
transfer2: none,
input: none,
output: none,
output2: none,
loss: none,
reference: none,
line: 0.5,
start: 1,
reference-gap: auto,
input-gap: auto,
feedback-height: 1.25,
label-size: 0.6em,
node-maker: rnode,
ref-maker: reference,
edge-maker: arrow,
feedback-edge-maker: uturn-v,
)
#sys-open(
controler: none,
actuator: none,
process: none,
input: none,
output: none,
output2: none,
output3: none,
subunit: none,
line: -2,
start: -2,
node-maker: rnode,
edge-maker: arrow,
boundary-edge-maker: uturn,
label-maker: label,
)
#sys-closed(
controler: none,
actuator: none,
sensor: none,
input: none,
output: none,
output2: none,
loss: none,
reference: none,
line: 0.5,
start: 1,
feedback-height: 1.25,
node-maker: rnode,
ref-maker: reference,
edge-maker: arrow,
)
Legacy high-level helpers are also exported:
#closed-loop-block(plant)
#compensated-loop-block(
first,
second,
third,
first-width: 5em,
second-width: 2em,
third-width: 6em,
)
Layout and Text Utilities
#control-diagram(
spacing: (1.5em, 1.5em),
node-stroke: 1pt,
mark-scale: 80%,
..body,
)
#ctext(label, size: 0.8em, font: "Songti SC", ..options)
#edge-label(body, size: 0.6em, ..options)
#label-length(body, fallback: 1)
#auto-gap(body, scale: 1, fallback: 1)
ctext is a convenience wrapper around text(...) with a Chinese-friendly
default font. label-length and auto-gap are useful when you want custom
diagram templates to adapt spacing to label content.
Nodes and Markers
#rnode(sym, label, shape: rect, height: 2em, corner-radius: 4pt, ..options)
#onode(sym, label, shape: circle, height: 1em, radius: 10pt, ..options)
#gain-node(
sym,
label,
dir: left,
width: 4em,
height: 4em,
fit: 0.8,
..options,
)
#formula-node(sym, body, width: 8em, height: 3em, ..options)
#label(sym, body, stroke: none, ..options)
#signed-node(
sym,
signs: (),
node-maker: onode,
label-maker: label,
..node-options,
)
#reference(
sym,
x-sign: "+",
y-sign: "-",
x-offset: -0.3,
y-offset: 0.3,
loss: none,
loss-offset: -0.5,
..options,
)
#reference3(
sym,
x: "+",
top: "+",
bottom: "+",
x-offset: -0.25,
top-offset: -0.25,
bottom-offset: 0.25,
radius: 1.35em,
node-maker: onode,
label-maker: label,
..node-options,
)
#dashed-box(
enclose,
stroke: (thickness: 0.5pt, dash: "dashed"),
inset: 1.5em,
fill: none,
corner-radius: 4pt,
..options,
)
Edges
#connector(
n1,
n2,
marks: "-",
label: none,
label-pos: 0.5,
label-side: left,
corner: none,
corner-radius: 4pt,
..options,
)
#arrow(
n1,
n2,
label,
marks: none,
label-pos: 0.5,
label-side: left,
dashed: false,
corner: none,
corner-radius: none,
..options,
)
#segment(
n1,
n2,
label,
marks: none,
label-pos: 0.5,
label-side: left,
dashed: false,
corner: none,
corner-radius: none,
..options,
)
#uturn(
n1,
n2,
label,
label-pos: 0.15,
label-side: left,
marks: "-|>",
height: 1.25,
corner: right,
corner-radius: 4pt,
..options,
)
#uturn2(
n1,
n2,
label,
label-pos: 0.15,
label-side: left,
marks: "-|>",
height: 1.25,
corner: right,
corner-radius: 4pt,
offset: 1,
..options,
)
#uturn-v(
n1,
n2,
label,
label-pos: 0.15,
label-side: left,
marks: "-|>",
height: 2.5,
corner: right,
corner-radius: 4pt,
..options,
)
#uturn2-v(
n1,
n2,
label,
label-pos: 0.15,
label-side: left,
marks: "-|>",
height: 2.5,
corner: right,
corner-radius: 4pt,
offset: 1,
..options,
)
Customization
The template functions are composable. You can pass custom maker functions to change how nodes, references, or edges are drawn. This is the main extension point when you want the built-in layouts but different visual styling.
#let thick-arrow(n1, n2, body, ..options) = arrow(
n1,
n2,
body,
stroke: 1.5pt,
..options,
)
#block-open(
transfer: $G(s)$,
input: $u$,
output: $y$,
edge-maker: thick-arrow,
)
For closed-loop diagrams, you can also replace the summing-junction maker
through ref-maker.
Repository Layout
0.1.0/src/lib.typ: package entrypoint and export hub0.1.0/src/charts.typ: ready-made block and control-system templates0.1.0/src/components.typ: compatibility barrel that re-exports drawing helpers0.1.0/src/nodes.typ: nodes, labels, references, and marker helpers0.1.0/src/edges.typ: connectors, arrows, and feedback paths0.1.0/src/utils.typ: text helpers and spacing helpersexamples/example.typ: usage examplesexamples/example.pngandexamples/example2.png: rendered example previewsarticles/lib.pdf: generated API reference preview
Local Development
To use the package from @local, clone the repository into your local Typst
package workspace:
- Linux:
$XDG_DATA_HOME/typst/packages/local~/.local/share/typst/packages/local
- macOS:
~/Library/Application Support/typst/packages/local - Windows:
%APPDATA%/typst/packages/local
Then clone the repository as consketcher:
git clone https://github.com/ivaquero/typst-consketcher consketcher
and import it with:
#import "@local/consketcher:0.1.0": *
If you are editing the package itself, the most common workflow is:
- Put new reusable graph primitives in
nodes.typoredges.typ. - Put new ready-made control-diagram layouts in
charts.typ. - Re-export only stable public entry points through
lib.typ. - Keep
components.typas a compatibility layer instead of growing it with new logic.