typst / typst/typst

Expose baseline through `measure()`

Open
#8,798 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature request introspection text
Dominant language
Rust
Stars
56.1k
Forks
1.7k
Avg merge
3d 10h
Merged PRs (30d)
22

Description

Motivation

Diagramming packages like CeTZ and Fletcher need to align text and equation nodes along their baselines. To get this working properly, they need access to the vertical offset from the top of the content frame to its baseline.

#8150 laid the foundation for this by implementing baseline tracking and propagation in frames. Currently, the laid-out frame already carries correct baseline information, but measure does not expose it, so there is no clean way to access it.

To address this, I propose extending measure() to return the frame's baseline alongside width and height.

API design
Option 1: Opt-in baseline measurement

A backwards-compatible design would be to add a parameter such as:

measure(
  width: auto,
  height: auto,
  baseline: false,
  content,
) -> dictionary

With baseline: false, measure would behave exactly as it currently does and return only:

(width: ..., height: ...)

With baseline: true, it would additionally return the baseline:

(width: ..., height: ..., baseline: ...)
Option 2: Always return the baseline

The simpler API would be for measure to always return:

(width: ..., height: ..., baseline: ...)

Conceptually, I find this quite natural. However, this is not completely backward-compatible. For example, existing code like rect(..measure(body)) may not work anymore. (Note that code like let (width, height) = measure(..) won't break, since Typst allows ignoring extra keys when destructuring a dictionary.)

Use Case

CeTZ and Fletcher need to align text and equation along their baselines. This has come up in several downstream discussions (e.g., cetz-package/cetz#683, cetz-package/cetz#794, and Jollywatt/typst-fletcher#44), where getting a proper baseline alignment is currently impossible or requires verbose workarounds.

Initial implementation

I put together an initial implementation in #8799 following Option 1 to keep it backward-compatible. I don't have a strong preference between the two designs, though. Happy to adjust based on what maintainers prefer.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the baseline tracking work in #8150 and the initial implementation in #8799, then inspect the existing measure() API. Determine which API design maintainers want to support and how its compatibility implications are handled. The work is done when measure() exposes the frame baseline in the accepted form for downstream alignment use cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend-api-design, compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.