- release.yml: new linux-riscv64 job (cross-compiled on ubuntu-24.04 against
ports.ubuntu.com riscv64 libs, tar.gz only, CLI smoke-tested under QEMU),
ported from GridCraft; the draft release job needs it, so SHA256SUMS covers it.
- packaging/linux/package.sh: CROSS_ARCH/CROSS_TARGET/CROSS_COMPILE/EMULATOR
support, as in GridCraft.
- cargo xtask version set 0.6.0; README, hardware parity and ROADMAP log note
the new platform.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Conflict: crates/compose/src/tests.rs: tests only, both (#310's tight word spacing test, #316's GREP style test)
#316's overlay test calls overlays() with the drop_end argument next added (#83).
One shared compiler (designcraft_compose::grep) translates the GREP dialect
documents and users write: \l \u \L \U letter classes, \h \H \v \V \R \N,
\r paragraph end and \n forced line break, ~ special-character codes,
Unicode-aware POSIX classes, and literal [ & -- inside character classes.
It compiles with fancy-regex, so lookahead, lookbehind, atomic groups,
possessive quantifiers, backreferences and \K work; a backtrack limit stops
pathological patterns with an error.
GREP styles skip a pattern that fails to compile or gives up on a search,
with one log warning. Find/Change returns the error. The paragraph style
dialog validates with the same compiler. Fixes en dash (~=) mapping to an
em dash in Find/Change.
Upstream main moved 9e4f694 -> 736acff by 10 squashes: #258, #285, #153, #280, #288, #281,
#176, #299, #298, #297. New to next: #258 (datamerge test), #153 (temporary files and release
inputs), #280 (warichu), #176 (PDF image conversion cache), #297 (graphics backend before the
window). Already on next: #285, #288, #281, #299, #298.
Conflict: ROADMAP.md: next's lines; CJK1 takes main's wording (ruby unfinished, warichu set after the line is broken)
Conflict: crates/compose/src/lib.rs: list labels (#298): next's list_label structure; paragraph start / break moves: next's `go` (with #295's sub-columns) under the maintainer's #285 comment; Cursor: next's start/next_page/next_baseline with tops; line placement: #280's warichu::place right after layout_line, before next's trimmed trailing spaces and the drop cap splice (so neither is stacked and the spaces follow the closed-up end_x); caret(): next's drop-cap branch first, then #280's stacked-row metrics
Conflict: crates/compose/src/tests.rs: next's tests kept; #280's tests auto-merged
Conflict: crates/engine/src/cmd/text.rs: both (next's TypingFormat/typing_format, #280's warichu_cmd)
Conflict: crates/idml/src/tests.rs: next's side; #280's warichu round-trip test auto-merged
Conflict: crates/pdf/src/export.rs: #176's content cache and test counter with next's RasterMode (no Exporter `interpolate` field on next, so the maintainer's `mode.interpolate &= self.interpolate` is not carried); test exporter gets next's drawing_items field
Conflict: crates/ui-egui/src/canvas.rs: #280's compose::highlight_quads (its RTL branch equals next's mixed-direction spans) followed by next's drop-cap highlight
Conflict: crates/ui-egui/src/menus.rs: next's formatting_affects_text test kept
Auto-merge duplicates removed: #288's table-style tests and #298's list test in idml tests.rs,
#288's tests in doc styles.rs and #285's docx test (both files equal next's), #281's dialog
tests in dialogs.rs (equals next's) and its menu_button/menu_max_height/clipped_submenu in
menus.rs. contributors/people.toml takes main's (next had a duplicated
[people.emanuelebonaventura] table from the 9e4f694 merge, which broke the ui-egui build
script's TOML parse).
Maintainer edits carried over: #285 break characters and Next Column through one closure
(next's `go`, comment added); #281 viewport-aware menu_button in the app bar and the Paragraph
menu, per-dialog widths clamped to the window (all already on next); #280 warichu after the
last-line rules (layout_line with ends_para/forced_mid) and rules at each warichu row's
baseline (rule_baseline in render and pdf text_rules); #176 CMYK fallback through
lossless(.., mode) and its updated contract tests; #258 test fixes; #153 and #297 as landed.
InDesign documents and templates (.indd, .indt) 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 indd-utils
(github.com/aiongg/indd-utils, rev 9cf456d, 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`. A file the converter can't read is an open error ("can't
convert the InDesign file: ..."), 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.
New designcraft-pptx crate (L3) and file.exportPptx command (File ›
Export PowerPoint…, CLI --export x.pptx). Each page becomes a slide of
native objects: shapes with fills, gradients, strokes and effects,
pictures cropped like their frames, native tables, and text boxes.
Text keeps DesignCraft's composition by default: composed lines end in
line breaks, justified spacing becomes character spacing, and leading
becomes percentage line spacing (PowerPoint rounds exact spacing to
whole points; its 100% line is 1.2 em for every font). Threaded
stories split at their frames and wrapped lines get their own boxes.
lineBreaks: reflow writes one box per frame in native columns instead.
TrueType fonts are embedded as Embedded OpenType when their licences
allow. Objects PowerPoint can't represent (placed PDF/EPS, type on a
path, some effects) are rasterised through the existing
rasterize_where path.
Checked in PowerPoint for Mac and LibreOffice: on the sample magazine,
word positions match DesignCraft's PDF to within 0.8 pt horizontally
and 1.6 pt vertically.
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.
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.
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>
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.
Fixes the Windows installer: the Start Menu shortcut and Add/Remove Programs icon were blank, and the shortcut description was wrong. Release builds no longer open a console window behind the app.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGENTS.md and CLAUDE.md get a "Never crash" section ahead of the
non-negotiables (craftrules standards/never-crash.md). Root clippy.toml lets
tests keep unwrap/expect/panic/indexing once crates deny them, and
unsafe_code goes from deny to forbid (no unsafe or allow(unsafe_code) in the
workspace).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- designcraft-textimport (L3): DOCX (styles by name with spacing/indents/alignment and font,
size, bold/italic/underline/strike/caps/position; runs, tabs, breaks, footnotes, tables,
hyperlink/field results; used styles only), RTF (text, paragraphs, bold/italic/underline/
strike, size, Unicode/cp1252, skipped destinations), plain text (+ tests)
- engine: file.place routes text files into the insertion point, the selected frame or a new
frame on the page; imported styles added (existing win); removeStyles; autoflow adds pages
with threaded frames until the story fits (+ test)
- app/web: Place dialogs accept .docx/.rtf/.txt/.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
apps/designcraft-web runs DesignApp through eframe's web runner (wgpu:
WebGPU with WebGL2 fallback, ?webgl forces GL, ?sample opens the sample).
Services gain open_async, download and an inbox: browser-picked and
dropped files are fed back as file.openBytes (.designcraft) or file.place
(images, base64); Save/Export download via Blob + anchor. The web app is
excluded from default-members.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>