Skip to content

Expose baseline through measure - #8799

Open
hooyuser wants to merge 1 commit into
typst:mainfrom
hooyuser:measure-baseline
Open

hooyuser wants to merge 1 commit into
typst:mainfrom
hooyuser:measure-baseline

Conversation

@hooyuser

@hooyuser hooyuser commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Adds an opt-in baseline parameter to measure().

When baseline: true is set, the returned dictionary includes the content's baseline offset measured from its top edge. The baseline parameter is set to false by default, so existing results are unchanged.


Update: Following maintainer feedback, the PR now always includes baseline in the
returned dictionary.

Closes #8798.

@MDLC01

MDLC01 commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

The baseline boolean parameter has the advantage of ensuring full backward compatibility, in particular with users who wrote let (width, height) = measure(..). Appart from this concern, however, it seems a bit pointless to have to pass an additional argument to get the baseline measurement, instead of always returning it.

@hooyuser

hooyuser commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Agreed, backward compatibility seems like the main argument for it.

Just a small detail on let (width, height) = measure(..). Since measure() returns a dict, adding a new key shouldn't actually break destructuring. The place it would break existing code is something like rect(..measure(body)). Personally I rarely write code like that, though.

@isuffix isuffix added text Related to the text category, which is all about text handling, shaping, etc. introspection Related to the introspection category labels Aug 29, 2026
@uwni

uwni commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Considering that typst is still pre v1.0 and unstable. Backward compatibility is not actually necessary and guaranteed. Breaking changes are acceptable in my opinion, and have already happened many times in the release history.

@saecki saecki added the waiting-on-decision A decision must be made to proceed. label Sep 3, 2026
@laurmaedje

Copy link
Copy Markdown
Member

Let's remove the parameter. The breakage is small enough.

@laurmaedje

Copy link
Copy Markdown
Member

One thing is that box.baseline (or more precisely box.baseline.shift) measures from the bottom rather than the top by default and, in particular, positive values go upwards ... so this would be a bit inconsistent. Measuring from the top is how Typst usually works, but measuring from the bottom has the nice effect that "no baseline" = 0pt and not the height.

I'm honestly not sure what's best here.

@laurmaedje

Copy link
Copy Markdown
Member

If we think inverting the direction for box.baseline would be the way to go, that would be another use case for the upcoming compatibility behavior. But I'm not sure we want to do that as common use cases of box.baseline (like box(image(..), baseline: ..)) would then require a negative number, which might be confusing.

@hooyuser

hooyuser commented Sep 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the feedback! I've removed the baseline argument, so measure() now always returns the baseline.

On the direction convention, one way I think about it is that the two APIs are exposing slightly different kinds of quantities. measure().baseline would be a position in the frame's local coordinate system: the top edge is y = 0, positive y points downwards, and the baseline value is simply its y coordinate.

box.baseline.shift, on the other hand, is a displacement parameter. In that same coordinate system, a positive shift intentionally corresponds to a negative y displacement, i.e. it moves the baseline upwards. That seems like a useful API convention especially for the common cases you mentioned, such as content without a natural baseline: the default baseline starts at the bottom, so raising it by 50% can be written as baseline: 50% rather than -50%.

If we take this perspective, the underlying coordinate convention can still be viewed as consistent, and the difference is just between exposing a position and specifying a shift.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

introspection Related to the introspection category text Related to the text category, which is all about text handling, shaping, etc. waiting-on-decision A decision must be made to proceed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose baseline through measure()

6 participants