Commit Graph
4115 Commits
Author SHA1 Message Date
aiongg 5f52150b31 CJK 1.9: document fonts belong to their document
The fonts in a document's Document Fonts folder are registered under a
font scope that the document holds while it is open (Document::font_scope,
runtime only; DocState keeps the scope alive and closes it when the last
copy of the state goes: file.close, closing a tab, revert, a book
chapter's export, the session ending). Composition, preflight, font.list,
Package and the font menus, Glyphs panel and previews look fonts up
through FontDb::scoped(scope): the document's own faces first, then the
shared ones. Other open documents don't see them, and two documents with
fonts of the same name each set text in their own. Composite fonts'
member fonts and the fallback for kenten marks are looked up the same
way.

Font files stay in memory for the session (FaceRef keeps faces for the
process); a document opened again reuses the faces of its unchanged files
(same path, length and modification time) instead of reading them again.
The composition cache's signature includes the scope; the word cache and
the outline and PDF font caches are keyed by face. Variable font
instances are kept per base face.

A family's installed faces join the shared fonts all at once, and a
face two lookups load at the same time is kept once, so a parallel
fallback lookup never takes a family's bold before its regular has
loaded.
2026-10-07 10:44:46 -04:00
aiongg e6e843dc26 CJK 1.8: arrow keys follow vertical lines
In vertical text Down and Up move along the line by a character (by a
word with Alt), Left and Right to the next and previous line keeping the
position along it, and Shift extends, as the arrows do in horizontal
text turned a quarter. The caret is a bar across the vertical line.
2026-10-07 10:44:46 -04:00
aiongg 6df33fa344 CJK 1.7: story direction belongs to the story
Vertical is a story property: every frame of a thread is vertical or
horizontal together, a frame threaded onto a story takes its direction,
and frames split off by threading or breaking a thread keep theirs.
Type > Story Direction is type.storyDirection {vertical} (checked in the
menu) for the stories of the text selection or selected frames;
object.textFrameOptions {vertical} and frame.create {vertical} set the
frames' stories. Documents that stored Vertical on the frame open with
each story taking its first frame's direction. IDML StoryOrientation is
read into and written from the story, beside its column direction
(StoryDirection), which stays a separate setting.
2026-10-07 10:44:46 -04:00
aiongg 1574dcdd45 CJK 1.6: upright text is shaped top to bottom
In vertical frames upright runs are shaped TopToBottom (vert; vkrn/vpal
when asked), advance by their vertical metrics and hang from their
vertical origins on the em box centre, on screen and in PDF; their line
ascent and descent are the em box. Turned runs stay horizontal without
vrt2 (rather than every run taking vert and vrt2), and tate-chu-yoko
stays horizontal and centres on the em box, its offsets moving it along
and across the line. Horizontal Kana in upright runs takes vkna. Each
run is shaped with the text around it, as horizontal runs are.
2026-10-07 09:33:52 -04:00
aiongg 1602b37ec9 CJK 1.5: fonts read vertical metrics
FontFace::v_advance, v_origin and em_box read vmtx/vhea, VORG (else the
glyph top plus its top side bearing) and the ideographic em box (BASE
ideo/idtp, else OS/2 typo metrics, else ascender/descender, centred on one
em); fonts without them fall back to the em box. shape_vertical shapes
top to bottom with those metrics (vert, and vkrn/vpal when asked).
2026-10-07 09:33:52 -04:00
aiongg e0fb78a230 CJK 1.4: Korean breaks at spaces
Korean is set word by word (KLREQ): Hangul, in any language, and Han
ideographs in Korean-language text take no line breaks between
characters, so lines break at spaces. Glyphs carry their language tag
for this. A paragraph attribute, koreanCharBreaks (type.para, paragraph
styles, Paragraph Style Options > Justification), breaks between
syllables instead. It is DesignCraft-only; IDML doesn't carry it.
A paragraph's kinsoku set decides which breaks it forbids, and Korean
still breaks at spaces under one.

Kinsoku still holds, also when the single-line composer has to split a
word wider than the measure: the split moves back so no line starts
with closing punctuation.
2026-10-07 09:33:52 -04:00
aiongg 832939691c CJK 1.3: documents bring their own fonts
Opening a .designcraft or .idml file from disk (file.open, file.openIdml,
book chapters, recovered documents) loads the fonts in the "Document
Fonts" folder beside it. Their faces come before installed faces of the
same family and style. The files are untrusted: at most 200 are read,
256 MB each (full CJK collections fit) and 512 MB in all; files over a
limit by their listed length are skipped unread, and damaged, oversized
and surplus files are listed in the open result's warnings. Document fonts stay
loaded for the session (the font database is process-wide).

Faces record their source (bundled, installed file, document file,
memory); font.list reports it. File > Package copies the font files the
document uses into the package's Document Fonts folder unless OS/2
fsType restricts the licence, and the report says which fonts weren't
copied and why.
2026-10-07 09:33:52 -04:00
aiongg 2da99b70e2 CJK 1.2: font fallback follows the language
Characters the primary font lacks try a fallback chain by language
before the language-blind search: Japanese (the craft-fonts Japanese
faces first, Mincho first), Simplified Chinese (also plain Chinese),
Traditional Chinese and Korean each list their macOS, Windows and Linux
system families. Hangul, kana and Bopomofo pick their language's chain
whatever the character language; ideographs and CJK punctuation follow
it, and keep today's fallback without a CJK language. Chain families
load from the system font catalog the first time they are needed.

designcraft_fonts::testing (feature `testing`) builds synthetic fonts
with a given family name and coverage for tests.
2026-10-07 09:33:51 -04:00
aiongg 2a516761ef CJK 1.1: the character language reaches the shaper
The character's language (as IDML names it) maps to a BCP 47 tag
(designcraft_doc::language_tag) and is the shaping context's language
on the harfrust buffer, so OpenType locl applies for every language in
the list (Japanese, Chinese, Korean, Turkish, ...), not only Arabic,
Persian, Urdu, Hebrew and English: other names used to reach the
shaper as they were written, which it doesn't know, so their locl never
applied. designcraft_fonts no longer maps names itself. The word-shaping
cache is keyed by the tag. Chinese: Simplified and Chinese: Traditional
join the language list (plain Chinese stays, tagged zh); Simplified
Chinese takes curly quotes, Traditional Chinese corner brackets.
2026-10-07 09:33:40 -04:00
aiongg c6b00bc03d Text: drop caps align their left edge and count characters by code point
Drop caps get the Drop Cap Detail options as paragraph attributes: Align
Left Edge (on by default) and Scale for Descenders (kept and
round-tripped; no layout effect yet). With Align Left Edge the drop
cap's origin moves left by its first letter's left side bearing so its
ink starts at the indent, and the lines beside it start where its
advance ends. Right-to-left drop caps are unchanged.

Drop cap characters are counted as code points, extended to the end of
the grapheme cluster so a letter keeps its combining marks.

IDML imports and exports DropcapDetail (bit 1 Align Left Edge, bit 2
Scale for Descenders). DropCapStyle is still imported but no longer
exported: IDML applies the drop cap's character style through a Dropcap
nested style instead.

Format 1 documents keep their drop caps unaligned where nothing set the
option. Paragraph Style Options > Drop Caps has Align Left Edge and Scale
for Descenders checkboxes.
2026-10-07 09:05:00 -04:00
aiongg 572799b883 IDML: frames inherit their object style's corners and text frame options
A frame takes the corner options and Text Frame Options it doesn't write
from its applied object style, the styles that one is based on, then
[None]: IDML frames write only what differs from their style. Each
corner's shape and radius resolve separately, item first; at each level
a per-corner attribute wins over the legacy CornerOption / CornerRadius
pair, so a frame that writes one corner keeps the style's other corners,
and a shape without a radius takes the chain's (12 pt at the root). Fill
and stroke lookups end at [None] too.

Checked, unchanged: corner radii are drawn clamped to half the shorter
side as circular arcs, and inside-aligned strokes are the stroke of the
path inset by half the weight (screen and PDF); tests pin both.
2026-10-07 09:05:00 -04:00
aiongg 7a72faf740 IDML: rules follow the text colour; defaults for auto-size, numbering and table fills
Paragraph rules can be in Text Color: they take the colour of the
paragraph's first character (rule above) or last character (rule below).
That is the default, and IDML maps RuleAboveColor / RuleBelowColor
"Text Color" both ways.

Defaults for what a file leaves unset, in the model and in IDML import:
text frames auto-size from the centre, numbered lists don't continue
across stories, and alternating table and table style fills start
Black 20 % then None 100 %. Kashidas (DefaultKashidas / KashidasOff)
import and export. A tint of -1 is the colour's own tint everywhere tints
are imported (underline and strikethrough, footnote rules included), and
tints are capped at 100 %.

Format 1 documents load as saved: they wrote rules, text frame options,
lists and table fills in full, so nothing relied on the old defaults.
2026-10-07 09:05:00 -04:00
aiongg 4a2a9ff7dd IDML: absent attributes take the defaults IDML files assume
Audit of every attribute the IDML importer reads against the value an
IDML file assumes when it leaves the attribute out. Paragraph,
character, text frame, page item, table and preference values already
match except the corner size: a corner shape without a radius is now
12 pt instead of a square corner.

Table-driven tests pin those defaults for the text attributes (omitted,
written as defaults, written otherwise) and for page items, frames,
tables and document preferences.
2026-10-07 09:05:00 -04:00
aiongg 3daf7fa1cf IDML: Keep Lines Together defaults to start/end of paragraph
Keep Lines Together now defaults to "At Start/End of Paragraph" (2/2):
new paragraphs, and IDML that sets Keep Lines Together without
KeepAllLinesTogether anywhere in the style chain, keep lines at the
start and end instead of moving the whole paragraph.

The native format is now version 2. Loading a version-1 document pins
"all lines" where that document resolved it from the old default (the
start of each paragraph style chain that leaves it unset, and
paragraphs whose style is missing), so saved documents keep their
layout.
2026-10-07 09:05:00 -04:00
aiongg 88b3be0136 UI: drop cap fields, selection over drop caps 2026-10-07 09:04:59 -04:00
aiongg 47d3f5b4bf Text: drop caps 2026-10-07 09:04:59 -04:00
aiongg b825cf3e10 Text wrap: lines jump an object by whole leadings; a column's first line starts below a top object
A line clears a Jump Object wrap with its leading box, [baseline - leading,
baseline]. It stays above the object while its baseline is at or above the
wrap top, so its descenders may hang into the wrap. The next line moves down
by whole leadings from the line above, after any space before or after,
until its leading box clears the wrap bottom. A line that would start a
column under an object starts as if the frame top were the wrap bottom (the
frame's first baseline offset below it). Wrap offsets, negative ones
included, set the wrap's edges.

Other wraps that leave no usable slot, such as a full-width bounding box,
push the line so its top lands exactly on the wrap bottom: the search jumps
from one exclusion bottom edge to the next. Lines aligned to the baseline
grid snap to the next grid line after a push and are re-checked, so they
stay on the grid. The breaker's slot estimate uses the same rules.
2026-10-07 09:04:59 -04:00
aiongg c246f1d34c Text: Cap Height and x Height first baselines use the font's cap and x heights 2026-10-07 09:04:59 -04:00
aiongg 84361ca9f9 Text: the Ascent first baseline uses the font's typographic ascender 2026-10-07 09:04:59 -04:00
Shao Wenbin 1c792b41e4 M9: remove stale localization terminology references
Remove links to the deleted localization-terminology.json from ROADMAP.md
and the Chinese/Arabic translation module comments. Preserve the scope
statement about verified Adobe help terminology and original labels.

Validation: cargo xtask ci passed fmt, clippy, tests, assets and layers.
WASM checks remain blocked by the missing wasm32-unknown-unknown standard
library in the local toolchain. Repository search finds no remaining
references to localization-terminology.json.
2026-10-07 19:47:38 +08:00
Shao Wenbin f52c591b87 M9: cache final RTL label layouts
Reuse wrapped and shaped RTL galleys across frames using a bounded,
context-local cache keyed by the complete LayoutJob. Invalidate cached
results when egui replaces its font-cache token, including font, DPI and
atlas changes. Preserve existing wrapping and elision behavior.

Add regression coverage for cross-frame reuse, layout parameter changes,
font/scale/atlas invalidation and cache eviction, plus an opt-in benchmark.

Validation: cargo xtask ci passed fmt, clippy, 590 tests, assets and layers.
WASM checks are blocked by the missing wasm32-unknown-unknown standard
library in the local Homebrew Rust toolchain (E0463).
Arabic menu screenshots remained identical after ten additional frames.
Manual benchmark: 200 wrapped labels took 31.46 ms uncached vs 0.082 ms
with final-layout cache hits on this machine.
2026-10-07 19:45:38 +08:00
Shao Wenbin ffcc2ef320 erf(i18n): cache translations and skip unnecessary bidi analysis
tr() uses a OnceLock<HashMap>, initialized once, changing lookups from a linear scan to average O(1).
Labels without RTL text, such as Chinese, Japanese, and Western-language labels, skip BidiInfo. Arabic, Hebrew, and directional controls retain their existing handling.
2026-10-07 19:45:38 +08:00
Shao Wenbin 0f09d48a7c Adjust all UI translation according to InDesign UI 2026-10-07 19:45:38 +08:00
Shao Wenbin 852ea64643 add missing Arabic UI translation 2026-10-07 19:45:38 +08:00
Shao Wenbin 02c5f61173 AR1.1: verify Kashida fallback without Tatweel fonts 2026-10-07 19:37:03 +08:00
Cameron Gilroy a2078ece67 Data merge: add the panel and the source file dialog
Window, Utilities, Data Merge lists the linked fields and previews a
record without merging. Create Merged Document runs the merge. The
desktop open dialog offers CSV, TSV, tab, text, and Excel files. The
roadmap records this phase of the feature.
2026-10-07 21:22:06 +11:00
Cameron Gilroy b41eba1cba Data merge: merge into a new document, with preview and tiling
Select, update, and remove a linked source. Placeholders cover text,
images, QR codes, and hyperlinks. Preview fills one record in the
session and is left out of save and recovery. Merge copies the template
into a new document, one record per page, or tiles frames on a single
non-facing page. A missing or changed file is marked and the cached
rows are still used. The template undo stack is left as it was.
2026-10-07 21:22:06 +11:00
Cameron Gilroy a83572a3b0 Data merge: read delimited text and an Excel sheet as rows
Records keep empty cells inside the header width and cap the table at
100,000 rows and 200 columns. Place as a table still uses the existing
Excel import, which drops empty cells.
2026-10-07 21:22:06 +11:00
Cameron Gilroy b3dafb8244 Data merge: store a linked source, placeholders, and options
A document keeps one data source, the placeholders that point at its
fields, and the last merge layout. Empty merge state is omitted from
the file. New documents and IDML imports start with that state empty.
2026-10-07 21:22:06 +11:00
Shao Wenbin c861a9f75e TYPE1: Reapply Chinese and Arabic typesetting rules on main
Port the CJK1 and AR1 changes from 3ecdb78 and de83cdc onto current main. Resolve translation and font-stack conflicts by retaining main localization and craft-fonts integration while preserving all typesetting code, tests, and documentation.

Validation: all six CI gates passed, including 616 tests and WASM checks.
2026-10-07 18:16:32 +08:00
aiongg 0193ac9285 UI: the Scale and Shear tools get their own icons
Scale: a small square grown into a larger one from their shared corner,
with a diagonal arrow. Shear: a rectangle slanted into a parallelogram
along its base, with an arrow. Both are drawn in code in the icon set's
stroke weight; Free Transform keeps its drawing.
2026-10-07 02:00:34 -04:00
aiongg 7861297237 Threading: load text from a port and click to thread 2026-10-07 00:16:50 -04:00
aiongg 6104f2ced1 Threading: thread and unthread commands 2026-10-07 00:16:33 -04:00
aiongg 576fde980b Snap: the nearer of a margin and the baseline grid wins; Type tool frames snap
Resizing or drawing at a zoom where the snap zone covers the baseline
grid's spacing (66% and below with a 12 pt grid) always snapped to a
baseline line, so frames could not reach the top or bottom margin. The
baseline grid and the guides (ruler guides, margins, columns) now
compete by distance and a tie goes to the guide.

Frames drawn with the Type tool snapped nothing; they now snap like the
frame tools' (press point and moving edges, with Shift and Alt).
2026-10-07 00:16:33 -04:00
aiongg 2d6213d40d Text editing: clicks, trailing spaces, bold/italic, clipboard, formatting affects text (#23)
- Double-clicking a text frame with the Selection tool edits its text. The
  canvas counts presses itself (egui reports double clicks only on release,
  so the press never saw them): 2 clicks select the word or run of spaces
  under the pointer, 3 the line, 4 the paragraph, 5 the story
  (`text.selectAt`; pointer events carry `clicks`).
- The caret moves past spaces typed at the end of a line: trailing spaces
  follow the line undrawn instead of being dropped.
- Bold and Italic (Shift+Cmd+B / Shift+Cmd+I, B and I in the Character
  panel) toggle the family's own styles per run, keeping the other trait
  (Italic + Bold = Bold Italic). Formatting chosen at a caret applies to
  what is typed next.
- Copy, Cut and Paste reach the system clipboard however they are chosen,
  including from the native macOS menu; without a native menu the copy and
  paste keys work for objects too.
- Formatting Affects Text (J, Tools panel) sends swatches, colours, tints,
  None, Swap and Default to the text of the selected frames; the proxy and
  the Swatches and Color panels show the text's colours.
2026-10-07 00:16:27 -04:00
aiongg 4a60312b80 Opening an InDesign document says to export IDML (#21)
.indd and .indt files (recognised by their published 16-byte signature)
failed to open or place with a confusing format error. They now explain
that the format is closed and how to export IDML from InDesign instead.

File › Open offers .indd and .indt files (desktop and web), and dropping
one on the window opens it like a .designcraft or .idml file. A file that
can't be opened or placed from File › Open, Place, a drop, the command
line or the control channel's app.open shows an alert with the reason, as
well as the status line.
2026-10-07 00:05:20 -04:00
aiongg 028106e0f4 Kerning survives a colour change (#29)
Each formatting run was shaped on its own, so a pair split by a colour,
underline or other paint-only change lost its kerning (and ligatures and
Arabic joining across the change). Pieces of a paragraph whose shaping
attributes are equal (everything but fill, stroke, underline and
strikethrough options, skew, ruby, kenten, conditions, tracked insertion
and XML tags) are now shaped as one run, and each glyph takes the style
of its cluster. A cluster that would span two styles (a ligature over a
colour change) is shaped apart, as before, so each letter keeps its colour.
2026-10-06 18:15:12 -04:00
aiongg b6162dd11d Transform dialogs: Rotate and Shear open their dialogs (#34)
A parameter written as `key (description)` was dropped by the command
form parser, so Object › Transform › Rotate… and Shear… (and Basic
Feather) had no required field, opened no dialog and ran with defaults.
The key is now the leading word and the parenthetical becomes its hint.
Double-clicking the Selection, Rotate, Scale or Shear tool opens Move,
Rotate, Scale or Shear.
2026-10-06 18:13:29 -04:00
aiongg 270984fab4 Images: PSD composites decode by colour mode
Decode the merged composite of .psd/.psb files in designcraft-images
(public file format spec) instead of the psd crate, which mapped
channels by count: grayscale with extra alpha/spot channels rendered
yellow, blue or invisible, and RGB + one spot channel was read as RGBA.

Channels now map by colour mode (Bitmap, Grayscale, Duotone, Indexed,
RGB, CMYK via the uncalibrated CMYK formula, Lab; 8 and 16 bit; raw and
PackBits). The first extra channel is the alpha only when the layer
count is negative (also via Lr16/Lr32), un-matted from white; other
extra channels are ignored. Damaged or oversized files return None
without panicking. Drops the psd dependency and its panic paths.
2026-10-06 18:12:14 -04:00
EthanSuquetandClaude Opus 5.5 873d293017 PDF: PDF/X-4 flags device RGB under its CMYK output intent
check_pdfx4 didn't look at colour spaces, so a placed RGB PNG (or a CMYK
TIFF converted to RGB, #35) went into a PDF/X-4 file as DeviceRGB under the
CMYK output intent with an empty warnings list. PDF/X-4 lets RGB in only
when it is colour-managed: ICCBased, or DeviceRGB remapped by a DefaultRGB
colour space. DeviceCMYK and DeviceGray are the intent's own values.

The check now reads the file with hayro-syntax and, when the PDF/X output
intent's profile has four channels, walks each page: its content, the
images, forms (placed PDFs), patterns, shadings and soft masks it uses, and
the transparency groups. It reports DeviceRGB (or Indexed over it) images
with their object number and pixel size, RGB fills and strokes, RGB
gradients, RGB inline images and groups blending in RGB, each with the pages
it is on, unless a DefaultRGB is in scope. Like the other PDF/X findings
these are export warnings. The separate "some transparency groups still
blend in RGB" warning is gone: the group check covers it, with the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 16:13:06 -04:00
EthanSuquetandClaude Opus 5.5 16694c8f3c PDF: placed CMYK TIFFs keep their inks
A CMYK TIFF went into every PDF, PDF/X-4 included, as a DeviceRGB image:
load_image sent anything that wasn't JPEG, PNG, GIF or WebP through
designcraft_images::decode_rgba, and `image` decodes CMYK TIFFs to RGB. 100%
K came out as RGB black, which the press separates as four-colour black
(#35).

designcraft-images now reads a CMYK TIFF's ink values with the tiff crate
(the version `image` already uses): 8- or 16-bit, interleaved, opaque or
with unassociated alpha. PDF export writes them through krilla's CustomImage
as DeviceCMYK, as it does a CMYK JPEG, and leaves out the TIFF's own ICC
profile so the numbers go to the output intent's press unchanged. PDF/A
exports stay RGB. A CMYK TIFF this can't read (planar, premultiplied alpha,
another ink set, over 256 MiB) is still converted, now with a warning. The
screen keeps decoding to RGB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:15:09 -04:00
Brandon ThomasandClaude Opus 5.5 d582277cc7 i18n: fonts from craft-fonts, not the repo; rebase onto main
- Noto Sans CJK SC and Noto Sans Arabic now live in storytold/craft-fonts
  (byte-identical to upstream); the UI picks them up by script (Hans,
  Arab) from CRAFT_FONTS, Chinese forms first in the zh interface, and
  the fonts reinstall when the interface language changes.
- Rebased onto main: zh column for the vertical-type and smart-guide
  rows added since; duplicate rows removed; ROADMAP merged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:12:49 -04:00
Shao Wenbin 11900ad923 UI: add translation for remained UI 2026-10-06 15:12:49 -04:00
Shao Wenbin 9d85777546 UI: add Chinese and Arabic localization with RTL-safe interface text
Extend interface language selection with Chinese and Arabic translations
across menus, dialogs, panels, tooltips, and common application controls.
Keep English fallback for untranslated strings, return borrowed translation
text, and validate translation key uniqueness and language switching.

Bundle redistributable Noto CJK and Arabic fonts with OFL license files and
ASSETS.md attribution so native and WASM builds have portable glyph coverage.
Register Arabic regular and semibold families while retaining existing font
fallbacks for proportional and monospace controls.

Render Arabic labels using Unicode bidirectional runs and contextual shaping.
Wrap logical text at grapheme boundaries before ordering each visual line,
mirror neutral punctuation, preserve logical source text for accessibility,
and handle truncation, empty lines, and mixed Latin text and numbers. Keep
ASCII labels on the normal rendering path. Disable selection on shaped RTL
labels because egui's default label cursor mapping assumes LTR text.

Adapt welcome controls, menu ordering, popup alignment, and new-document rows
for RTL layout. Bound popup geometry and avoid unsupported RTL grid behavior;
keep numeric inputs LTR. Isolate user-provided document names from Latin
application and zoom metadata. Interface language changes leave document
binding, paragraph direction, editable text, and engine state unchanged.

Add regressions for contextual Arabic joining, bidirectional punctuation,
mixed document names, logical wrapping, truncation, language switching, and
finite widget geometry. Update the roadmap with localization coverage.
Apply equivalent chunk-iteration and PDF Option/borrow simplifications needed
by the current Rust toolchain's strict Clippy checks.

Validation:
- cargo xtask ci: fmt, Clippy, native tests, assets, and layers passed;
  native tests total 517 passed and 2 ignored.
- UI regression suite: 26 passed.
- Headless UI screenshots verified Arabic welcome/new-document creation,
  menus, mixed-script document names, and switching back to Chinese/English.
- Default WASM gate is blocked by this host's missing precompiled wasm32
  standard library. All 15 WASM crates pass using the installed Rust sources:
  RUSTC_BOOTSTRAP=1 CARGO_UNSTABLE_BUILD_STD=std,panic_abort
  target/debug/xtask wasm.
2026-10-06 15:12:49 -04:00
epfabianandClaude Opus 5.5 9bbaa2940a Canvas: middle-mouse drag pans the view
Dragging with the middle mouse button pans the canvas with any tool, like
Space-drag, and shows the grabbing hand. Tools still only see the primary
button. ui.click / ui.drag accept "button": "middle".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:34:28 +02:00
Brandon ThomasandClaude Opus 5.5 a6519d8a55 Fonts: use craft-fonts as an optional build input; move the Japanese fonts out
Shippori Mincho (8.7 MB) and its licence leave assets/fonts. Japanese fonts now
come from storytold/craft-fonts when built with CRAFT_FONTS_DIR (never a
Cargo.toml dependency): crates/fonts/build.rs embeds its manifest as
designcraft_fonts::CRAFT_FONTS. Native builds embed all four fonts; wasm32
embeds BIZ UDPGothic Regular only (web size budget).

- UI (egui): the Jpan faces at the end of every family, BIZ UDPGothic first
  (Bold first in the semibold family).
- Documents: FontDb loads them after the bundled fonts, Mincho first, so they
  are the Japanese fallback ahead of system fonts; SVG text gets them too.
- Vertical alternates test runs on every craft-fonts face and skips when
  CRAFT_FONTS is empty; new UI no-tofu test and without-craft-fonts tests.
- FreeBSD CI tests with craft-fonts; release.yml builds every platform with
  CRAFT_FONTS_DIR + CRAFT_FONTS_REQUIRED=1 at a pinned commit, packages carry
  OFL-<family>.txt; NOTICE, ASSETS.md, AGENTS.md/CLAUDE.md, README, ROADMAP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 11:01:35 -04:00
Brandon ThomasandClaude Opus 5.5 99b6228abd Snap: snap preferences as a command, overlay colours from tokens, tidy-up
- view.snapPreferences {alignEdges, alignCenters, smartDimensions,
  smartSpacing, zone} sets the smart guide options; the Preferences
  dialog goes through it, so the control channel and MCP reach them.
- Smart guide, gap and measurement colours come from theme::Tokens.
- Remove the unused closest-target helper (snap_rect and friends).
- Drop the agent planning docs (docs/superpowers) and the .worktrees
  ignore line; ROADMAP entry for smart guides and snapping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 09:05:59 -04:00
Cameron Gilroy 78605f2944 Snap: visible bounds and constrained gestures 2026-10-06 09:05:59 -04:00
Cameron Gilroy b0f9773205 Snap: view commands and guide preferences 2026-10-06 09:05:59 -04:00
Cameron Gilroy 09c8dc3f06 Snap: pen and anchor points 2026-10-06 09:05:59 -04:00