This page explains how to set up Chinese typography with CTyp 0.3.1 and how to draw a diagram with CeTZ 0.5.2. The old one-off CJK rules remain at the end as legacy snippets.
All examples on this page are compile-tested with Typst 0.15.1. The package versions are also pinned so that the examples stay reproducible. CTyp 0.3.1 requires Typst 0.14.1 or newer, while CeTZ 0.5.2 requires Typst 0.14.0 or newer.
Table of Contents
Open Table of Contents
Set up Chinese typography with CTyp
CTyp provides a document-wide Chinese typesetting setup. In addition to selecting CJK fonts, it sets the document language to Chinese, justifies paragraphs, adds a two-em first-line indent, fixes list-marker alignment, and removes unwanted spaces between CJK characters split across source lines.
Check Typst and the fonts first
Typst downloads a @preview package automatically when it first sees the
import. CTyp does not bundle the fonts themselves, so check what the compiler
can see before choosing a font preset:
typst --version
typst fonts
The first command should report typst 0.15.1. If it reports an older
version, update the CLI before using these examples.
Use the exact family names printed by typst fonts when defining a custom
font set. The two most useful built-in CTyp presets are:
fandol, the default, which expectsFandolSong,FandolHei,FandolKai, andFandolFang Rto be installed.noto, a good choice in the Typst web app or on a local machine withNoto Serif CJK SCandNoto Sans CJK SCinstalled.
CTyp also includes source, windows, fangzheng, and huawen presets, but
those work only when their corresponding fonts are available to Typst.
Recommended local setup with Fandol
If all four Fandol families are available, the default configuration is the shortest setup:
#import "@preview/ctyp:0.3.1": ctyp
#let (ctypset, cjk) = ctyp()
#show: ctypset
= 中文标题
这是正文。CTyp 会应用中文字体、两字宽首行缩进和其他基础排版规则。
#(cjk.hei)[这里显式使用黑体。]
ctyp() returns two values. ctypset is the show rule that applies the
document theme; cjk is a dictionary of helpers such as song, hei,
kai, and fang, depending on the selected font set. A helper stored in a
dictionary must be called as #(cjk.hei)[...], with parentheses around the
field access.
Place #show: ctypset after the CTyp configuration and before the document
body that should receive it.
Typst web app or local Noto setup
CTyp 0.3.1 adds title-font support, but its released Noto preset omits the
required title mapping. This remains necessary with Typst 0.15.1. Without
the override below, the preset fails with
dictionary does not contain key "title". This setup supplies the missing
mapping and also shows optional Latin fonts and heading numbering:
#import "@preview/ctyp:0.3.1": ctyp
#let (ctypset, cjk) = ctyp(
fontset-cjk: "noto",
font-latin: (
serif: "Libertinus Serif",
mono: "DejaVu Sans Mono",
),
font-cjk-map: (
title: (cjk: "song:bold", latin: "serif"),
),
heading-numbering: "1.1",
)
#show: ctypset
#set document(title: [中文文档])
= 第一章
正文使用 Noto Serif CJK SC,*粗体*使用 Noto Sans CJK SC。
The other non-Fandol presets in CTyp 0.3.1 also lack a title entry. Apply a
matching font-cjk-map.title override when using one of them. Remove the
workaround after upgrading only when the newer preset defines that mapping.
CTyp improves common Chinese layouts, but it is not a complete implementation of every Chinese typesetting rule. Keep document-specific adjustments close to your template instead of assuming that the package handles every edge case.
Draw diagrams with CeTZ
The package is spelled CeTZ and imported as cetz; ctez is a common
transposition. CeTZ provides a drawing canvas with an API inspired by TikZ and
Processing.
Start with a scoped canvas
Use the package namespace for the canvas, then import drawing functions only inside its code block:
#import "@preview/cetz:0.5.2"
#cetz.canvas({
import cetz.draw: *
circle((0, 0))
line((0, 0), (2, 1))
})
Keeping import cetz.draw: * inside the canvas matters because CeTZ exports
names such as line that would otherwise shadow Typst’s built-in functions.
The canvas grows to fit its drawing. By default, one coordinate unit is one
centimetre, the x-axis points right, and the y-axis points up. Pass length:
to cetz.canvas when a different scale is needed.
Connect named elements with anchors
For diagrams that may change, name elements and connect their anchors instead of hard-coding every line endpoint:
#import "@preview/cetz:0.5.2"
#cetz.canvas({
import cetz.draw: *
set-style(content: (
frame: "rect",
padding: .18,
fill: rgb("e8f0fe"),
stroke: rgb("2457c5"),
))
content((0, 0), [Typst], name: "source")
content((3, 0), [PDF], name: "output")
line("source.east", "output.west", mark: (end: ">"))
})
Here, content creates two framed nodes, source.east and output.west
refer to their border anchors, and mark: (end: ">") adds the arrowhead.
set-style supplies defaults for later elements; arguments passed directly to
a drawing function override those defaults.
For more complex work, use the CeTZ manual
for coordinate systems, anchors, marks, transformations, and reusable styles.
Use a focused library such as cetz-plot for plots rather than rebuilding a
charting layer from primitives.
Legacy manual CJK snippets
These small rules predate CTyp. They are still useful when adding a package is unnecessary, but they cover only one concern each and do not form a complete Chinese typesetting setup.
Set a font for Han characters
This show rule applies a Simplified Chinese Noto serif font to runs of Han
characters. The named font must be visible in typst fonts.
#show regex("\p{sc=Hani}+"): set text(lang: "zh", font: "Noto Serif CJK SC")
Indent paragraphs by two CJK character widths
Measuring two representative CJK characters is more robust than hard-coding a point value because the indent follows the active font and size:
#context {
let indent-width = measure("空格").width
set par(first-line-indent: indent-width)
// Content goes here.
}
Prefer CTyp for a Chinese document-wide baseline. Keep these legacy snippets for isolated content or for templates that intentionally manage every other typographic rule themselves.