You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: DEVELOPMENT.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,6 +34,8 @@ bun install
34
34
-`bun run benchmark-check:safari`
35
35
-`bun run pre-wrap-check` — compact browser oracle for `{ whiteSpace: 'pre-wrap' }`
36
36
-`bun run keep-all-check` — compact browser oracle for `{ wordBreak: 'keep-all' }`, including mixed-script no-space canaries
37
+
-`bun run letter-spacing-check` — compact batched browser oracle for `{ letterSpacing }`, using one posted-report probe per browser and covering narrow wraps, combining marks, bidi, CJK, emoji, digits, RTL punctuation, `pre-wrap`, and soft hyphens
38
+
-`bun run letter-spacing-snapshot` — refresh `accuracy/letter-spacing.json` from the Chrome + Safari compact `{ letterSpacing }` oracle
37
39
-`bun run probe-check` — smaller browser probe/diagnostic entrypoint
38
40
-`bun run probe-check:safari`
39
41
On a first-break mismatch, probe output now includes a small break trace.
@@ -78,6 +80,7 @@ Use these for the current checked-in picture:
78
80
-[STATUS.md](STATUS.md) — short pointer doc for the main browser accuracy + benchmark snapshots
79
81
-[status/dashboard.json](status/dashboard.json) — machine-readable main dashboard
80
82
-[accuracy/chrome.json](accuracy/chrome.json), [accuracy/safari.json](accuracy/safari.json), [accuracy/firefox.json](accuracy/firefox.json) — raw browser accuracy rows
If you want CSS-like `word-break: keep-all`, pass`{ wordBreak: 'keep-all' }` to `prepare()` too.
40
+
Other `prepare()` options are `{ wordBreak: 'keep-all' }` for CSS-like `word-break: keep-all`, and`{ letterSpacing: n }` to match CSS `letter-spacing` (`n` is treated as a px value).
41
41
42
42
The returned height is the crucial last piece for unlocking web UIs:
43
43
- proper virtualization/occlusion without guesstimates & caching
@@ -124,13 +124,13 @@ It is intentionally narrow:
124
124
125
125
Use-case 1 APIs:
126
126
```ts
127
-
prepare(text: string, font: string, options?: { whiteSpace?: 'normal'|'pre-wrap', wordBreak?: 'normal'|'keep-all'}): PreparedText// one-time text analysis + measurement pass, returns an opaque value to pass to `layout()`. Make sure `font` is synced with your css `font` declaration shorthand (e.g. size, weight, style, family) for the text you're measuring. `font` is the same format as what you'd use for `myCanvasContext.font = ...`, e.g. `16px Inter`.
127
+
prepare(text: string, font: string, options?: { whiteSpace?: 'normal'|'pre-wrap', wordBreak?: 'normal'|'keep-all', letterSpacing?: number}): PreparedText// one-time text analysis + measurement pass, returns an opaque value to pass to `layout()`. Make sure `font` and `letterSpacing` are synced with your CSS for the text you're measuring. `font` is the same format as what you'd use for `myCanvasContext.font = ...`, e.g. `16px Inter`; `letterSpacing` is a CSS pixel value.
128
128
layout(prepared: PreparedText, maxWidth: number, lineHeight: number): { height: number, lineCount: number } // calculates text height given a max width and lineHeight. Make sure `lineHeight` is synced with your css `line-height` declaration for the text you're measuring.
129
129
```
130
130
131
131
Use-case 2 APIs:
132
132
```ts
133
-
prepareWithSegments(text: string, font: string, options?: { whiteSpace?: 'normal'|'pre-wrap', wordBreak?: 'normal'|'keep-all' }): PreparedTextWithSegments// same as `prepare()`, but returns a richer structure for manual line layout needs
133
+
prepareWithSegments(text: string, font: string, options?: { whiteSpace?: 'normal'|'pre-wrap', wordBreak?: 'normal'|'keep-all', letterSpacing?: number }): PreparedTextWithSegments// same as `prepare()`, but returns a richer structure for manual line layout needs
134
134
layoutWithLines(prepared: PreparedTextWithSegments, maxWidth: number, lineHeight: number): { height: number, lineCount: number, lines: LayoutLine[] } // high-level api for manual layout needs. Accepts a fixed max width for all lines. Similar to `layout()`'s return, but additionally returns the lines info
135
135
walkLineRanges(prepared: PreparedTextWithSegments, maxWidth: number, onLine: (line:LayoutLineRange) =>void): number// low-level api for manual layout needs. Accepts a fixed max width for all lines. Calls `onLine` once per line with its actual calculated line width and start/end cursors, without building line text strings. Very useful for certain cases where you wanna speculatively test a few width and height boundaries (e.g. binary search a nice width value by repeatedly calling walkLineRanges and checking the line count, and therefore height, is "nice" too). You can have text messages shrinkwrap and balanced text layout this way. After walkLineRanges calls, you'd call layoutWithLines once, with your satisfying max width, to get the actual lines info.
136
136
measureLineStats(prepared: PreparedTextWithSegments, maxWidth: number): { lineCount: number, maxLineWidth: number } // returns only how many lines this width produces, and how wide the widest one is. Avoids line/string allocations.
text:string// raw author text, including leading/trailing collapsible spaces
171
171
font:string// canvas font shorthand for this item
172
+
letterSpacing?:number// extra horizontal spacing between graphemes, in CSS px
172
173
break?:'normal'|'never'// `never` keeps the item atomic, like a chip
173
174
extraWidth?:number// caller-owned horizontal chrome, e.g. padding + border width
174
175
}
@@ -231,11 +232,12 @@ Pretext doesn't try to be a full font rendering engine (yet?). It currently targ
231
232
- `word-break:normal` and `keep-all`
232
233
- `overflow-wrap:break-word`. Very narrow widths can still break inside words, but only at grapheme boundaries.
233
234
- `line-break:auto`
235
+
- `letter-spacing` as a numeric pixel value passed to `prepare()` / `prepareWithSegments()`
234
236
- Tabs follow the default browser-style `tab-size:8`
235
237
- `{ wordBreak:'keep-all' }` is supported too. It behaves like you'd expect for CJK/Hangul text, while keeping the same `overflow-wrap:break-word` fallback for overlong runs.
236
238
- `system-ui` is unsafe for `layout()` accuracy on macOS. Use a named font.
237
239
- Runtime requires `Intl.Segmenter` and Canvas 2D text measurement. Browsers or runtimes without `Intl.Segmenter` are currently unsupported.
238
-
- CSS text features outside the canvas `font` shorthand, such as `letter-spacing`, `font-optical-sizing`, `font-feature-settings`, and standalone `font-variation-settings`, are not modeled separately. Variable-font axes only help when the active axis is reflected in the canvas font string, for example via weight.
240
+
- CSS text features outside the canvas `font` shorthand, such as `font-optical-sizing`, `font-feature-settings`, and standalone `font-variation-settings`, are not modeled separately. Variable-font axes only help when the active axis is reflected in the canvas font string, for example via weight.
0 commit comments