Skip to content

Position Thai tone marks over stacked vowels and tall consonants - #27

Merged
narze merged 1 commit into
mainfrom
feat/thai-tone-mark-positioning
Jun 16, 2026
Merged

Position Thai tone marks over stacked vowels and tall consonants#27
narze merged 1 commit into
mainfrom
feat/thai-tone-mark-positioning

Conversation

@narze

@narze narze commented Jun 16, 2026

Copy link
Copy Markdown
Member

Builds on the per-letter Thai highlighting already on main. Each code point renders as its own inline-block .letter box, so a combining mark shaped alone can collide with whatever shares the consonant's above slot. This PR adds the small positional nudges that fix those collisions, plus a /kitchen-sink dev page for finding and tuning more cases.

What changed

  • tone-raise — lift a tone clear of an above-vowel (ทื่อ, สิ้น) or of สระอำ/นิคหิต whose circle sits in the slot (ต่ำ, น้ำ).
  • tone-shift — nudge above marks left on tall-ascender consonants ป ผ ฝ พ ฟ ฬ so they clear the ascender (ป่า, ฟ้า, ปุ่น). Applies to the above-vowel and the tone by the same amount, so they stay aligned (ปี่, ปิ้น).
  • Below-vowels (ปู่) and bare consonants (ท่อ) are left at their natural height.
  • Logic extracted to $lib/engine/thai-marks.ts (toneClass), shared by the typing view and the kitchen-sink.
  • The .letter CSS moved to app.css (global) with tunable --tone-raise-y / --tone-shift-x variables (defaults -0.3em / -0.1em).
  • New /kitchen-sink page: paste/type Thai, compare natural shaping vs. the letter-box renderer side by side, and tune the raise/shift amounts with live sliders ("mark nudged tones" tints raised=teal, shifted=amber).

Why

In Sarabun, rendering each code point as a separate box means tone marks/vowels sit at a nominal position that overlaps an above-vowel, a สระอำ circle, or a tall consonant's ascender. These nudges reproduce what the font's natural shaping does.

Reviewer notes

  • The shift/raise amounts are CSS variables — /kitchen-sink exists specifically to dial them in and surface more exceptions, so the current -0.3em/-0.1em defaults are easy to revisit.
  • Verified on Chromium + Sarabun (the user's setup); the per-mark inline-block approach is browser-shaper-dependent, so a Firefox/Safari spot-check is worthwhile if the support matrix widens.
  • Tests: toneClass behavior is covered in TypingFlow.test.ts (ทื่อ/ต่ำ raise; ปุ่น/ฟ้า shift; ปี่ both; ท่อ/กี่ neither). 67 web tests pass, svelte-check clean.

🤖 Generated with Claude Code

…onsonants

Builds on the per-letter highlighting already on main. Each code point renders
as its own inline-block `.letter` box, so a combining mark shaped alone can
collide with whatever shares the consonant's above slot. A shared helper now
nudges the marks so they sit correctly:

- tone-raise: lift a tone clear of an above-vowel (ทื่อ, สิ้น) or of สระอำ/นิคหิต
  whose circle sits in the slot (ต่ำ, น้ำ).
- tone-shift: nudge above marks LEFT on tall-ascender consonants ป ผ ฝ พ ฟ ฬ so
  they clear the ascender (ป่า, ฟ้า, ปุ่น). Applies to the above-vowel AND the
  tone, by the same amount, so they stay aligned (ปี่, ปิ้น).
- below-vowels (ปู่) and bare consonants (ท่อ) are left at natural height.

The decision logic lives in $lib/engine/thai-marks (toneClass), shared by the
typing view and a new /kitchen-sink page. The `.letter` CSS moves to app.css
(global) with tunable --tone-raise-y / --tone-shift-x vars.

/kitchen-sink is a blank canvas to find more exceptions: paste/type Thai, see
natural shaping vs. the letter-box renderer side by side, and tune the raise/
shift amounts with live sliders.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
learn-manoonchai Ready Ready Preview, Comment Jun 16, 2026 11:48am

Request Review

@narze
narze merged commit 770f61f into main Jun 16, 2026
3 checks passed
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.

1 participant