Pages keep their background colour when pages are deleted or moved, a page can be given a colour of its own, replacing a page with just its spreads no longer fails on a colour the document already has, a document can be opened on any page, and a small correction to how the image scale setting is shown.
A page can have a background colour of its own. typograph.set_page_fill(page, swatch_uuid, tint) colours one page, or a whole spread with record_index: null; get_page_fill(page) says
which colour a page shows. The colour is saved and printed on that page only. See
A page's background colour.
⚠️ Replacing a page with just its spreads is no longer refused over a colour, font or image.
typograph.replace_page_content() / replace_spread_content() given the spreads part alone used
to refuse the whole call when one reference was not in the document's manifest — even a colour
the document had. It now places the layout, as it always did for a full bundle:
merged.manifest;unresolved, so check that list (or validate()).To keep the old all-or-nothing behaviour, pass { require_manifest: true }.
Page colours no longer disappear when a page is deleted or moved. A background colour
belonged to the spread, and deleting or moving a page re-pairs the pages after it into new
spreads — which started white. Each page now keeps its colour. Colours set with
get_active_page().set_fill_swatch_uuid() are kept too; set_page_fill() is the better call,
since it records an undo step and redraws.
Opening a document on a page works. A page shown from typograph_document_opened — with
typograph.show_page() or show_spread() — was replaced by the first spread straight after:
the event fired before the editor had finished opening the document. It now fires last, when the
first spread is shown and the page bar lists the pages, so a page shown there stays shown. A
setTimeout used to work around this can be removed. See
Opening a document on a page.
The image scale setting reads "Scale to Fill", not "Scale_to_Fill". When an image was selected, the Scale control in the toolbar showed its setting with underscores ("Scale_to_Fill", "Scale_to_Fit") until another value was chosen. It now shows "Scale to Fill" and "Scale to Fit" from the start, the way the menu lists them. The setting itself is unchanged.
fix/popup-title-underscores: Popupmenu built its title element from the raw value
and skipped the underscore-to-space step that setTitle() applies, so every popup showed its
first value as an id ('Scale_to_Fill') and only later ones as text. The first render now
follows removeunderscore like setTitle(). That affects only how the first value is shown, in
any popup with an underscore in its initial value; this.title, the menu ids and the stored values
are unchanged.fix/TYP-825-document-opened-order): DocumentManager sent
typograph_document_opened before set_active_page(0), page_bar.update_pages() and
enable_page_bar(). Listeners run synchronously, so those three undid whatever a handler
navigated to. The event and send_page_images_loaded() now come last; typograph_page_shown for
spread 0 fires before them. Canvas browser suite run_document_opened_tests(): 10 passed; the old
order fails two. The viewer's own listener re-showed the page bar, and canvas then hid it again
for a one-page document; with the order reversed, viewer.ts re-shows it only for more than one
spread, so a one-page document still opens without a page bar.TYP-846-page-fill, canvas feat/TYP-846-page-fill,
document-generator TYP-846-page-fill): a page record carries optional fill_swatch_uuid /
fill_tint_value, written only when the page has its own colour. Canvas Spread.page_fills (like
page_margins) is carried by extract_record(), absorb_page(), copy() and the single-page
builders, drawn by draw_page_fills(), and included in the swatch collect/remap and the loader's
swatch-id remap. Canvas suite run_page_fill_tests(): 37 passed, the reported case (colours set through the spread, then a delete) among them. The generator's drawPage()
paints each record's own colour by the same rect rule (PageFillTest, 7). Merged in order:
document-schema #55 (e197a5e); the schema lock in publisher-service #63, converter-service #69
and document-service; canvas #176; document-generator #57 (1dc902e), then publisher-service's
lock of the generator. The three services need a deploy for page colours to validate and print.feat/TYP-847-short-form-accepts): the short form's references outside the
manifest are sorted instead of refused — library_not_manifest swatches are published through
sync_swatches_to_manifest() inside the undo step (reported only once actually in the manifest; a
document with no manifest has nothing to publish to), FontManager fonts are accepted as they are,
missing ones go to unresolved. In both forms an image key no manifest names gets a placeholder
manifest entry (stand_in_missing_images(), sized as the converters do: 96 dpi, max 1024 px) —
asset_id_to_asset() otherwise looked for it at userdata/images/<key> on the host and the
frame showed nothing. require_manifest: true keeps the TYP-720 refusal. Suite
run_page_replace_tests(): 43 passed.editor.js, editor.min.js and their maps,
so a deploy looked as if the viewer had been left out. It never was: the deploy uploads all of
dist/, the viewer bundles included. On 2026-10-07, build 865 had all four bundles on the CDN within two
seconds of each other. The log now lists viewer.js, viewer.min.js and their maps as well.7f0e139 — TYP-847 (PR #177), TYP-846 (PR #176) and TYP-825 (PR #175), on top of
dd32fd3.