* Type: story Optical Margin Alignment with a size, and Ignore Optical Margin (engine, IDML) A story's Optical Margin Alignment applies to every paragraph except those with Ignore Optical Margin; hang amounts scale with the story's size. story.options sets it, type.para and paragraph styles take ignoreOpticalMargin. IDML imports and exports StoryPreference OpticalMarginAlignment/OpticalMarginSize and IgnoreEdgeAlignment. The per-paragraph opticalMargin switch keeps hanging at the text's own size. Part of #947. * Type: the Story panel, and Ignore Optical Margin in the Paragraph panel menu and Paragraph Style Options Window > Type & Tables > Story sets Optical Margin Alignment and its size for the stories of the text selection or the selected text frames through story.options, and is disabled without either. type.selectionAttrs reports the stories' values as storyOptions, null where they differ. The Paragraph panel menu toggles ignoreOpticalMargin, and Paragraph Style Options > Indents and Spacing has an Ignore Optical Margin checkbox. Part of #947. * ROADMAP: the story Optical Margin Alignment entry names its default and scope
9.3 KiB
Typography and composition parity
Last reviewed: 2026-10-10 · Last updated: 2026-10-24 · Change: minor (Optical Margin Alignment per story with a size in the Story panel, and Ignore Optical Margin in the Paragraph panel menu and paragraph styles, kept through IDML (#947); Type › Reload Fonts reads fonts installed, edited or removed since start-up (#328, #547); Optical kerning from outlines (#181); macOS lists fonts that font services and managers activate; Justification dialog for the selected paragraphs; anchored objects wrap text; Tabs panel listed as present (#343); character stroke behind fill) · Target: Adobe InDesign 2026 (21.6)
Typesetting is what InDesign is bought for. A feature can exist and still set text differently from InDesign: different line breaks, different page count, overset where InDesign fits. This document tracks both: does the attribute exist, and does it compose like InDesign? Script-specific detail lives in cjk-typography.md, cjk.md and arabic-typography.md. Overall numbers: target-app-parity.md.
Dimension score: ~45% ready (estimated), 120–200 h to parity. Presence is high (76% scored below, nothing absent); fidelity against InDesign is unmeasured, which is the main gap.
Fidelity: how we'd know
There is no oracle yet. What exists: unit tests of break points and invariants in
crates/compose/src/tests.rs (172 tests in the crate), IDML files built by DesignCraft and opened
in InDesign 2026 by hand, and user reports comparing the two (#179, #180, #181, #282–#295).
Needed (gap 4 in gaps.md): a set of synthetic stories (our own text and fonts:
Source Serif 4, Inter, Shippori Mincho from craft-fonts) covering each row below, set in InDesign
2026 by observation on the owner's Mac (results under plan/, never committed), exported as IDML;
DesignCraft opens the IDML and a test compares per paragraph: line count, break positions (by
character offset), last-line width, overset and frame fit. Report the share of paragraphs whose
breaks match exactly. Target for beta: ≥ 90% of Latin body paragraphs identical, 100% fit in the
same frames.
Checklist
Status: ✓ present and believed close · ~ present, known differences or partial · ✗ missing. Fidelity: unmeasured unless stated.
| Area | InDesign 2026 | DesignCraft | Status | Notes / evidence |
|---|---|---|---|---|
| Paragraph Composer | Adobe's multi-line composer | Knuth–Plass total fit, fitness classes, hyphen penalties | ~ | same family of algorithm, Adobe's weights unknown; breaks will differ on some paragraphs |
| Single-line Composer | greedy | greedy with the same ranges | ✓ | |
| World-Ready composers | Paragraph / Single-line World-Ready | RTL, Arabic and bidi in the main composer | ~ | Indic scripts (Devanagari etc.) shape through harfrust but are untested |
| Justification | word/letter spacing, glyph scaling min/desired/max, single-word, last line | all of these | ✓ | a justified line with a tab justifies after the tab (#284); set per paragraph in Type › Justification… and the Paragraph panel menu (#531) |
| Hyphenation | per-language dictionaries (~40), zone, limits, capitalized, last word, across columns | Liang patterns: English (trained from the public-domain Moby list), Spanish (Bezos), Portuguese (hyph-pt), Norwegian (hyph-no) and Greek (hyph-el-monoton); zone, limits, exceptions in the user dictionary; Hyphenate Across Column off keeps automatic hyphens off the last line of a column or frame | ~ | other languages don't hyphenate (#87 reported "doesn't work") |
| Spelling | per-language dictionaries | English (Moby) + document/user dictionary | ~ | |
| Kerning | Metrics, Optical, manual, none | Metrics, Optical (outline-based: pairs pulled towards the font's stem gap, crates/compose/src/optical.rs), manual, none |
~ | Optical is an approximation of Adobe's algorithm (#181), not a match: imported display text can still break differently |
| Tracking, scale, skew, baseline shift | ✓ | ✓ | ✓ | |
| Character fill and stroke | fill, stroke, tint, weight, stroke aligned to centre or outside | fill, stroke, tints, weight, stroke behind fill (screen, PNG, PDF, IDML StrokeAlignment) |
~ | text strokes have no join or miter limit settings (#619 for stroke behind fill) |
| OpenType features | ligatures, discretionary, swash, fractions, ordinals, figures, small caps, stylistic sets, positional forms | through harfrust | ✓ | |
| Variable fonts | axes in Character panel | named instances and free axis values; PDF embeds the instance | ✓ | |
| Leading | auto (120%), absolute, leading model | ✓ | ✓ | CJK leading models in cjk-typography.md |
| First baseline | ascent, cap height, x-height, leading, fixed, min | ✓ | ✓ | |
| Frame fit / overset | baseline of the last line must fit | descenders must fit | ~ | differs (#180): frames go overset where InDesign fits |
| Baseline grid | document grid relative to the top of the page or each page's top margin; frame grids relative to the top of the page, top margin, top of frame or top inset | ✓ | ✓ | |
| Vertical justification | top, centre, bottom, justify, paragraph spacing limit | ✓ | ✓ | |
| Text in shaped frames | lines follow oval, polygon and freeform frame outlines, one inset from the outline | ✓ | ~ | concave shapes set one slot per line (the widest); vertical justification and paragraph shading use the frame's rectangle (#646) |
| Columns, span / split columns | ✓ | ✓ | ✓ | split columns within a column (#295); text after a span flows below it (#276) |
| Column rules | ✓ | ✓ (screen, PDF, IDML) | ~ | no stroke types or overprint (#274) |
| Balance columns | ✓ | ✓ (IDML VerticalBalanceColumns) |
✓ | evens out the columns of the frame the story ends in, after its last column break (#609) |
| Keep options and breaks | keep with next, lines together, start in next column/frame/page/odd/even | ✓ | ✓ | break characters end paragraphs (#285); the line before a break is a last line (#283) |
| Drop caps, nested, line and GREP styles | ✓ | ✓ | ✓ | |
| Bullets and numbering | lists, levels, formats, restart, across stories | ✓ | ~ | numbering expressions from IDML (#298); Convert Bullets/Numbering to Text missing |
| Tabs | left/center/right/decimal/align-on, leaders, right-indent tab | ✓ | ~ | Tabs panel with a ruler over the text column, and a Tabs section in Paragraph Style Options (#343); wrapping of lines with tabs fixed (#282) |
| Paragraph rules, borders, shading | ✓ | ✓ | ✓ | |
| Balance ragged lines | ✓ | ✓ | ✓ | |
| Optical margin alignment | per story with a size, Ignore Optical Margin per paragraph and style | ✓ (hang table of our own, scaled by the story's size; Story panel; IDML StoryPreference, IgnoreEdgeAlignment) |
~ | hang amounts are ours, InDesign's unknown (#947) |
| Text wrap | bounding box, shape, jump object/column, wrap sides (text on both sides of an object), contour options, on page items and anchored objects | ✓ | ~ | Detect Edges, Alpha Channel and Photoshop Path contours follow the frame's path (composition doesn't read the image) |
| Anchored objects | inline, above line, custom | ✓ | ~ | anchored objects in table cells not drawn (#163) |
| Footnotes, endnotes | ✓ | ✓ | ~ | footnotes don't split across columns yet |
| Type on a path | ✓ | ✓ | ✓ | |
| Vertical text (CJK) | ✓ | ✓ | ~ | see cjk.md |
| CJK composition | mojikumi, kinsoku, aki, tsume, ruby, kenten, warichu, frame grid | most; mojikumi tables kept but not applied; ruby group-only; no frame grid | ~ | cjk.md, cjk-typography.md |
| Arabic / Hebrew | kashida, digits, diacritic positioning, RTL stories and tables | ✓ | ~ | vendor justification presets unsupported; list bullets and multi-column RTL (#100) |
| Missing glyphs and fonts | pink highlight, substitution | ✓ | ✓ | |
| Installed fonts | every activated font, picked up as installed or changed | system font folders; on macOS also fonts that font managers and Adobe Fonts activate; user folders not always found; fonts installed, edited or removed while running found by Type › Reload Fonts, not automatically | ~ | #161, #110, #107, #327, #261, #328 |
| Composition highlights | H&J, keeps, custom tracking/kerning, substituted fonts | ✓ | ✓ |
Measured from the table above (2026-10-10): 34 rows, 18 ✓, 16 ~, 0 ✗, scoring ✓ = 1 and ~ = 0.5: 76%. Every row exists in some form; the ~ rows are where InDesign users will see a difference.
Remaining effort
| Work | Opus 5.5 h |
|---|---|
| Oracle harness (synthetic stories, IDML exchange, comparison metric) | 20–30 |
| Optical kerning tuning against InDesign (measured pairs per class, once the oracle harness exists) | 5–10 |
| Overset rule (baseline fits) and frame-fit parity | 5–10 |
| Fixing composer differences the harness finds (weights, penalties, glyph-scaling order) | 40–70 |
| Hyphenation patterns for the top 15 InDesign languages (permissive sources) | 20–35 |
| Spelling dictionaries beyond English (licence review per language) | 10–20 (+ owner review) |
| Tabs panel, list conversion commands | 8–15 |
| Total | 120–200 |
Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-10 | major | Created: typography checklist (34 rows), fidelity gap and oracle plan |
| 2026-10-10 | minor | Text wrap: wrap sides and contour types |