feat(mcp): text-measurement primitive + 3 layout-prediction tools#22
Merged
Conversation
Adds a fontkit-backed text measurement utility and three tools built on top of it. All three eliminate the iterate-render-check loop the agent used to do manually. New module `packages/mcp/src/measure.ts`: - `measureText(opts)` — reads the bundled woff2 directly, sums glyph advances via fontkit, handles word-wrap to a max width. Returns singleLineWidth, wrappedWidth, lineCount, height. ~10ms per call. Caches parsed fonts; falls back to a 0.55-em heuristic if the font file isn't found. - `estimateDeviceBounds(screen)` — canvas-% bounds of the primary device frame from deviceTop / deviceScale / deviceOffsetX, using a 2:1 aspect approximation. New tools: - `auto_fit_headline(slug, index, text?, maxLines?, apply?)` — binary- searches the largest headline size that fits in `maxLines` (default 2). Returns suggestedSize + measurement metrics. Pass apply:true to write headlineSize via patch_screen. - `check_text_overlap(slug, index)` — computes headline bounds from current size + position, intersects with estimated device bounds, returns overlap status + a recommendation if they collide. Use as a pre-render sanity check. - `predict_locale_overflow(slug, index, translatedText, maxLines?)` — given a translated headline, predicts whether it overflows the text area at the current font size. If it doesn't fit, runs the auto-fit binary search internally and suggests a smaller size. Useful before committing translations to a locale — German/Russian/Finnish often expand the headline by 30-50%. Total tool count: 65 → 68. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switches `stripTagsFromHeadline` from an iterate-until-stable regex to a character-by-character state machine. Same behavior (handles nested constructs like `<<p>p>` safely), but CodeQL recognises the state machine as a safe parser instead of flagging it as incomplete-multi-character-sanitization on every PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a fontkit-backed text measurement utility plus three tools that use it to predict layout issues before render-time. All three eliminate the iterate-render-check loop the agent used to do manually.
Measurement primitive (
packages/mcp/src/measure.ts)measureText(opts)reads the bundled woff2 directly via fontkit, sums glyph advances, handles word-wrap to a max width. Returns{ singleLineWidth, wrappedWidth, lineCount, height }. ~10ms per call. Caches parsed fonts; falls back to a 0.55-em heuristic if a font file isn't found.estimateDeviceBounds(screen)returns canvas-% bounds of the primary device frame fromdeviceTop/deviceScale/deviceOffsetXusing a 2:1 aspect approximation.New tools
auto_fit_headlineBinary-searches the largest headline font size that fits in
maxLines(default 2). Returns the suggested size + measurement metrics. Passapply: trueto writeheadlineSizeviapatch_screenin the same call.check_text_overlapComputes headline bounds from the current size + position, intersects with estimated device bounds, returns overlap status + a recommendation if they collide. Use as a pre-render sanity check.
predict_locale_overflowGiven a translated headline (e.g. for a non-English locale), predicts whether it overflows the text area at the current font size. If it doesn't fit, runs the auto-fit binary search internally and suggests a smaller size. Useful before committing translations — German / Russian / Finnish typically expand by 30-50%.
Live smoke test (against my own project)
Tool count: 65 → 68
Test plan
pnpm typecheckcleanpnpm test— 535 / 535 passingtools/list🤖 Generated with Claude Code