Commit Graph
63 Commits
Author SHA1 Message Date
aiongg 51e55fa145 Integration: README takes #998's font guidance instead of #701's 2026-10-16 04:12:33 +00:00
aiongg 18ae8e4761 Merge upstream main a184db6f8 with our 15 PRs (batch-0) into next
Conflicts resolved per file (both sides kept unless noted):
crates/engine/src/atomic.rs | 1 | main's: `write_file` removed (main routes command writes through `crate::io::write_file`); its one caller in file.rs now uses `crate::io::write_file`
crates/engine/src/cmd/datamerge/fill.rs | 1 | next's `Graphic` literal (has `clip` and `wrap`, which next's `Graphic` carries)
crates/engine/src/cmd/datamerge/mod.rs | 1 | main's `read_path_capped` (crate::io metadata/read_capped, roots checked); next's capped read is the same behaviour
crates/engine/src/cmd/datamerge/parse.rs | 1 | main's (`crate::io::metadata`, `crate::io::Metadata`)
crates/engine/src/cmd/edit.rs | 1 | next's `spread_param(p, "edit.paste")` (the second argument is the command id on both sides)
crates/engine/src/cmd/export.rs | 3 | main's: EPUB params doc, `toc_title` once (main's position; next's duplicate dropped)
crates/engine/src/cmd/file.rs | 7 | place doc: next's (lists page/rect/autoflow params #803 checks); next's recent-file functions + main's `foreign_document`; next's open (load_bytes, warnings, non-DesignCraft refusal) with main's checked `crate::io::read_file` for the bytes; main's `check_write` be
crates/engine/src/cmd/find.rs | 7 | main's Find scope (FindContext, scope/selection/story, continuation, UTF-8 repair) on next's `designcraft_compose::grep::Grep` (dialect GREP): find uses `find_all` capped at MAX_MATCHES, change uses `replacements`/`find_all` (literal change text not expanded), fin
crates/engine/src/cmd/fonts.rs | 1 | next's (`has_style`, resolved/replacement face); `has_style` already compares styles ignoring spacing and case, which is main's `same_style` fix; main's test kept
crates/engine/src/cmd/interchange.rs | 1 | next's `import_idml_report_with_previews` (previews for unreadable links)
crates/engine/src/cmd/layout.rs | 8 | pages.insert: main's overflow-safe `after` + next's checked `parent_ref`; main's duplicateSpread doc; layout.section: next's `SectionEdit` (already keeps unnamed settings, #717) with main's `d.repaginate()` moved into `SectionEdit::apply` (remove and set paths),
crates/engine/src/cmd/links.rs | 5 | next's links.list (no doc clone); main's `text_status` via crate::io; `use std::io::Read` dropped (unused after main's read_capped); test literals main's. `link_missing` (next) uses `crate::io::exists` for the file-guard scan
crates/engine/src/cmd/object.rs | 4 | object.fill/stroke tint-alone: main's (23e1680e7; out-of-range tint is an error, which main's test asserts); object.fit doc: next's (lists `axis`)
crates/engine/src/cmd/paths.rs | 1 | next's (shatai transform on outlines)
crates/engine/src/cmd/place_text.rs | 1 | next's `add_flow_frame` (used by autoflow)
crates/engine/src/cmd/preflight.rs | 2 | next's overset/unplacedStory issue (its `overset_location` already applies the parent transform main's #738 fix adds); next's two test modules kept with main's
crates/engine/src/cmd/scripts.rs | 1 | combined: next's `in_undo_step = false` (#406) + main's full rollback of a failed script (#709)
crates/engine/src/cmd/style.rs | 14 | param docs next's (gradient swatch.create, swatch stops, model colours); create_para next's; rename_style main's structure (rename entry, then `redirect_style_refs`), redirect has next's full reference set (cells, defaults, notes, TOC) + main's never-based-on-it
crates/engine/src/cmd/text.rs | 10 | main's selectSentence/Paragraph/Story + select_around; next's selectionAttrs (mixed) + main's openTypeFeatures/type.feature; main's comments; tracked typing: next's `reserve_command_text` + main's `insert_format_at`; empty-paragraph mark formatting main's (with `
crates/engine/src/cmd/thread.rs | 1 | next's `spread_param(p, "text.thread")`
crates/engine/src/dtd.rs | 1 | next's linear, depth-bounded `expand_parameter_entities` with main's budget (input + 1 MiB, `MAX_EXPANDED_BYTES`) and message ("expand the DTD beyond"); 16 MiB constant removed; both sides' tests pass on message
crates/engine/src/guard.rs | 2 | main's whole-transaction snapshot (docs, active, journal; #742) + next's `in_undo_step` restore; tests both
crates/engine/src/lib.rs | 5 | LoadedGraphic doc next's; next's `new_document_preview`; execute: main's `discard_stale_find_scope()` before next's nested-undo run; modules both (tests_autosize, tests_file_guard, tests_params, tests_roots)
crates/engine/src/recovery.rs | 1 | next's test (superset of main's assertion)
crates/engine/src/tests.rs | 4 | moved tests deduplicated (identical on both sides); next's preflight and direct-selection/kerning tests + main's style-delete, locked-frame and baseline-fit tests
crates/engine/src/tests_idml.rs | 3 | main's order (drop cap and margins tests identical on both sides, once each)
crates/ui-egui/src/canvas.rs | 3 | next's screen_options/DisplayKey block and tests kept; two tests that auto-merge had added twice (parent_guides_on_a_page_are_not_picked_there, baseline_grid_lines_are_the_ones_on_the_page) kept once; main's `typing`/`screen_at`/`click` helpers and its tests clicks
crates/ui-egui/src/control.rs | 3 | main's `count` check and pending budget (control queue + synthetic queue); exact-budget test runs both sides' cases (click 255 on 9,492 pending; drag 9492×255)
crates/ui-egui/src/cursors.rs | 1 | main's (same Pen cursor set)
crates/ui-egui/src/dialogs.rs | 14 | dialog body (newDocument … alert match) is next's text, with main's Find/Change scope reset (`set_field`, `reset_find_scope`, `find_change_params`) and main's Create Guides / Margins and Columns arms ported in; `Dialog::new` ruby section (next) + main's `set_fi
crates/ui-egui/src/i18n.rs | 7 | ka and pl modules, languages, statics and lookups both; `category_first` covers uk, ru, pl, ka and `count_label` keeps next's Czech plurals; shared TABLE union; next's duplicate rows for Auto, Number:, Gutter:, Top:, Bottom:, Inside:, Outside:, Left:, Right: dropped
crates/ui-egui/src/i18n/ar.rs | 2 | union of rows, no duplicate keys
crates/ui-egui/src/i18n/it.rs | 1 | union of rows, no duplicate keys
crates/ui-egui/src/i18n/ja.rs | 1 | union of rows, no duplicate keys
crates/ui-egui/src/i18n/pt_br.rs | 1 | union of rows, no duplicate keys
crates/ui-egui/src/i18n/uk.rs | 1 | union of rows, no duplicate keys
crates/ui-egui/src/icons.rs | 2 | both tests (main's typography icon, next's distribute icons)
crates/ui-egui/src/lib.rs | 11 | UiState: next's tabs_panel + main's last_color/last_gradient; `cursors` field once; next's SVG paste and paste-on-spread-in-view; next's extensionless document open; opens_as_document next's comment; tests both (next's control bar / key-name tests, main's rich black
crates/ui-egui/src/menus.rs | 15 | app.language doc next's text with pl and ka; UI_COMMANDS both (next's Tabs, Toggle Presentation, Apply None text; main's panel commands, Apply Color, Apply Gradient); Edit › Interface Language stays out (next moved it to Preferences); Type menu main's order with
crates/ui-egui/src/panels/glyphs.rs | 1 | next's (already has main's scroll-bar fix); the scroll-bar test module auto-merge had added twice kept once
crates/ui-egui/src/panels/layers.rs | 3 | next's drag-and-drop `object_rows`, with main's features ported into it: selection reveal (layer opens, row scrolls into view once), selected rows highlighted (also a group whose member is selected), double-click rename in place (`object.rename` queued like
crates/ui-egui/src/panels/mod.rs | 6 | tabs + typography modules and color_panel_tests; SelInfo has wrap_side/wrap_contour and wrap_offsets (offsets from the graphic's own wrap when it is selected); next's swatch_picker returning the chip response; next's content_selection_tests
crates/ui-egui/src/panels/pages.rs | 1 | next's (parents dragged by id)
crates/ui-egui/src/panels/properties.rs | 4 | next's swatch popup (Apply To, Tint); main's four wrap offsets then next's Wrap To / Contour Type; test fixtures main's (`..Default::default()`, no unused builder)
crates/ui-egui/src/panels/swatches.rs | 3 | main's Delete Swatch button + next's New Swatch comment; next's draggable rows; click: main's PICKED + fill/stroke in front, with next's no-apply on double-click
crates/ui-egui/src/toolbar.rs | 2 | main's Apply Color / Gradient / None wells and functions; next's apply_none doc line
crates/compose/src/lib.rs | 5 | next's line loop kept (mark_leading + last_line_mark, wrap segments/carry, grid gyoudori); main's mark-chars base_leading block (auto-merged) stays beside it. `fits`: next's #106 rule (baseline fit for horizontal frames, full descent for paths, vertical text, footnote
crates/compose/src/tests.rs | 5 | next's tests (tombstone set, sliver/one-sided/contour/clipping wrap tests, borders, lists, kenten, grid, anchored wrap, balance, shaped frames) plus main's an_empty_last_paragraph_isnt_overset; main's wrap_object_beside_one_narrow_column_leaves_the_other_alone re-ad
crates/doc/src/assets.rs | 1 | main's doc comment (same meaning)
crates/doc/src/build.rs | 3 | parent_page_for: next's parent_page_for_side (RTL-aware); single_sided_page_shows_first_parent_page test kept once, at main's position
crates/doc/src/item.rs | 1 | next's rotated_group_bounds_follow_the_children_outlines test kept
crates/doc/src/lib.rs | 1 | next's kerning_increment field kept; main's "Bulleted & Numbered" wording
crates/doc/src/page.rs | 1 | next's outer_page_indices + parent_page_for_side (integration of parent-margins with rtl-master-sides); main's parent_page_index dropped, its only caller (build.rs) uses parent_page_for_side
crates/doc/src/slice.rs | 5 | extract: next's `marked()` (get-based, fix_notes/fix_endnotes/fix_marks; main's version indexed slices and could panic); insert_story: main's take() limit on endnote/editorial payload copies with next's id comment, redundant `let ne`/`let nn` dropped; main's excess_note
crates/geom/src/corners.rs | 1 | next's box_outline_rounds_only_closed_corners test kept
crates/render/src/damage.rs | 1 | next's wrapping-anchored-object damage test kept
crates/render/src/fx.rs | 2 | feather: next's choke/corners sigma+join inside main's structure (body and clip at device resolution, with_filters(.., None)); inner glow centre: next's blend `mix` with main's clip argument (bp, xf)
crates/render/src/lib.rs | 3 | next's layer comment; next's front baseline grid draw after items; gradient match on g.kind (main's tuple scrutinee did not match the single-pattern arms)
crates/render/src/text.rs | 5 | paint_glyphs: main's paint_stroke closure structure with next's stroke overprint (overprinting helper, stroke `(TextPaint, bool)`); callers pass next's overprint_fill/overprint_stroke
crates/render/tests/placed_pdf.rs | 1 | main's `near` helper version
crates/tools/src/lib.rs | 1 | main's (PenConvert already declared below, avoids a duplicate variant)
crates/tools/src/pen.rs | 1 | main's module doc
crates/tools/src/select.rs | 1 | next's Drag::Corner variant (live corners) kept
crates/tools/src/tests.rs | 4 | next's tests (content drag, live corners, table border drag, eyedropper matchFrom, fitting handles, pen cursors once); eyedropper_ignores_inactive keeps next's samples_image check (main's exact-JSON compare lacks matchFrom) with main's `..Default::default()` Asset lit
crates/tools/src/text.rs | 2 | next's table border drag (BorderDrag, border_at) kept, then main's comment on locked text frames
crates/tools/src/xform.rs | 2 | main's explicit `Vec<&Item>` for shown children; next's eyedropper matchFrom (integration 796e9d713)
Cargo.toml | 2 | main's craft-pdf workspace dep added (craft-print stays once, in next's craft-libs block); [patch.crates-io] keeps next's winit (rust-windowing #4694 backport) and adds main's krilla patch; main's skylartaylor winit left out (see UNSURE 1)
Cargo.lock | 1 | union: next's craft-atomic and craft-cms entries plus main's craft-pdf entry; needs `cargo` normalisation
README.md | 1 | Open bullet combines INDD import via indd-utils (next) and editable PowerPoint export (main); main's paragraph break kept
contributors/people.toml | 1 | both people kept (switch87 from next, Nmarello from main)
apps/designcraft-cli/src/main.rs | 4 | next's `Export` enum dispatch kept; main's .pptx export added as `Export::Pptx` (run prints slides and warnings, script runs file.exportPptx); main's `--pdf-options` null-as-{} parse; usage lines list .pptx
apps/designcraft/src/main.rs | 3 | `startup.leave()` right after `app.ui` (main #380) and next's macOS `sync_movable` kept after the IME discard; next's Apple Events install kept; main's macOS Dock Quit `with_close_requested_on_terminate` block left out (needs the skylartaylor winit; UNSURE 1)
crates/fonts/src/fontdb.rs | 9 | FONT6 aliases (next) combined with #911 WWS names (main): ScannedFace and both CatalogEntry constructors carry `wws` and `aliases`; `canonical_family` falls back to WWS family names; `exact_style_traits` canonicalises then tries typographic, then WWS names (`named_st
crates/format/src/lib.rs | 1 | tests: both sides kept (next's r7a nullable-default tests; main's oversized ZIP entry/asset/entry-count tests)
crates/idml/src/import.rs | 11 | main's bounded `Package` reader under next's `import_idml_report_with_previews` (metadata read through `pkg.part`); next's `tab_list_repaired` kept; ruler origin: next's `settings.ruler_origin`, and main's guide import reads it (main's private `RulerOrigin` enum and
crates/idml/src/tests.rs | 6 | item-level union: all next tests plus main's new ones (ruler guides, package limits, CJK leading model, liquid page rules module, mojikumi); no test dropped
crates/mcp/src/backend.rs | 1 | test comment merged from both
crates/pdf/src/tests.rs | 1 | tests: both sides kept
crates/pdf/src/text.rs | 4 | next's (skew `tan`, cluster `start`, ruby overprint warning); main had no change here beyond base
crates/textimport/src/docx.rs | 5 | next's (ListCounter integration for list levels, page-break test position); main's side was the older form of the same code
crates/epub/src/lib.rs | 30 | non-test code is next's (StoryWriter holds img_src/images/no_alt/heading_ids; covers main's #787/#791/#782 fixes, plus #314 group transforms, anchored images in images_without_alt, endnote story skipped in the TOC); tests: next's set plus main's extra css_weight_style a
docs/control-protocol.md | 2 | next's rows (ui.paste, count 1–255, documentGrid) and wording
docs/file-format-parity.md | 1 | rows combined (next's ICC notes, main's TIFF indexed colour)
docs/gaps.md | 2 | status change notes unioned; Flex Layout removed from missing (main implemented it), next's Parent Options sentence kept
docs/localization-parity.md | 4 | Polish and Georgian rows; 5 languages beyond the twelve; file list includes cs and ka; both history rows
docs/roadmap.md | 1 | M1 next's (#186 fixed on next), M2 main's IME wording
docs/target-app-parity.md | 6 | next's status line; File formats row next's, UI/UX row main's (IME no longer failing); UI line next's plus main's Swatches detail; one Page tool line (main's fuller one); Load styles and main's fuller Pathfinder line both kept, main's duplicate short Pathfinder line r
docs/ui-parity.md | 1 | IME row main's, Font menu row next's

i18n/fr.rs: five rows dropped that main's shared table now has (Row, Open Path, Flex Layout, Current Page Number, Rulers).
2026-10-16 03:09:22 +00:00
aiongg 4186f95aed Merge upstream main a930276 into gpu-startup: the indirect-call validation fix is kept once
Conflicts:
- README.md: one WGPU_VALIDATION_INDIRECT_CALL row (this branch's wording).
- apps/designcraft/src/gpu.rs: main's only change is a test tweak in the backend-fallback tests, which now live in gpu/backend.rs; kept this branch's file and ported the tweak there (the check depends on the chosen backend, not the candidate count).
- apps/designcraft/src/main.rs: dropped main's inline VALIDATION_INDIRECT_CALL block (#664) in favour of gpu::instance_flags(); kept the adapter selection, restart and first-frame watch, and took main's macOS Dock Quit handling, preserve_documents_on_exit in on_exit, and profile::config_dir/recovery_dir.
- crates/engine/src/recovery.rs: took main's version; its retained recovered checkpoints do what this branch's recovery change did.
- ROADMAP.md: main's file plus this PR's one progress-log line.
2026-10-15 06:15:27 +00:00
Brandon Thomas 6132b60e9b Merge PR #170 2026-10-15 00:35:26 -04:00
Brandon Thomas d2f2ecc940 Merge PR #903 2026-10-14 22:05:12 -04:00
Brandon Thomas 3614ae7255 Merge PR #664 2026-10-14 22:05:11 -04:00
ujo4evaandClaude Opus 5.5 6cacf4e8b7 Linux: build an Arch package (.pkg.tar.zst)
package.sh now also builds designcraft-<ver>-linux-<arch>.pkg.tar.zst with nfpm's archlinux packager,
from the same nfpm.yaml. It is named by the bundle id (ai.storyteller.designcraft), provides designcraft and
conflicts with designcraft, designcraft-bin and designcraft-git, so an AUR helper doesn't take it over and ArtCraft
Launcher can tell it from an AUR build. The README lists it with the other Linux downloads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:54:12 +01:00
aiongg a6621723b9 Merge #121: README: install on Gentoo from the ::snakebyte overlay
# Conflicts:
#	contributors/people.toml
2026-10-13 19:16:01 +00:00
Gert Pellin 6ae1d6dc31 README: install on Gentoo from the ::snakebyte overlay 2026-10-13 19:25:33 +02:00
aiongg 7ad3d12883 Merge indd-import: open .indd and .indt files through indd-utils 2026-10-13 16:18:53 +00:00
aiongg a7c3e330ec INDD: open .indd and .indt files through indd-utils (#21, #114)
.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)
2026-10-13 16:15:15 +00:00
Philipp Krüger f8474fa1c8 Merge branch 'main' into feat/pptx-export 2026-10-13 14:44:29 +02:00
aiongg ac6177116b Merge pr/701: docs: fix the README font integration link (#701) 2026-10-13 12:30:04 +00:00
haranishi bd93ea92c3 docs: READMEの公開フォントガイドへのリンクを修正 #376 2026-10-13 20:04:00 +09:00
aiongg 605b31c6d6 Merge pr/663: CLI: accept a UTF-8 BOM in scripts and document the syntax in script --help (#663) 2026-10-12 23:56:41 +00:00
fabian-coandClaude Opus 5.5 260af3b5df macOS: open the window on Intel Metal by skipping indirect-call validation
wgpu validates indirect draw and dispatch arguments with a compute shader it
compiles when the device is created. Metal on an Intel Iris Pro (MacBookPro11,3,
macOS 12.7.6) fails to compile it ("Compiler encountered an internal error" in
MTLCompilerService), the device is lost, and the window never opens.

DesignCraft draws and dispatches nothing indirectly, so leave the check out of the
instance flags. WGPU_VALIDATION_INDIRECT_CALL=1 turns it back on. VectorCraft
does the same (storytold/vectorcraft#651).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:15:02 -05:00
Marco Arnulfo 9e15d5a17e fix(cli): accept a UTF-8 BOM in scripts and document the syntax in script --help (fixes #654) 2026-10-13 00:41:46 +02:00
aiongg 6d2163d497 Merge #580 (update): portable mode needs a writable DesignCraftData
Conflict: apps/designcraft/src/main.rs: next's catch_unwind/run_native app creator kept; the portable note is set after load_prefs inside it
2026-10-12 14:41:07 +00:00
Marco Arnulfo 1207ab14d3 feat(desktop): portable mode needs a writable DesignCraftData (#574)
A portable copy unzipped into a read-only folder such as Program Files
kept pointing settings and recovery at a DesignCraftData it could not
write, so both were lost without a word. The data folder is now probed
(created, then a file written and removed) and, when that fails, the
platform folders are used as if there were no portable.txt; the log and
the status bar say which folder could not be written.
DESIGNCRAFT_CONFIG_DIR still wins. Adds
a_portable_install_that_cannot_write_its_data_uses_the_platform_paths.
2026-10-12 16:30:58 +02:00
aiongg 814153ba62 Merge #580: feat(desktop): portable mode, portable.txt next to the executable (#574)
Conflict: apps/designcraft/src/profile.rs: recovery_dir takes the PR's root_with (config override, else portable folder) and keeps next's .map(own_run) and own_run
Conflict: README.md: the PR's Portable mode section, then next's Graphics backend and processor section
2026-10-12 14:17:27 +00:00
Marco Arnulfo b4eedc42eb feat(desktop): portable mode looks next to DesignCraft.app on macOS (#574)
Inside a macOS bundle the executable sits in DesignCraft.app/Contents/MacOS,
a signed folder nobody edits, so the marker and DesignCraftData are looked
for next to the .app, as craft-settings does. Adds
inside_a_macos_bundle_the_marker_sits_next_to_the_app.
2026-10-12 15:09:02 +02:00
Marco Arnulfo 4acd5ba43c feat(desktop): portable mode, portable.txt next to the executable (#574)
A file named portable.txt beside the executable keeps settings, logs,
the GPU start-up record and crash recovery in a DesignCraftData folder
next to it instead of the per-user folders, as PhotoCraft and FilmCraft
do. A folder of that name is not a marker. DESIGNCRAFT_CONFIG_DIR still
wins, empty or not. The Windows portable zip now ships portable.txt;
the MSI and the macOS app bundle don't, so nothing changes there.
2026-10-12 13:45:05 +02:00
aiongg 2fae23fcc6 Merge atomic-save: MCP: exported files replace the target atomically (#436)
Conflict: ROADMAP.md: both progress-log entries, next's newer ones first
Conflict: apps/designcraft/src/gpu.rs: next's side; the branch's test fix targets the startup record tests next replaced
Conflict: apps/designcraft/src/main.rs: next's gpu startup and macOS IME helper; config_dir() dropped for the branch's profile::config_dir(), recovery_dir from profile::recovery_dir()
Conflict: crates/ui-egui/src/canvas.rs: next's guard (menu_open, keyboard_pane already limits keys to the focused pane)
Conflict: crates/ui-egui/src/lib.rs: modules from both sides
2026-10-11 05:16:10 +00:00
aiongg ce144a614a Merge remote-tracking branch 'upstream/main' into next
# Conflicts:
#	ROADMAP.md
2026-10-11 00:30:35 +00:00
skylar taylor-barrick a77bf8bff5 UI.9: reconcile upstream before shared UI landing 2026-10-10 18:00:07 -06:00
Brandon ThomasandClaude Opus 5.5 a9124a0517 Release prep: version 0.6.0; Linux riscv64 tar.gz in releases (#398)
- 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>
2026-10-10 19:33:30 -04:00
aiongg fbfd0b2fe9 Merge gpu-startup: recovered documents survive restarts, the watchdog only restarts a hung adapter, software adapters last, the skip list as an argument
Conflicts: designcraft main.rs ui() (#366's macOS marked-text discard, then the startup watch's leave);
engine recovery.rs (the branch's rewrite-then-discard with next's bump_revision).
2026-10-10 21:28:17 +00:00
aiongg 158f366af8 Startup: restarts keep recovered documents, a busy UI never counts as a GPU hang, software renderers last
- Recovery: file.recovery.open moves each entry to the reopened document's uid
  (written before the old one is removed), so recovered documents stay on disk
  until saved or closed, also when the app restarts on another adapter or
  stops before its first recovery save.
- First-frame watch: a late first frame is logged and noted in the status bar.
  The adapter counts as hanging only when the UI thread has been stuck outside
  the app's code (logic/ui mark entry and exit) with no progress for 60 s while
  the window isn't known to be minimized, occluded or unfocused. The watch asks
  for a repaint on each look, so an idle UI ends it. VectorCraft restarts on
  the late frame alone, which a held-back compositor or a long compose can set
  off.
- Software renderers (WARP, llvmpipe) are passed over while another backend is
  left; once no hardware adapter of any backend could show the window, the app
  starts again with them allowed, once.
- A restart clears gpu.json's backend entry just before exec or spawn and puts
  it back when starting again fails. Backends a restart left out are no longer
  recorded as failed.
- The watch ends a hung process with TerminateProcess on Windows.
- The skip list travels as the restarted app's --gpu-skip= argument instead of
  an environment variable, so processes the app starts don't inherit it.
2026-10-10 21:26:51 +00:00
skylar taylor-barrick c62866443c UI.9: integrate shared panel docking and preserve workspace behavior 2026-10-10 14:42:40 -06:00
aiongg 16bb39e531 Merge gpu-startup: pick the GPU that drives the display, fall back across adapters and backends, and log startup errors (#273, #334) 2026-10-10 20:30:59 +00:00
aiongg 279336c445 Startup: pick the GPU that drives the display, restart on the next adapter or backend, and log startup errors
Ported from VectorCraft's start-up fixes (#502, #545, #651, the display-GPU
choice, #806, #964) and reconciled with the backend fallback of #297:

- The app picks the window's adapter itself (eframe's native_adapter_selector,
  apps/designcraft/src/gpu.rs): adapters that can't present never, then
  WGPU_ADAPTER_NAME, hardware before software, native backends before OpenGL,
  the GPU that drives the primary display (Windows EnumDisplayDevices through
  winsafe, Linux /sys/class/drm), the power preference (WGPU_POWER_PREF;
  otherwise power saving on Windows and macOS, the system's order elsewhere),
  then DX12 before Vulkan. Every adapter and the choice are logged.
- wgpu's indirect-call validation is off (WGPU_VALIDATION_INDIRECT_CALL=1 turns
  it back on): its compute shader failed to compile on an Intel Mac and lost
  the Metal device (#334, first error).
- run_native runs under catch_unwind. A wgpu error or a panic in wgpu,
  egui-wgpu or naga during the first frames, or a first frame that doesn't
  reach the screen in 20 s, starts the app again without that adapter
  (DESIGNCRAFT_GPU_SKIP; exec on Unix, a new process on Windows). When no
  adapter of the start's backends is left, it starts again with the next
  backend. Each restart leaves out one more adapter or backend, so they end.
  Adapters without PCI ids (Metal) are keyed by name.
- The backend fallback (gpu/backend.rs, gpu.json) stays for driver faults that
  take the process down. Windows tries DirectX 12, then OpenGL, then Vulkan,
  each in its own instance: Vulkan last because creating its instance loads
  every installed Vulkan driver, and OpenGL kept out of the DX12 instance
  because creating it crashed in AMD's atio6axx.dll (#167).
- main returns an ExitCode and logs why the app stopped to standard error and
  the log file, which is all a Windows start without a console leaves (#273).

README, architecture, gaps, hardware and target-app parity docs and ROADMAP
describe the choice, the restarts and the variables.
2026-10-10 20:26:06 +00:00
aiongg 5fae1ac2cc Merge upstream main a127c6d: progress docs (#355); ROADMAP.md takes upstream's rewrite 2026-10-10 18:47:02 +00:00
Brandon ThomasandClaude Opus 5.5 a127c6d5c3 Progress docs: target-app parity, gaps, alpha gate, readiness by audience (#355)
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, and feature, format, hardware, UI and localization parity docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:09:17 -04:00
Philipp Krüger 377fc3f3eb Merge branch 'main' into feat/pptx-export 2026-10-10 13:11:34 +02:00
aiongg aadd54a926 Merge upstream main 736acff into next
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.
2026-10-10 08:20:36 +00:00
aiongg b832cdb065 Revert "Merge #168: Fix Windows startup crash by defaulting to DirectX 12"
This reverts commit 6e8f33c386, reversing
changes made to de5d32c90f.

#168 is closed; upstream main has #297, which picks the backend before the window exists.

Conflict: apps/designcraft/src/main.rs: kept mod logging; dropped #168's graphics module and its call
2026-10-10 08:13:14 +00:00
736acffe5f Desktop: pick the graphics backend before the window exists; DirectX 12 on Windows (#297)
* Desktop: pick the graphics backend before the window exists; DirectX 12 on Windows

On an AMD hybrid-graphics laptop (Radeon RX 6800M beside an integrated
Radeon, with two versions of amdvlk64.dll loaded into one process) the
app died a few seconds after launch with an access violation inside
AMD's Vulkan driver at the first swapchain present. Nothing reached the
log: a fault inside a driver is a native crash the engine's panic guard
never sees. wgpu's default backend set (PRIMARY | GL) enumerates Vulkan
first, so every start on that machine went down the same path, while
WGPU_BACKEND=dx12 and WGPU_BACKEND=gl ran fine and the headless CPU
renderer was never affected.

The desktop app now chooses the backend before creating the window
(apps/designcraft/src/gpu.rs): DirectX 12 first on Windows, then Vulkan,
then OpenGL; Vulkan then OpenGL on Linux; Metal on macOS. OpenGL stays
in the set as the in-process fallback when the chosen backend has no
adapter. WGPU_BACKEND still overrides everything and turns the fallback
off.

Start-up fallback: gpu.json in the settings directory records the
backend being tried until the third frame begins (the first has been
presented by then) or the app exits normally. A record left behind means
that backend never showed a frame, so the next start skips it, tries the
next candidate and says so in the status bar. The list starts over when
every candidate has failed or the app version changes;
DESIGNCRAFT_NO_PREFS records nothing. The adapter, backend and driver
version are logged at start-up for bug reports.

Verified on the affected machine: a default start runs on DirectX 12; a
simulated crashed DX12 start moved to Vulkan, which faulted for real,
and the start after that came up on OpenGL with the status line. Nine
unit tests cover the chooser and the record; cargo xtask ci passes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Merge origin/main; on Windows OpenGL isn't added to the DX12 or Vulkan instance (#167)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-10 04:11:47 -04:00
Gert Pellin - GPE 3d2bda4d6b Desktop: write log records to standard error and a rotating log file (#122)
* Desktop: write log records to standard error and a rotating log file

The desktop app installed no logger, so every log::warn!/log::error! in
the workspace was discarded: the crash guard's panic report, a failed
crash-recovery save, font folders that can't be read. A launch from a
desktop menu has no terminal either, so there was nothing to attach to a
bug report.

apps/designcraft/src/logging.rs (no new dependency):
- standard error plus <settings dir>/logs/designcraft.log (beside
  ui.json and prefs.json); each launch rotates the previous log to
  designcraft.1.log and .2.log, so the log of a run that crashed
  survives the next start; the file is capped at 16 MiB
- records logged before the settings directory is known are buffered
  (bounded) and written once the file is attached
- default levels: info for designcraft*, warn for everything else;
  RUST_LOG replaces them with env_logger-style directives
- never panics: an unusable directory or a failed write leaves standard
  error as the only sink

The logger is installed first in main (before the engine's panic hook)
and the file is opened after argument parsing (--version leaves no
file). The settings directory moves out of prefs_path into config_dir.
A --control or DESIGNCRAFT_CONTROL_PORT value that is not a port is now
logged instead of silently leaving the control channel off. Documented
in README.md (Quick start > Logs).

* Desktop: no eprintln! on the log and panic paths

eprintln! panics when standard error is a broken pipe (a GUI launch on
Windows), and a panic inside the panic hook aborts. The "no log file"
message goes through log::warn! (standard error only by then); the panic
hook's fallback writes to standard error with write_fmt and ignores the
error. Same fix as storytold/vectorcraft#465.
2026-10-10 01:50:38 -04:00
aiongg 3033c8cc64 CLI: export options after the last export are an error; MCP and README docs match the code (#127)
* CLI: run rejects an export option with no export after it (#67)

--page, --scale and --pdf-options apply to the exports that follow them; one
given after the last --export or --all-pages did nothing and said nothing.
The usage text and docs/agents.md say so.

* MCP: document that text offsets and story lengths are UTF-8 bytes (#68)

* MCP: docs name the UI-only commands precisely; app.links works headless (#62)

* README: PDF and EPUB export ship (#60)
2026-10-10 01:13:42 -04:00
aiongg bb8a6a23fa INDD: open .indd files through indd-utils
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.
2026-10-09 23:06:40 +00:00
aiongg ff38aede13 Merge #127: CLI: export options after the last export are an error; MCP and README docs match the code 2026-10-09 22:16:13 +00:00
aiongg 5729796705 Merge #122: Desktop: write log records to standard error and a rotating log file
Conflict: apps/designcraft/src/main.rs: kept both module declarations (#168's graphics, #122's logging)
2026-10-09 22:16:13 +00:00
Philipp Krüger a11bd021cd feat(pptx): export documents as editable PowerPoint presentations
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.
2026-10-08 23:32:53 +02:00
DWAA1660 412962d9f8 Fix #167: default Windows startup to DirectX 12 2026-10-08 14:56:37 -06:00
d26b91335c README Downloads: where to get it first, then builds with Windows before macOS (#135)
Co-authored-by: Brandon Thomas <shared2@storyteller.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:50:30 -04:00
865640b70a Release: FreeBSD x86_64, Flatpak x86_64/aarch64, AppImage zsync updates; README Downloads (#132)
- freebsd job: builds packaging/freebsd/package.sh in a FreeBSD 14.3 VM (same image and
  packages as freebsd.yml) into designcraft-<ver>-freebsd-x86_64.tar.gz.
- flatpak jobs (x86_64 on ubuntu-24.04, aarch64 on ubuntu-24.04-arm): repackage the Linux
  tarball with packaging/linux/flatpak-bundle.sh and a new bundle manifest; runtime and
  finish-args shared with the from-source manifest (checked by packaging-lint).
- AppImages embed gh-releases-zsync update information and ship a .zsync beside them.
- version, linux, web, flatpak and freebsd no longer use the release environment (they read
  no secrets), so a workflow_dispatch on a branch dry-runs them; the signing jobs and the
  draft release stay environment-gated.
- nfpm package description described an image editor; now describes DesignCraft.
- README: Downloads section listing every build.

Co-authored-by: Brandon Thomas <shared2@storyteller.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:38:16 -04:00
aiongg 67c05eb22c README: PDF and EPUB export ship (#60) 2026-10-08 08:30:57 -04:00
Gert Pellin 4f25955002 Desktop: write log records to standard error and a rotating log file
The desktop app installed no logger, so every log::warn!/log::error! in
the workspace was discarded: the crash guard's panic report, a failed
crash-recovery save, font folders that can't be read. A launch from a
desktop menu has no terminal either, so there was nothing to attach to a
bug report.

apps/designcraft/src/logging.rs (no new dependency):
- standard error plus <settings dir>/logs/designcraft.log (beside
  ui.json and prefs.json); each launch rotates the previous log to
  designcraft.1.log and .2.log, so the log of a run that crashed
  survives the next start; the file is capped at 16 MiB
- records logged before the settings directory is known are buffered
  (bounded) and written once the file is attached
- default levels: info for designcraft*, warn for everything else;
  RUST_LOG replaces them with env_logger-style directives
- never panics: an unusable directory or a failed write leaves standard
  error as the only sink

The logger is installed first in main (before the engine's panic hook)
and the file is opened after argument parsing (--version leaves no
file). The settings directory moves out of prefs_path into config_dir.
A --control or DESIGNCRAFT_CONTROL_PORT value that is not a port is now
logged instead of silently leaving the control channel off. Documented
in README.md (Quick start > Logs).
2026-10-08 11:36:29 +02:00
Brandon ThomasandClaude Opus 5.5 f17397c305 Rename PrintCraft to PdfCraft (storytold/pdfcraft) (#95)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 14:55:09 -04: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