A data-driven Chinese poetry reader for Typst. It provides A4/A5/A6 page profiles, one- or two-column layouts, pinyin ruby annotations, short notes under each poem, chapter covers, a table of contents, and optional appendix pages for poet biographies, famous lines, and an author index.
The package contains the layout engine and a small public-domain example. It does not bundle a poetry corpus, curriculum, school logo, or other institution-specific data. You provide the content as a Typst dictionary or a JSON file.
Quick start
Create a project from the template:
typst init @preview/shiyin-reader:0.1.0 my-poetry-book
cd my-poetry-book
typst compile main.typ
Or import the package directly:
#import "@preview/shiyin-reader:0.1.0": poem-book
#let book = json("book.json")
#show: poem-book.with(book: book)
Data model
Book dictionary
| Key | Type | Required | Description |
|---|---|---|---|
metadata |
dictionary | yes | Title and edition information. |
format |
dictionary | yes | Page size, columns, type sizes, and leading. |
notes |
dictionary | yes | Note mode. Currently mode: "short". |
fonts |
dictionary | yes | Body and title font fallback lists. |
chapters |
array | yes | Chapters, each containing poems. |
branding |
dictionary | no | Optional school or organization branding. |
features |
dictionary | no | Optional appendix pages; all default to false. |
front-matter |
dictionary | no | Preface text. Required when features.front-matter is true. |
appendix |
dictionary | no | Data for the optional appendix pages. |
metadata
| Key | Type | Description |
|---|---|---|
title |
string | Book title (required). |
volume |
string | Volume or grade label. |
edition |
string | Edition year or label. |
author |
string | Document author. Defaults to the book title. |
cover-mode |
"general" or "personal" |
personal adds name and class fields to the cover. |
student-name, class-name |
string | Values used in personal mode. |
review-mode |
boolean | Show a review label on the title page. |
review-label |
string | Review label text. Defaults to 审核稿. |
format
| Key | Type | Description |
|---|---|---|
paper |
"a4", "a5", "a6" |
Page size. |
columns |
1 or 2 |
Column count. |
gutter-pt |
number | Column gutter in points. |
body-size |
number | Body text size in points. |
leading |
number | Paragraph leading multiplier. |
note-size |
number | Note text size in points. |
title-size, title-pinyin-size, author-size, author-pinyin-size, pinyin-size |
number | Optional pinyin-mode overrides. |
notes
notes: (mode: "short")
"short" renders numbered notes under each poem. Other values render no notes; footnote rendering is not implemented yet.
branding
All fields are optional. The cover and back cover hide empty branding blocks automatically.
| Key | Type | Description |
|---|---|---|
school-name |
string | School or organization name. |
school-name-en |
string | Secondary name, usually English. |
slogan |
string | Cover and back-cover slogan. |
motto |
string | Vertical motto on the back cover. |
cover-lines |
array of strings or string | Lines shown in the middle of the cover in general mode. |
logo |
string or image | Logo image. Typst callers can pass image("logo.svg"), which resolves in their project. JSON callers pass a path string, resolved from the package file; use an absolute path or the asset-root prefix. |
end-motto |
string | Ending-page motto. Defaults to 诗心常在 书香长伴. |
features
| Key | Default | Description |
|---|---|---|
front-matter |
false |
Render the preface page. |
famous-lines |
false |
Render the famous-lines appendix. |
poet-bio |
false |
Render the poet biographies appendix. |
author-index |
false |
Render the author index. |
end-page |
false |
Render the closing page. |
back-cover |
false |
Render the back cover. |
front-matter
front-matter: (
title: "卷首语",
preface: "Plain-text preface.",
paragraphs: (
"First paragraph.",
"Second paragraph.",
),
)
paragraphs is what gets rendered. preface is optional metadata kept for convenience.
appendix
appendix: (
famous-lines: (
(quote: "春眠不觉晓,处处闻啼鸟。", source: "孟浩然《春晓》"),
),
poet-heading: "【诗人简介】",
poets: (
(group: "唐", name: "孟浩然", years: "689—740", bio: "唐代诗人,襄阳人。"),
),
author-index: (
(
initial: "M",
name: "孟浩然",
dynasty: "唐",
poems: ((title: "春晓", poem-id: "chunxiao"),),
),
),
)
Every poem referenced from author-index must have a matching poem-id in the chapter data so its page reference can be resolved.
chapters and poems
chapters: (
(
name: "第一编 春晓",
subname: "五言绝句",
bg-color: "#E65100",
poems: (
(
number: 1,
poem-id: "chunxiao",
title: "春晓",
author: "(唐)孟浩然",
lines: ("春眠不觉晓,处处闻啼鸟。", "夜来风雨声,花落知多少。"),
notes: (
(headword: "晓", text: "天刚亮的时候。"),
(headword: "闻", text: "听见。"),
),
),
),
),
)
poem-idis optional, but it is required for pinyin annotations and author-index page references.notesis required; use()when a poem has no notes.topicandsubtopicare optional grouping headings within a chapter.
Pinyin annotations
Pinyin data is passed separately:
#let pinyin = json("pinyin.json")
#show: poem-book.with(
book: book,
pinyin: pinyin,
pinyin-mode: true,
)
pinyin-mode forces a single column and larger type. The JSON shape is:
{
"version": 1,
"poem-count": 1,
"poems": {
"jingyesi": {
"title": [["静", "jìng"], ["夜", "yè"], ["思", "sī"]],
"author": [["李", "lǐ"], ["白", "bái"]],
"lines": [
[["床", "chuáng"], ["前", "qián"], ["明", "míng"], ["月", "yuè"]],
[["疑", "yí"], ["是", "shì"], ["地", "dì"], ["上", "shàng"], ["霜", "shuāng"]]
]
}
}
}
Each title, author, and line is an array of [hanzi, pinyin] pairs. The key under poems must match the poem’s poem-id.
poem-book parameters
| Parameter | Default | Description |
|---|---|---|
book |
required | Book dictionary. |
format |
none |
Override book.format. |
notes |
none |
Override book.notes. |
fonts |
none |
Override book.fonts. |
features |
(:) |
Override book.features. |
cover-mode |
none |
Override metadata.cover-mode. |
asset-root |
"" |
Prefix for branding.logo. |
pinyin |
none |
Pinyin dictionary. |
pinyin-mode |
false |
Enable ruby annotations and single-column layout. |
Page profiles
| Paper | Margins (left/right/top/bottom) | Status |
|---|---|---|
| A4 | 22/20/21/20 mm | Production target. |
| A5 | 20/17/19/18 mm | Supported; visual acceptance is still in progress. |
| A6 | 18/14/16/15 mm | Supported; visual acceptance is still in progress. |
Fonts
The template uses Noto Serif CJK SC for body text and STKaiti or KaiTi for titles, with Noto Serif CJK SC as the final fallback. Install a CJK font before compiling. On Debian/Ubuntu, install fonts-noto-cjk; on macOS and Windows, the system KaiTi/STKaiti fonts can be used. If a font is unavailable, Typst falls back to another installed font and emits a warning.
Template contents
The template ships with four public-domain poems (春晓, 静夜思, 登鹳雀楼, 咏鹅) and neutral example data. Replace the chapters, appendix, and front-matter entries with your own content. No real school name, logo, or curriculum is included.
License
MIT. See LICENSE.