Vertical writing systems (tategaki column layout) - #18
Merged
Conversation
Splits two things that were fused into one assumption ("lines stack down,
tokens flow across, connectors run vertically"):
- `layoutAxis` (project-wide): `rows` as before, or `columns` where every
line becomes a vertical column and connectors run sideways. Plus
`columnOrder` for which edge the first line sits on (right for CJK, left
for Mongolian). The axis is project-wide on purpose: a connector between
an adjacent pair needs one consistent "between" direction, and a line pair
gap is a single number.
- `textOrientation` (per line): `upright` keeps words horizontal, `vertical`
stacks characters (tategaki), `sideways` rotates the line. So a Japanese
column stacks glyphs while the English column next to it stays a stack of
upright word boxes.
Column mode sets the token row itself vertically, so flex direction and the
logical margin between tokens map to the block axis and DOM measurement is
unchanged. Link geometry, auto-fit, and `refitLayoutToFill` take the axis;
SVG export draws vertical tokens as one tspan per character (SVG 1.1
writing-mode is not honored by the PNG/PDF rasterizer) and sideways tokens
as a rotation about the box center.
Compact v4 gains two settings keys and one trailing line column, both
omitted at their defaults, so existing share links decode unchanged.
Not included, tracked as follow-ups: API/MCP/OpenAPI surface, vertical
HarfBuzz shaping for custom-font path export (CJK brackets and punctuation
need `vert`/`vrt2` and vertical advances), automatic CJK segmentation.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Turning on vertical writing needed two controls in two panels: Direction buried below Canvas and Colors in the Style tab, and each line's glyph setting behind its own gear popover. Nobody found it. Layout is now the first section of the Style tab (it is structural, not decorative), and switching to Columns reveals a per-line "Stack characters" list right underneath. Two clicks, one place. The per-line popover keeps the full three-way setting, since `sideways` stays the advanced option. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`columnOrder` expressed nothing that line order did not: reversing the lines produces the same mirror. Removed it. The first line is now always at the start of the stack — topmost in rows, leftmost in columns — which is the one consistent rule and matches the reorder arrows. The tategaki example therefore lists English first so the Japanese column still lands on the right, where a vertical text belongs. New Mongolian example. Traditional Mongolian runs top-to-bottom with columns progressing left to right, so the script line comes first with no reordering. Its setting is `sideways`, not `vertical`: Mongolian fonts store glyphs rotated 90° counter-clockwise and expect the line to be rotated back (UAX #50), unlike CJK where each character is set upright. That is the case the three-way enum was kept for. Text is the masthead of the newspaper Buriyad Mongɣol-un ünen (1925), taken from the Wikipedia article on the Mongolian script, with a transliteration tier. The genitive ᠤᠨ has no English word of its own, so it stays unlinked. Verified in Chromium: Noto Sans Mongolian loads, glyphs orient correctly, and the exported SVG matches the preview. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Gallery pages for both new examples, with a word-by-word table and the reasoning each one demonstrates: Japanese particles that link to nothing, and the Mongolian genitive that does the same. New guide at /guide/vertical-writing-alignment covering when to use columns, the three per-line text settings, mixing a vertical script with a horizontal translation, why line order decides the column side, and splitting spaceless text into words. Both surfaces cross-link. Also: README and about feature lists, CHANGELOG, llms.txt (new walkthroughs plus a Guides section that was missing entirely). Guide catalog entry gives the index card and sitemap URL for free. Rendered the gallery previews. Two fixes fell out of doing that: - The 70vh frame height that auto-fit needs in column mode made a readonly embed screenshot mostly blank canvas. It is now scoped to the editor, and columns stretch to the tallest one instead of to a percentage height, so the same rules work bounded or hugging content. The credit line was landing beside the diagram as a flex item; it now wraps underneath. - The render script can use a system Chromium via CHROMIUM_PATH. Playwright's bundled build cannot start on NixOS, which made the documented pipeline unrunnable there. Preview PNGs still need `make examples-upload` (object storage credentials) before the two new gallery pages show their images. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`npm run audit:ci` started failing on advisories published against unchanged code, the same way it did earlier this week: - nanoid <3.3.17 — GHSA-2v37-7h3g-55p8, high. Custom generators loop indefinitely when size is zero. 3.3.16 → 3.3.18. - dompurify <=3.4.12 — GHSA-55q2-fjhq-7xh7, moderate. Came along with the fix. 3.4.12 → 3.4.13. Lockfile only; package.json untouched. The three remaining low advisories on `cookie` are reachable through @sveltejs/kit and npm's only offered fix downgrades it to 0.0.30, so they stay below the --audit-level=high gate. Co-Authored-By: Claude Opus 5 (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.
Several users asked to align texts written vertically: Japanese and Chinese tategaki, traditional Mongolian. The design question was what a diagram should look like when a vertical language is paired with a horizontal one.
Approach
Two things were fused into one assumption ("lines stack down, tokens flow across, connectors run vertically"). This splits them:
layoutAxis(project-wide) —rowsas before, orcolumns, where every line becomes a vertical column and connectors run sideways.textOrientation(per line) —upright(words stay horizontal),vertical(characters stack, for Japanese and Chinese), orsideways(line rotates).A Japanese column stacks its glyphs while the English column beside it stays a stack of upright word boxes. That is the answer to the mixed case.
The axis is project-wide on purpose: a connector between an adjacent pair needs one consistent "between" direction, and the gap between a line pair is a single number. Mixing axes per line would break both.
Column mode sets the token row itself to
writing-mode: vertical-rl, so flex direction and the logical margin between tokens map onto the block axis and DOM measurement is untouched. That is why this did not become a rewrite. Link geometry, auto-fit, andrefitLayoutToFilltake the axis. SVG export draws a vertical token as one<tspan>per character, because SVG 1.1writing-modeis not honored by the rasterizer behind PNG and PDF, and a sideways token as a rotation about the box center.Compact v4 gains one settings key and one trailing line column, both omitted at their defaults, so existing share links decode unchanged (covered by a test).
Decisions worth flagging
sideways, notvertical. Its fonts store glyphs rotated a quarter turn counter-clockwise and expect vertical layout to rotate the line back (UAX #50), unlike CJK where each character is set upright. This is the case the three-way enum exists for.upper/lowernot renamed. In column mode "upper" means "earlier in stack order". Those names are part of the/api/alignand MCP surface, so renaming would break clients for no user benefit.Not included
Verification
Driven in Chromium (Playwright): preview and downloaded SVG match, the Japanese column sits right with stacked glyphs, English stacks upright beside it, connectors cross correctly on SOV/SVO. Mongolian loads Noto Sans Mongolian and orients correctly. Horizontal mode unchanged.
check,lint, andtestgreen (189 tests, 26 added);npm run buildprerenders all three new pages.Docs and content
Gallery pages for both examples, a guide at
/guide/vertical-writing-alignment, plus README,/about, CHANGELOG, andllms.txt(which also gained a Guides section it was missing). Preview PNGs are rendered and already uploaded to the CDN.Two fixes fell out of rendering those previews: the 70vh frame height that auto-fit needs in column mode is now scoped to the editor, since a readonly embed was screenshotting mostly blank canvas, and the credit line no longer sits beside the diagram as a flex item. The render script also accepts
CHROMIUM_PATH, because Playwright's bundled Chromium cannot start on NixOS, which made the documented pipeline unrunnable there.🤖 Generated with Claude Code