Skip to content

EN:Development

谢耳朵 edited this page Feb 1, 2026 · 3 revisions

English | 中文版

Development Documentation

This document summarizes the core design philosophy, modular architecture, and the complete development workflow for the luatex-cn typesetting engine.

1. Core Architecture: Three-Layer Design

luatex-cn utilizes a three-layer architecture to decouple layout logic from rendering:

  1. LaTeX Interface Layer (.sty, .cls): Defines user commands; sets attributes and parameters via luatexbase.
  2. Coordination Layer (core_*.lua): Manages logic flow. For instance, core_main orchestrates the main process, while core_textflow handles interlinear note splitting.
  3. Processing Layer (layout_*.lua, render_*.lua):
    • Flattening: Converts TeX node lists into linear Lua tables.
    • Layout: Calculates grid coordinates for each character and its associated elements.
    • Rendering: Reassembles content based on coordinates and outputs PDF instructions.

Module Directory Structure (v0.2.0+)

tex/
├── core/              # Core vertical engine (26 files)
├── guji/              # Ancient book specific features (6 files)
├── banxin/            # Page center system (5 files)
├── splitpage/         # Tube page splitting (2 files)
├── fonts/             # Font auto-detection
├── util/              # Utility modules (including style registry)
├── decorate/          # Text decoration
├── debug/             # Debug tools
└── configs/           # Preset configuration files

Plugin System (v0.2.0+)

v0.2.0 introduced a standardized plugin API where each module implements a three-phase interface:

plugin = {
  initialize = function(params, engine_ctx) end,  -- Initialization
  layout = function(list, layout_map, engine_ctx, context) end,  -- Layout
  render = function(head, layout_map, params, context, ...) end   -- Rendering
}

Style Registry (v0.2.1+)

luatex-cn-style-registry.lua provides multi-attribute style storage:

-- Register a style, returns unique ID
local style_id = style_registry.register({
  color = {1, 0, 0},
  font_size = 19,
  grid_height = 20
})

-- Retrieve style by ID
local style = style_registry.get(style_id)

Supported attributes: color, font_size, grid_height, font, etc.

2. Participating in Development

We welcome contributions and Pull Requests (PRs).

2.1 Fork & Workflow

  1. Fork the Repo: Click the Fork button on GitHub.
  2. Clone: Clone your forked repository locally.
  3. Coding: Main source code is located in the tex/ directory.

Tip

VS Code with LaTeX Workshop is recommended for development.

2.2 Testing

Please ensure all tests pass before submitting a PR.

  1. Install Dependencies: You need l3build installed.

  2. Unit Tests: Run Lua unit tests:

    l3build test

    This invokes test/run_all.lua.

  3. Regression Tests: We use automated regression testing based on PDF rendering comparison to prevent layout regressions.

    l3build check

    This compiles .lvt files in testfiles/ and compares the output logs (.tlg) against baselines. If your changes affect layout, ensure these pass. If layout changes are intentional, update baselines:

    l3build save test-name

2.3 Release

For release procedures, please refer to Release.

3. Key Technical Details

Vertical Direction (RTT)

Leverages LuaTeX's dir RTT attribute. In RTT mode, text flows top-to-bottom, and lines stack right-to-left.

Attribute Management

Uses LuaTeX attributes to pass metadata across languages (e.g., "this glyph belongs to an interlinear note").

Warning

\selectfont clears all active attributes. Ensure attributes are reset AFTER setting the font size.

Node Ownership

Passing nodes to TeX via tex.box[n] = node transfers ownership. Use node.copy_list() if you need to reuse nodes.

4. Development Lessons (LEARNING)

  • Color Commands: Must use normalized RGB (e.g., 0 0 0 rg), not names.
  • Rendering Order: PDF follows the "painter's model"—later content overlays earlier content. Insert backgrounds at the head of the list to ensure they are at the bottom.
  • Module Loading: Standardize on require() and utilize package.loaded for caching.

Clone this wiki locally