Skip to content

feat: infer and apply CSS letter-spacing - #65

Merged
gkurt merged 3 commits into
mainfrom
feat/letter-spacing
Jul 11, 2026
Merged

feat: infer and apply CSS letter-spacing#65
gkurt merged 3 commits into
mainfrom
feat/letter-spacing

Conversation

@gkurt

@gkurt gkurt commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Closes #62

What

Adds first-class letter-spacing support to the tegaki renderer, plus a Studio slider to control it.

Many of the handwritten fonts ship tracked out quite wide (the issue's motivation), and there was no way to tighten or loosen the spacing. Now the component infers letter-spacing from CSS — the same way it already picks up font-size, line-height, and color — and applies it to the rendered strokes.

How

Renderer (tegaki)

  • The engine reads letter-spacing from the container's computed style in _measure(), and re-measures reactively when it changes (the hidden sentinel now inherits letter-spacing and transitions on it, matching the existing font-size/line-height/color mechanism). It's added to the layout-cache key so a spacing-only change forces a re-layout.
  • Shaper path: spacing is inserted between clusters during the pen-walk in applyShaperPositions, so it accumulates just like the browser applied it to the overlay used for line-breaking.
  • Char-keyed fallback path: no code needed beyond cache invalidation — offsets come from the DOM overlay, which inherits letter-spacing via CSS.
  • The headless textToSvg export gained a matching letterSpacing option.

Studio (@tegaki/website)

  • New "Letter spacing" slider, persisted to the URL as ls.
  • Wired useShaper through StandaloneTextPreview so /preview honors the documented hb param (previously ignored) — needed for the non-shaper visual test and consistent with the generator.

Correctness across scripts

Verified in-browser with the overlay on (canvas strokes vs. the browser-spaced DOM text):

  • Latin (Caveat), shaper on/off — spaced correctly, canvas aligned to overlay.
  • Hebrew (non-cursive RTL) — aligned.
  • Arabic (cursive RTL) — glyphs are spaced, but the canvas can drift slightly from the hidden debug overlay because HarfBuzz cursive-attachment advances don't map linearly onto the browser's per-grapheme spacing. Documented in the code; letter-spacing on cursive scripts is a rare/discouraged case and only the debug overlay reveals the difference.

Tests

  • Unit tests for the headless textToSvg letter-spacing behavior (widens layout, shifts later glyphs, leaves the first glyph put).
  • Three Playwright snapshot cases with committed -darwin + -linux baselines: letter-spacing-shaper, letter-spacing-non-shaper, letter-spacing-rtl. Linux baselines generated and re-verified in the v1.61.1-noble CI image.
  • Docs: a "Styling" section in the rendering guide listing the CSS-inferred properties.

bun checks green.

The renderer reads letter-spacing from the container's computed style
(alongside font-size, line-height, color) and applies it to the animated
strokes, re-measuring on change via the sentinel transition. Spacing is
inserted between clusters in the shaper pen-walk and picked up from the
DOM-measured offsets on the char-keyed fallback path, keeping wrapping,
glyph positions, and drawn text in sync. Adds a Studio slider (persisted
to the URL as ls) and a textToSvg letterSpacing option.

Closes #62
@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Tegami

This repository uses Tegami to manage releases. When your changes affect published packages, add a changelog file under .tegami/ before merging.

Create a changelog → · Changelog format

Release preview

Package Bump Version
@tegaki/root minor 0.20.00.21.0
@tegaki/example-remotion minor 0.20.00.21.0
hyperframes minor 0.20.00.21.0
@tegaki/example-next minor 0.20.00.21.0
@tegaki/example-editframe minor 0.21.00.22.0
@tegaki/example-nuxt minor 0.20.00.21.0
@tegaki/example-vite minor 0.20.00.21.0
@tegaki/website minor 0.20.00.21.0
@tegaki/example-e2e minor 0.20.00.21.0
tegaki-generator minor 0.20.00.21.0
tegaki minor 0.20.00.21.0

Changelogs in this PR

Changelog Title
letter-spacing.md Infer and apply CSS letter-spacing

Run bun run tegami locally to create a changelog interactively.

Managed by Tegami.

gkurt added 2 commits July 11, 2026 18:57
A prior lockfile change pulled in multiple @types/node versions (22, 24,
25, 26). With the root tsconfig's node resolution, 'node:child_process'
resolved to a different copy depending on platform — on Linux (CI) it
picked one where ChildProcess/ChildProcessByStdio lost its EventEmitter
base, so 'proc.on(...)' in generate-fonts.ts and derive-korean-chars.ts
failed with TS2339/TS7006. macOS happened to resolve a working copy, so
'bun typecheck' passed locally while CI stayed red.

Pin @types/node to a single 22.20.1 via overrides so resolution is
deterministic across platforms. Verified with a frozen install + full
'bun typecheck' in the Linux (oven/bun) image CI uses.
@gkurt
gkurt merged commit ff0b8a4 into main Jul 11, 2026
5 checks passed
@gkurt
gkurt deleted the feat/letter-spacing branch July 11, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Please add a letter spacing slider in the Studio

1 participant