The engine's atomic module keeps its functions and signatures and delegates to craft-libs/craft-atomic (pinned to e9546e19), so every save and export caller is unchanged. write_atomic_with also turns a panicking writer into an error, so its temporary file is removed. Recovery checkpoints and package output keep their own writers, which replace links instead of following them.
On Unix, new files follow the umask and replaced files keep their permissions.
open_dropped sent every dropped file that is not a document to
file.place, so a swatch exchange (.ase) file dropped on the desktop
window failed with a "Can't Place the File" alert: "invalid parameters
for `file.place`: unsupported or corrupt image".
open_dropped now sends .ase files to swatch.load with the dropped path,
as Load Swatches in the Swatches panel menu does with the picked path.
The web app already sent dropped .ase files to swatch.load. The
swatches are added to the active document as Load Swatches adds them,
and if the file can't be loaded, the status line shows the error.
A frame holding items pasted into it (Edit › Paste Into) was drawn by
its own branch in draw_item that skipped every effect: Basic Feather,
Inner Glow, shadows and the rest were stored but never drawn. LYH Studio
episode 14 (11:51) gives the outlined "GET MORE." title, with a photo
pasted into it, an Inner Glow and a Basic Feather.
Such a frame now goes the way of any other object: draw_body draws its
fill, its items clipped to the frame and its stroke, so draw_item_fx
wraps all of it. Its silhouette counts as solid for shadow spread.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A frame holding items pasted into it isn't a group. Ungroup took it
apart like one, leaving its content loose and losing the clipping shape,
and the Properties panel called it "Group" with an Ungroup quick action.
As in InDesign, Ungroup now only takes real groups apart; other objects
stay as they are and stay selected (Ungroup used to clear them from the
selection). Such frames are labelled by their shape (<ellipse>, ...), so
Properties shows "Ellipse" with Convert Shape.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As in InDesign, outlining a text frame gives a group with one compound
path per line (split further by text colour within a line), so Ungroup
leaves each line on its own: LYH Studio episode 14 ungroups the outlined
title at 4:56 to tighten the space between its lines before making one
compound path again. A single line in one colour stays a single compound
path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Backspace at the start of the second of two consecutive tables merged their
anchor paragraphs: Story::delete kept one table id, the other table was
dropped and the paragraph held two anchors. Pasting a table next to an anchor
replaced the existing table the same way, and pasting several paragraphs
right before an anchor left its table unreferenced. Saving succeeded;
reopening failed with "paragraph must hold exactly one anchor".
fix_tables now splits a table paragraph that holds further anchors, so every
anchor gets its own paragraph again. delete and insert_story tell it which
table each surviving anchor belongs to (fix_tables_with), and insert_story
fixes tables up once after the whole paste instead of after every run.
Regression tests in doc (Backspace between tables, deleting the middle of
three, paste before/after an anchor, paragraphs pasted before an anchor) and
engine (text.delete and edit.paste through commands, then a file round-trip);
all failed before the fix.
Claude-Session: https://claude.ai/code/session_01La6SDgsmdZfgfDDmx3wiGU
With a placed image selected via Direct Selection (InDesign's content
selection), Copy now copies the graphic itself: a frame of the whole
image's bounds (uncropped) at its spread position, without the frame's
fill, stroke or effects. Paste Into then puts the full picture in place
inside the target shape, as InDesign does (LYH Studio episode 14, 5:44).
Cut and Delete with the graphic selected remove only the graphic; the
frame stays, empty and selected.
Nested items copy in spread coordinates (parent transform applied).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As in InDesign, the Eyedropper applies a colour sampled from a placed image
to the fill or the stroke, whichever is in front in the toolbox: with the
Stroke box in front a selected line takes it on its stroke (it has no
fill to show it). The toolbox's state reaches tools through
ViewInfo/ToolContext::stroke_in_front.
Depends on #572.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In InDesign double-clicking a selection handle fits the frame to its
content: a corner fits both sides, a top or bottom handle the height, a
side handle the width. LYH Studio's tutorial uses it at 9:30 to fit the
INDESIGN text frame before moving it to the corner. In DesignCraft the
double-click switched to the Type tool.
- Selection tool: a double-click on a handle runs object.fit
{mode: fitFrameToContent, axis: both|height|width}.
- object.fit fitFrameToContent fits text frames to their composed text:
the bottom to the last line's descent, the right side to the longest
line (one column), plus the insets, keeping the top-left. Overset text
grows the frame first. Before, it fitted graphic frames only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Text is composed in the box around a frame's path in the frame's own
coordinates. A sheared then rotated frame turns that box past its path's
bounds, which was all a move repainted, so its text left trails behind.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The renderer painted the paper, then blended page items with it: black
text in Color Dodge over blank paper dodged the white to white and
vanished, and other modes showed the same way. In InDesign (and in PDF,
where the page group starts transparent) the paper is not a backdrop:
over blank paper an object in any blend mode shows as it is, and only
the objects below it are blended with. On spreads that use a blend mode
the items are now drawn in their own group, laid over the paper once;
other spreads render as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A gradient feather on a group (Gradient Feather tool over grouped text, as
in LYH Studio's poster tutorial) did nothing on screen: groups never went
through the effects path. In PDF the group's mask was the group's own path
bounds, and a group has no path, so the mask covered a box of zero size and
hid the group.
- Item::feather_bounds: the box the feather spans, the objects' bounds for
a group.
- Render: a feathered group draws its objects in one layer, then fades it
with the same mask as other objects (fx::gradient_feather_mask).
- PDF: the group's mask spans its objects.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A preview that a menu or script edits or saves while the window is open
becomes a document of its own: Close keeps it and gives it its Untitled
number. document.list and the control inspect mark the preview.
- Close shows the previously active document again only if the preview was
still active; a document opened meanwhile stays active.
- Create refuses invalid fields with a status beside the buttons, keeping
the window and the preview. When the settings are the previewed ones, the
preview document becomes the new document; otherwise file.new makes it,
and a failure puts the window back with the error.
- The preview is rebuilt once the fields have stayed the same for 200 ms,
and refused settings are not retried until they change.
- No recovery discard for preview documents, which are never written.
- The window's key is _previewedDoc, distinct from the interaction preview
key, and ending the preview is a no-op without one.
A Preview checkbox beside Close and Create shows a document with the
window's settings in the workspace and rebuilds it as they change: size,
orientation, pages, facing pages, margins, columns, gutter, bleed and slug.
It is off by default and kept for the session. Fields that don't hold a
value yet, and sizes file.new refuses, keep the last preview.
The engine keeps the preview document (Session::preview_new_document,
end_new_document_preview): it replaces itself in its tab, takes no
Untitled number and is never written as recovery data. Create removes it
and makes the document with file.new, so it starts with a clean undo
history. Close, Escape, ui.dialog.cancel, turning Preview off or another
dialog replacing the window remove it and show the previously active
document again, unchanged.
Keep small and high-precision numbers intact in table placement and data merge. Honor cached formula strings as text, including leading zeros and whitespace.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Pages draw the base parent's items, then the parent's, then their own,
on the canvas, in PDF and image export, and on the parent spread itself.
Chains are followed base first with a depth bound. Overrides, parent hit
testing and the flattener's transparency check include base items.
layout.parents.options {parent, basedOn} sets or clears the base and
refuses cycles; document.inspect reports basedOn per parent. Opening a
.designcraft or IDML file clears a cyclic or dangling base with a warning.
IDML already carried the base as the parent pages' AppliedMaster; a test
covers the round trip.