Preferences OK read the vertical units by indexing the dialog's
fields. A dialog opened through `ui.dialog.open` with horizontal
units only made that panic on the UI thread, outside the crash
guard, and the app exited. The units are now read with `get`, and a
ruler the dialog doesn't name keeps its units.
.indd and .indt documents open through File › Open, drop, the web inbox,
file.open, file.openBytes, file.openIdml and the CLI. The engine converts
them to IDML in memory with storytold/indd-utils (pinned by rev, MIT OR
Apache-2.0, no dependencies, builds for wasm) and imports the result
through the existing IDML path. The converter's warnings come first in the
open result's `warnings`, before the IDML importer's and the font
warnings. A file the converter can't read is an open error, shown in the
Can't Open the File alert.
Routing: a path or name ending in .indd/.indt, or bytes starting with the
INDD signature (the web inbox passes the name without its extension).
opens_as_document and the desktop and web Open dialogs list indd/indt.
Tests use synthetic bytes only: signature-bearing junk, a zero-filled
.indd and a short .indt all fail as open errors with no document added;
a dropped unreadable .indd raises the open alert.
(cherry picked from commit bb8a6a23fa)
file.open on a .indd reported "not a DesignCraft document: expected value at
line 1 column 1"; file.openBytes with a .indd name failed the same way, and a
dropped .indd was placed as a graphic. All now say InDesign documents and
templates can't be opened yet and point to File > Export > InDesign Markup
(IDML), which DesignCraft already opens. The check is by extension, before
anything is read.
Also adds my contributors/people.toml entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
File times are whole seconds (as in Data Merge's fingerprint), so a
same-size change saved within the same second as the last check kept
both size and time, and the Links panel said OK. A size and time are now
only remembered (on place, update, relink, and in the session's check
cache) once the file has been unchanged for two seconds; a file changed
more recently is checked by content on each poll. Found by the Update
Link dialog test, which rewrites a file within the same second; the
polling test now also changes a file twice in one second.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Links panel lists links about twice a second, and each listing
hashed every linked text file. A linked text file now also remembers
its modification time (as Data Merge does for its source, through the
same size-and-time fingerprint): while size and time match, it isn't
read. A different size is Modified without reading. When only the time
changed, the content hash still decides (a file saved or synced again
without changes stays OK), and the session remembers that check by
size and time, so the next poll doesn't read the file again. Update and
Relink record the size and time from before their read. Test: polls of
an unchanged file don't read it (it is made unreadable), a touched but
unchanged file is read once and stays OK, a changed file is Modified.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Callers from outside the app now get a parameter error for a key a
command's params description doesn't name, instead of the command
running with its defaults: `text.select {story, start, end}` and
`style.list {bogus: 1}` are refused with "unknown parameter `…`" and the
nearest or the accepted keys.
- engine: `cmd::params` (ported from VectorCraft #1442) reads the keys
from each params description; `check_params` / `check_keys`.
`Session::execute` itself stays lenient so old journals replay; in the
engine's own tests it checks too, as the audit of the descriptions.
- MCP: tools/call answers -32602 for an argument a tool doesn't take and
for params a command doesn't take (`execute`, every `batch` step before
the first runs); the headless backend checks as well.
- Control channel (`engine.execute`) and `designcraft-cli run --cmd`.
- Descriptions now name every key their commands read (table target
cells, anchored objects, gap.move, file.place, data merge, prefs.set,
…); type.char / type.para stay unchecked (their attributes may be the
params object itself; the setters refuse unknown attributes).
- Tests that passed keys the commands never read are fixed, and the pen
tool no longer sends the unread `notifyPen`.
Fixes#776
Save and Save a Copy put a picture of the first page in the .designcraft
zip as preview.png (320 px on the longer side). The start screen reads
only that entry and shows the last eight recent files as cards with the
picture and the name, below the community card. Files saved before have
a blank page until they are saved again.
The package fallback-font test writes its fixture without Save's preview:
drawing it before the document's fonts load pulled in a system font that
covers the test's characters (Unifont CSUR) ahead of the document's own.
The whole book was one content.xhtml, which is slow on e-readers and
loses chapter starts. The body is now split before each h1 into
content.xhtml, content2.xhtml, …: a section a split goes through is
closed and reopened, and a story that opens with its h1 starts in the
new file with its id. The manifest and spine list the files in order,
and the navigation links each heading to the file it is in. HTML export
stays one page.
Fixes#768
- describe style.paragraph.create (and .edit, style.character.create,
.edit) gave chars?: {…} and para?: {…}. The descriptions now say they
take type.char's and type.para's attributes and name the common ones.
- A wrong attribute gave "invalid parameters for `style`: unknown
attribute `font`". The error now names the command and the group,
and the attribute meant (nearest name, or one the key starts or ends)
or else lists them all: "invalid parameters for
`style.paragraph.create`: chars: unknown attribute `font`; did you
mean `fontFamily`?". The suggestion comes from set_json, so
type.char, type.para and find.change get it too.
- chars or para that isn't an object is an error instead of ignored.
Fixes#777
- Every font-family fell back to serif, sans-serif typefaces included.
The fallback now comes from the font's classification (PANOSE, OS/2
class, name: serif, sans-serif, monospace, cursive, fantasy), passed
in by the engine; without one, from the family name.
- file.exportEpub takes embedFonts: the faces the stylesheet names are
packaged (OEBPS/fonts, @font-face, manifest items with font/ttf, otf,
woff or woff2). Faces that aren't available, whose licence (OS/2
fsType) forbids embedding, or that sit in a font collection are left
out and listed in the new warnings array. Fonts are packaged whole;
subsetting is a follow-up.
Fixes#775
- An image without alt text (Object Export Options) got its file name as
alt, which a screen reader then reads aloud. It is now decorative
(alt=""), and file.exportEpub lists those images in a new warnings
array so they can be given alt text.
- Images and media were packaged as images/<asset id>.<ext>. They are
now <name>-<asset id>.<ext>, the name from the original file name
(lowercase ASCII); the id keeps two files of the same name apart.
Fixes#774
- dcterms:modified was always 2026-01-01T00:00:00Z. It is now the
export time (from the command; on the web, and in the crate without
one, the document's last save or creation time).
- The default dc:identifier was urn:designcraft:<title>, shared by
books with the same title. It is now a urn:uuid derived from the
title and the document's creation time: stable from export to export,
different between documents. file.exportEpub takes identifier to set
it (an ISBN, say).
- file.exportEpub takes coverImage, a PNG or JPEG file used as the
cover (cover-image); a JPEG is packaged as cover.jpg/image/jpeg.
Fixes#771Fixes#773
nav.xhtml had one entry per placed story, labelled with its first
paragraph (body text too), and always the title "Contents".
- Headings (h1-h6) get an id in the EPUB, and the navigation lists the
h1-h3 headings of the stories in reading order, nested by level and
linked to them. A document without headings keeps one entry per
story (its first paragraph).
- The navigation's title follows the language (Inhoud, Inhalt, Table
des matières, Índice, Indice, 目次, 目录; Contents otherwise), and
file.exportEpub takes tocTitle to set it.
Fixes#769Fixes#770
Table cell paragraphs go through the same run and inline path as body paragraphs, so deleted and moved-from text and field instructions stay out of cells, and field results, tabs and breaks come in.
Word's Normal imports as a paragraph style named Normal whose definition is w:docDefaults with Normal's own properties on top; paragraphs without a style use Word's default paragraph style. A styleMap entry can still map Normal to [Basic Paragraph].
to_bytes returns a Result and every caller propagates it, so a document
that can't be written is an error: the existing file, the unsaved state
and the recovery checkpoint stay. Asset entries near or over 4 GiB are
written with zip64 sizes. On the web, Save marks the document saved only
after the browser download has started.
Fields, buttons and video or sound are collected with the page content's
inclusion rule: the item's layer is visible and printable, and neither the
item nor any group around it is hidden or non-printing.
story_html wrote every paragraph on its own, so li paragraphs had no
list around them and each line of a pre style was its own <pre>.
Consecutive li paragraphs now share one list: ol for a numbered style,
ul for a bulleted one, and an unmarked ul (list-style:none) when the
style has no list type of its own (typed bullets). Consecutive pre
paragraphs of one style (and direction) become one <pre> with their
lines separated by newlines.
Fixes#767
Czech for Step and Repeat (Repeat, Count:, Rows:, Create as a grid),
transparency (Isolate Blending, Knockout Group, Object:, Group:),
fill/stroke commands, Reverse Path, Set Anchor, Sample Color, the
Presentation view mode and Invalid value. Removes Type/Proof Setup,
Type/Rotate Spread and Type/Separations Preview, which main no longer
uses (czech_catalog_has_no_stale_keys).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
story_html left out each anchored object's mark and the object with it,
and reading_order only sees page items, so an image anchored in a story
was in neither the EPUB nor the HTML export. The story's text is now
split at the object marks, and each anchored graphic is written in
place: inline in the paragraph, an above-line object as a block span
with its alignment. The graphic markup (and image or media file
registration) is shared with free graphics (graphic_html).
Fixes#766