Goal
Tune the artifact canvas's horizontal reading mode (spec 1380) so every column is a readable, same-shaped page: a bounded measure, a bounded height, and no stranded headings. Grounded in two reading studies (Braganza et al., WWW 2009, horizontal multi-column scrolling with eye tracking; Baker, Wichita State 2005, columns and justification): layout does not change comprehension, but it changes reading effort, place-keeping, and satisfaction. Optimal measure across the literature is 45 to 66 characters per line; both very short (30) and very long (90+) lines slowed readers.
Today (packages/artifact-canvas/src/styles/default-theme.css)
--codev-canvas-column-width: 25em is a preferred minimum; CSS multicol stretches columns to share leftover width. With the 16px system font the measure swings with pane width:
| Pane width |
Columns |
Characters per line |
| 1800 px |
4 |
about 52 |
| 1400 px |
3 |
about 54 |
| 1290 px |
2 |
about 78 |
| 840 px |
1 |
about 106 |
Wide panes land in range; a half-window pane (the two-group layout in #1671) blows through it.
- Column height fills the viewport (
height: 100%; max-height: 100vh): a tall pane gives 50-line columns and a long diagonal return sweep from the foot of one column to the head of the next.
- Fragmentation protection exists for
pre, table, img, marker cards and the composer, but nothing for headings or paragraphs: a heading can sit alone at the bottom of a column with its text on the next page.
- Text is left-aligned; no hyphenation;
text-wrap default.
Changes
- Bounded measure (JS + CSS).
- When fewer than two columns fit, do not render horizontal mode at all: fall back to vertical with the prose cap engaged. A one-column horizontal mode is vertical mode with a worse scrollbar.
- Choose the column count in code from the measured pane width (the geometry helper in
components/column-geometry.ts already measures columns) so each column stays between 45 and 66 characters, and absorb the remainder as horizontal body padding instead of letting columns stretch. Lower the minimum token to about 22em so the count ticks over sooner. Expose the target measure as a token (--codev-canvas-column-measure, in ch) rather than a settings UI, matching the existing token-only contract.
- Bounded height (CSS). A maximum column height token in line-height units, default about 40 lines, applied as
max-height: min(100%, 40 * line-height). Once the measure is pinned this makes every page the same shape, which is what makes paging a rhythm.
- No stranded lines (CSS, cheapest). In horizontal mode: headings
break-after: avoid; paragraphs and list items orphans: 2; widows: 2; prose text-wrap: pretty.
- Code in columns (CSS). Slightly smaller code font in horizontal mode, about 0.85em, so a fence fits roughly 60 columns of code inside a 50-character prose column without changing the prose. Keep the existing inner scroll; do not span fences across columns (breaks the page rhythm).
- Justification, experiment only (CSS token, default off). Baker's fastest layout was two fully justified columns, attributed to predictable line ends, but that was without hyphenation on a fixed page; in a browser, justification without hyphenation opens rivers. Add
--codev-canvas-justify that turns on text-align: justify together with hyphens: auto, default off, and decide after a hands-on read of a real spec.
Out of scope here: wheel snapping (#1701); a screenful page step alongside the one-column step (follow-up if wanted); a document-position overview strip.
Tests
- Geometry: for a table of pane widths, the chosen column count keeps the measure within 45 to 66 characters; below two columns the mode falls back to vertical.
- Token snapshot test updated for the new tokens; the height and measure tokens honour the
--codev-canvas-* contract.
- Fragmentation fixture (from 1380's Playwright suite): no heading is the last block in a column; no single-line orphan at a column top.
- Visual check on a real plan file with wide code fences at half-window and full-window widths, light and dark.
Verification by the owner
Half-window pane: two or three columns of about 50 to 60 characters, columns no taller than about 40 lines, headings never stranded, code readable. Full-window pane: same page shape, more columns.
Relation
Goal
Tune the artifact canvas's horizontal reading mode (spec 1380) so every column is a readable, same-shaped page: a bounded measure, a bounded height, and no stranded headings. Grounded in two reading studies (Braganza et al., WWW 2009, horizontal multi-column scrolling with eye tracking; Baker, Wichita State 2005, columns and justification): layout does not change comprehension, but it changes reading effort, place-keeping, and satisfaction. Optimal measure across the literature is 45 to 66 characters per line; both very short (30) and very long (90+) lines slowed readers.
Today (
packages/artifact-canvas/src/styles/default-theme.css)--codev-canvas-column-width: 25emis a preferred minimum; CSS multicol stretches columns to share leftover width. With the 16px system font the measure swings with pane width:Wide panes land in range; a half-window pane (the two-group layout in #1671) blows through it.
height: 100%; max-height: 100vh): a tall pane gives 50-line columns and a long diagonal return sweep from the foot of one column to the head of the next.pre,table,img, marker cards and the composer, but nothing for headings or paragraphs: a heading can sit alone at the bottom of a column with its text on the next page.text-wrapdefault.Changes
components/column-geometry.tsalready measures columns) so each column stays between 45 and 66 characters, and absorb the remainder as horizontal body padding instead of letting columns stretch. Lower the minimum token to about 22em so the count ticks over sooner. Expose the target measure as a token (--codev-canvas-column-measure, inch) rather than a settings UI, matching the existing token-only contract.max-height: min(100%, 40 * line-height). Once the measure is pinned this makes every page the same shape, which is what makes paging a rhythm.break-after: avoid; paragraphs and list itemsorphans: 2; widows: 2; prosetext-wrap: pretty.--codev-canvas-justifythat turns ontext-align: justifytogether withhyphens: auto, default off, and decide after a hands-on read of a real spec.Out of scope here: wheel snapping (#1701); a screenful page step alongside the one-column step (follow-up if wanted); a document-position overview strip.
Tests
--codev-canvas-*contract.Verification by the owner
Half-window pane: two or three columns of about 50 to 60 characters, columns no taller than about 40 lines, headings never stranded, code readable. Full-window pane: same page shape, more columns.
Relation
chso it scales with font size too.