typograph-editor-documentation
    Preparing search index...

    Release Notes - Version 1.0.0-20260922

    One theme, and it is the one clients have been asking for: content that knows where it is. A folio that keeps to the outside edge, a title that stays aligned outward, a page number that is a page number rather than a typed digit — all of them following the page when the page moves.

    Plus a crash that took the editor down on a document it should merely have drawn plainly, and three things an InDesign conversion used to lose without saying so: the page number, a gradient feather, and a text frame's columns.

    • An element can sit against a page edge, and stay there. The size panel gains a third rule beside position and size — Sits against: no page edge, inside (spine) or outside — with the distance from that edge beside it.

      Move the page from a right-hand to a left-hand position and the element mirrors about the spine, keeping its distance. This is the thing a folio, a logo or a standing rule needs and could not be told before.

      ⚠️ Choosing an edge does not move the element. The distance is measured from where it already sits, so the rule reads "stay this far from that edge". Typing a distance is the instruction that moves it.

      ⚠️ Inside and outside, never left and right: the whole point is that the element keeps its place when the page changes side, and a rule stated as left cannot do that. Which physical edge it means is decided by the page's number — page 1 is a right-hand page — so it is answered the same way the page bar counts.

      ⚠️ A group holds the rule for its children. Anchor the group, not the items inside it.

    • Text can align to the outside. The alignment control gains inside and outside beside left, centre, right and justify. A title set to outside draws right on a right-hand page and left on a left-hand one, and changes with the page rather than with the control.

      The icons make the spine the subject — a heavy bar at the edge, with the lines hugging it or running from it — because a left/right-looking icon cannot say this: the same rule draws both ways.

      The control keeps showing what was authored. A paragraph set to outside reads outside, never the side it happens to be drawn on today.

    • Dragging an anchored element teaches it a new distance. The distance counts up and down while you drag or resize, so what the rule is about to remember is visible as it changes. A resize moves it too — the distance is measured to the element's nearer edge, and a handle drag moves that edge without moving the element.

    • Clicking into text no longer takes the editor down. A text frame whose first run resolved to a font with no name threw while the toolbar was being built, and the editor stopped there — no toolbar, no text cursor, nothing to do but reload.

      Two things were wrong and both are fixed: the canvas can no longer produce a font without a family (it falls back to the frame's own font, then to the document default), and the toolbar's menus can no longer be broken by a value a document handed them. A menu with nothing to show now shows nothing.

      ⚠️ The frame's own font is what the toolbar reports for a run whose font cannot be resolved, rather than an empty font menu on a frame with visible text in it.

    • A document no longer picks up the host's text colour where it stated none. Every text frame the loader created was given the host's text defaults first, and where the document stated nothing that default stayed — so an unstyled frame, whose colour lives in its paragraph style, was recoloured on open. Converted documents are where this showed most.

    A page number from InDesign is a page number again. InDesign's automatic page-number marker was dropped at import: a footer reading Page ⟨#⟩ converted to the word "Page" and nothing else, in every document that used one. The marker is a processing instruction rather than text, and the importer was reading text only.

    It now arrives as a field — a run whose text is the page it sits on. So a folio renumbers itself when pages are reordered, and four pages sharing one footer show four different numbers.

    ⚠️ A converted template still has to be opened once before it can be printed, as it always has: a conversion carries no text geometry at all, and the canvas is what produces it. A folio shows # until that happens, which is the placeholder saying "not yet resolved" rather than a fault.

    ⚠️ Markers other than the page number — the section marker, the footnote number — are still left alone rather than guessed at. InDesign writes them as the same kind of instruction with codes that are not published anywhere, and a marker read wrongly would put a page number where the designer asked for something else.

    A gradient feather converts instead of disappearing. An object faded with InDesign's gradient feather arrived fully opaque, with nothing to say the effect had been dropped. A feather over a solid fill is exactly a gradient from that colour at one opacity to the same colour at another — which is something a Typograph gradient can say, because its colour stops carry an opacity — so it converts faithfully rather than approximately, including a feather whose start and end opacities were changed from the defaults.

    ⚠️ Three cases are deliberately left opaque rather than approximated: a feather over a gradient fill, because the result is one ramp multiplied by another and two stops cannot express it; a feather over an image, which needs a mask Typograph has no concept of; and an object-level feather on an object that has a stroke or content, because folding it into the fill would fade the fill and leave the stroke sharp. An effect that looks right but is not is worse than one that is visibly missing.

    A text frame's columns arrive. A two-column InDesign frame converted to a one-column frame, with the text reflowing across the full width. The column count, the gutter between columns and InDesign's balance columns all now come across, in all three of InDesign's column modes.

    ⚠️ What does not come across is how a frame re-flows when resized: InDesign can hold columns at a fixed width and change their number as the frame grows, and a converted frame keeps the number it was exported with. The layout is identical at the size it was designed; only that behaviour is absent. Column rules — a line drawn between columns — are not converted either: nothing in Typograph draws one yet.

    • A template with page-number markers, to gain the field. Nothing else recovers it — the marker was lost at import, so there is nothing in the stored template to repair.
    • A template with gradient feathers, for the same reason: the effect was dropped at import and the stored template has no trace of it.
    • A template with multi-column text frames. These are the ones to look at first, because the difference is visible without being obviously wrong: the text is laid out across the whole frame instead of in its columns, which reads as a design choice rather than as a conversion fault.

    Everything else in this release applies the moment a host loads the new bundle.

    • page_side() is the one translation between the model's absolute left/right and the inside/outside the rules are stated in: {side, page_number, inside_edge, outside_edge, inside_margin, outside_margin}.

      ⚠️ Side comes from the document-wide page number, not from a page's position in its spread. repaginate() already owns that rule — page 1 is a recto, a facing pair starts on an even number, a lone even page mid-document is a left-hand page — and deriving side from the spread disagrees with it in two ordinary shapes: a single-page cover followed by pairs, and a lone page mid-document. It would also disagree with the page bar, which counts the same way.

    • ⚠️ Nothing consumed page margins before this, which is worth knowing before anyone plans mirrored margins: they are stored, serialised, copied and compared, and that is all. Page guides are the page's edges and centres, not its margins, and the PDF generator never reads one. So inside_margin / outside_margin map the stored left/right by side, and a mirrored-margin flag would be honoured in that one accessor.

    • The anchor writes the element's rect; the alignment does not. Both resolve where the answer is known, and the difference is what each renderer consumes: the PDF reads an element's own rect and transform, so a position derived only while drawing would be right on screen and wrong in print — but it reads text as positions, which composition already produced, so a resolved alignment reaches print for free. Same for the page-number field, whose digits travel as word text.

    • ⚠️ A rule resolved while text composes is only half a feature. Three bugs this cycle had one shape — a substituted colour, a side-relative alignment, and a folio — where the model was right and nothing had forced the text to lay out again. The symptom is always "it works after I re-apply it". recompose_page_dependent_text() and resolve_page_anchors() now run from the structural normaliser and from the document load, which was the path none of the tests could reach: a test builds its fixture on a spread that already exists.

    • ⚠️ A test that composes on purpose cannot see a missing invalidation. Two suites passed while the editor was visibly wrong, because they called linalyze() before asserting. The assertions are on the flag now, not only the value.

    • ⚠️ The five richtext resolvers are closures bound to the element they were installed on, and Editor.copy() carries them without rebinding. That was latent for as long as they have existed and invisible, because the other four read document-level style tables and the element's own cached font — identical in a copy. page_side_resolver is the first whose answer is positional, so it exposed it: a copied frame resolved against the element it came from. copy_properties_to() re-installs them now.

    • A font reference is a uuid OR a family, and an unresolvable uuid is inert. Only a uuid that resolves outranks the family. story_style_to_font() now guarantees a family rather than admitting undefined into a field typed string — a nameless font produced "12pt undefined" as a CSS font string, so the run was measured and drawn in a face nobody chose. That was a layout fault, not a label fault.

    • The page-number field carries its resolved text, cached the way a word processor caches a field result. Not a convenience: the PDF maps each drawn word back to its story run by character position, so a word composed from characters the story does not have would shift every following word's properties — wrong font, wrong colour, silently.

    • ⚠️ An IDML attribute at its default is not written at all, and that cost two near-misses this cycle. A gradient feather's stop opacities and a text frame's column gutter were both absent from the test documents because both sat at InDesign's defaults — the defaults are written once in Resources/Preferences.xml (a 12 pt gutter, an opaque-to-transparent feather), and the way to confirm which is in force is arithmetic: InDesign also states the column width it computed, and it only reconciles when 12 pt is assumed. Reading an absent gutter as zero would have made every multi-column frame's columns too wide. Where a construct is attested only at its defaults, ask for a second export with the values changed; one minute of InDesign settles what a day of reasoning cannot.

    • ⚠️ Open a document on typograph_setup_ready, never on typograph_init_ready. A document opened between the two is loaded, fires typograph_document_opened, and is then silently replaced by a blank one. Now written into the canvas CLAUDE.md, along with the second fault that masked it: a cold canvas — no document open at all — could not open a rich-text document at all, because the undo snapshot ran before the document's pages were assigned.