Commit Graph
59 Commits
Author SHA1 Message Date
Brandon Thomas 081c9fdc5e Merge the landing branch into land-r7
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
#	apps/deckcraft-cli/tests/cli.rs
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/cmd/text.rs
#	crates/engine/src/lib.rs
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/textures.rs
2026-10-14 15:34:15 -04:00
Brandon Thomas 9fc910886c Merge PR #247 from isaac-levine: MCP: confine file access with --automation-read-root and --automation-write-root
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/lib.rs
2026-10-14 15:25:09 -04:00
Brandon ThomasandClaude Opus 5.5 d66833b7c2 Fix up merged PRs: land-r6's changes fitted to the landing branch
- review.thesaurus's params doc parses under describe's grammar; describe's edit.copy test
  expects the landing branch's {text, html?} answer.
- The Language dialog test picks the landing branch's "Français (France)" entry; the Format
  Background test allows the pane's title to appear twice.
- Progress docs rebuilt from the landing branch's versions with land-r6's rows applied on top,
  so the union merge no longer drops the pen-pressure, ui.pointer and ui.key rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:23:16 -04:00
Brandon Thomas 91eb9d8884 Merge the landing branch into land-r6
# Conflicts:
#	crates/engine/src/tests.rs
#	crates/engine/src/tools.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/dialogs.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/panes.rs
#	crates/ui-egui/src/ribbon.rs
#	crates/ui-egui/src/status.rs
#	crates/ui-egui/src/textures.rs
#	crates/ui-egui/src/thumbs.rs
2026-10-14 15:14:21 -04:00
Brandon Thomas f800acee47 Merge the startup, clipboard, animation-preview and UI PRs integrated on land-r5 (#644 #652 #655 #702 #571 #539 #674 #648 #697 #479 #369 #368)
# Conflicts:
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/ribbon.rs
2026-10-14 14:58:48 -04:00
Brandon ThomasandClaude Opus 5.5 afc387cdc5 Merge PR #468 from NikitkaRa: Media: a failed or stalled audio output hands the clock back to wall time (#417)
Fix-up in the merge (review): a just-started stream gets 5 s for its first callback before it
counts as stalled (slow Bluetooth devices), and the failure count resets once a restarted
stream delivers, so one bad start no longer silences media for the session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:57:54 -04:00
Brandon ThomasandClaude Opus 5.5 ed13dd6158 Fix up merged PRs: GIF export goes through main's export path
The Export dialog's GIF choice runs through SlideApp::export_as (desktop and web download),
.gif is a writable output extension for convert/run, and the CLI help pages describe GIF output
and --export-params. A file.export `slides` range string ("1-3,5") works for GIF as for PDF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:54:35 -04:00
Brandon Thomas c354f02279 Merge PR #177 from Mathiasko: Export: animated GIF of the deck (Export… dialog, CLI, MCP) (#171)
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/lib.rs
#	crates/mcp/src/tests.rs
#	crates/mcp/src/tools.rs
#	crates/ui-egui/src/dialogs.rs
2026-10-14 14:52:34 -04:00
Brandon Thomas e9923c6c42 Merge PR #368 from NikitkaRa: A tabbed slide body is an outline, and --help exits (#360)
# Conflicts:
#	apps/deckcraft/src/main.rs
#	crates/engine/src/cmd/slide.rs
#	crates/engine/src/cmd/text.rs
2026-10-14 14:45:23 -04:00
Brandon Thomas 5fbdb6c79e Merge PR #479 from NikitkaRa: Web: keep a picked file on the document and slide that asked for it
# Conflicts:
#	crates/ui-egui/src/lib.rs
2026-10-14 14:43:55 -04:00
Brandon ThomasandClaude Opus 5.5 3b28496c36 Fix up merged PRs: main's newer params docs fit describe's grammar; help pages for bench and render-transition
file.export's slide range and transition.sound's keys parse as parameters, and the subcommands
main added since #303 have their own help page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:40:09 -04:00
Brandon Thomas 38e95d8c15 Merge PR #702 from NikitkaRa: Clipboard: rich text and pictures for Pages and Keynote
# Conflicts:
#	crates/engine/src/cmd/edit.rs
#	crates/ui-egui/src/lib.rs
2026-10-14 14:39:36 -04:00
Brandon Thomas b590cb0b0b Merge PR #303 from hoblin: deckcraft-cli help explains the CLI to an agent
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
#	crates/engine/src/cmd/design.rs
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/cmd/format.rs
#	crates/engine/src/tests.rs
2026-10-14 14:36:13 -04:00
Brandon Thomas 89da88e374 Merge PR #258 from RCShoemaker: fix(cli): render refuses an unknown option instead of writing it as a file (#235)
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
#	contributors/people.toml
2026-10-14 14:34:57 -04:00
Brandon Thomas e406e11db2 Merge PR #444 from MarekSpodBiedry: CLI: render-transition refuses --t values that would share one file name (#423)
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
2026-10-14 14:33:40 -04:00
Brandon ThomasandClaude Opus 5.5 8ee597216d Fix up landed PRs from review
- #178: ToUnicode ranges looked up without indexing
- #465: frame_num gaps are concealed (bounded) even when the SPS forbids them; cut streams keep playing
- #471: control request lines up to 256 MB so picture/media inserts still fit
- #473: a merge that loses its only row or column is removed, with regression tests
- #521: AutoCorrect no longer rewrites real words (cant, wont, im)
- #654: inherit_placeholder_geometry's doc comment back on its function

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:31:01 -04:00
Brandon Thomas a0d97fa931 Merge PR #644 from NikitkaRa: Startup: survive damaged settings, font folders, recovery folders and small texture limits
# Conflicts:
#	crates/engine/src/recovery.rs
#	crates/fonts/src/fontdb.rs
#	crates/fonts/src/lib.rs
#	crates/ui-egui/src/lib.rs
2026-10-14 14:24:45 -04:00
Brandon Thomas fca521ac8c Merge PR #471 from NikitkaRa: Control server: bound connections, line length, queue and socket timeouts (#418) 2026-10-14 14:24:15 -04:00
Brandon Thomas 8ea2cb0871 Merge PR #361 from NikitkaRa: CLI: say that render --slide counts from 0 (#359)
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
2026-10-14 14:12:10 -04:00
Brandon Thomas 2009242055 Merge PR #684 from NikitkaRa: Export: a PNG or JPEG slide records 144 dpi at the default 2× size
# Conflicts:
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/tests.rs
2026-10-14 14:02:59 -04:00
Brandon Thomas f52bcfa1c8 Merge PR #530 from NikitkaRa: Design: Browse for Themes from a .thmx, .pptx or .potx file
# Conflicts:
#	crates/ui-egui/src/lib.rs
2026-10-14 13:36:45 -04:00
Brandon Thomas 6a8922ac49 Merge PR #661 from NikitkaRa: Startup: fall back to Wayland when DISPLAY names no X server 2026-10-14 13:09:05 -04:00
Brandon Thomas 3a5153a1d0 Merge PR #564 from NikitkaRa: Performance baseline: deckcraft-cli bench and cargo xtask bench 2026-10-14 13:08:54 -04:00
Brandon Thomas f8d52f6fbe Merge PR #308 from marcoarnulfo: macOS: end the process in on_exit so closing the window doesn't crash 2026-10-14 12:57:23 -04:00
Brandon Thomas 8d8cbeb123 Merge PR #179 from MarekSpodBiedry: CLI: --help prints usage and unknown render flags are rejected (#163) 2026-10-14 12:57:20 -04:00
Brandon Thomas 40231d8114 Merge PR #176 from itrycodinganditsbad: Windows: compile DX12 shaders with FXC 2026-10-14 12:57:20 -04:00
Gert Pellin cf640c4b08 CLI: convert and run refuse output formats DeckCraft can't write (#715)
convert, run --save and run --export picked the format from the output
extension and fell back to native .deckcraft bytes for any extension
they didn't know, so out.odp, out.gif, out.svg and out.outline were
zips with exit status 0. They now fail before writing anything, with
the extension and the supported ones in the error.
2026-10-14 13:07:49 +02:00
Nikita RakitinandCursor 5d9f47c81a Clipboard: rich text and pictures for other apps
Copy puts HTML on the pasteboard with the same plain words, so Pages keeps
bold, italic and underline, and a paste of that HTML keeps them here. A
shape with no text copies out as a picture.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 06:37:49 +03:00
Nikita RakitinandCursor d04df05249 Export: record slide resolution in PNG and JPEG pictures
A default export is 2 pixels per point. Without a resolution, Preview
treats those pixels as 72 dpi and the picture opens at twice the slide's
size. PNG pHYs and JPEG JFIF density now say scale times 72, so the
default is 144 dpi. Screenshots stay untagged.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 05:35:37 +03:00
Nikita Rakitin 0c84b0434d Merge remote-tracking branch 'origin/main' into m-359-cli-slide-index
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
2026-10-14 05:16:53 +03:00
Nikita RakitinandCursor fcb5eae1a5 Startup: fall back to Wayland when DISPLAY names no X server
DeckCraft forces X11 whenever DISPLAY is set. A stale DISPLAY (an ended ssh -X session, or
Xwayland turned off) made start-up fail with "failed to open display" while a Wayland
compositor was running. A local DISPLAY whose /tmp/.X11-unix socket is missing now starts on
Wayland when WAYLAND_DISPLAY is set; remote displays and live servers keep X11. Forcing Wayland
without a compositor keeps X11, and with no display at all the error says so plainly.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 04:21:30 +03:00
Nikita RakitinandCursor c583480010 Startup: survive damaged settings, font folders, recovery folders and small texture limits
- ui.json / prefs.json are read through a new settings module: regular files only, 4 MiB
  cap, parse errors logged, values sanitized (a saved zoom of 1e30 aborted start-up,
  1e4 panicked in egui); writes are atomic.
- The canvas and the control protocol clamp stray zooms; the status bar shows the zoom in use.
- The canvas texture is cut to the GPU's max texture side (zoom 400% on a 2048 limit panicked).
- The system font scan opens only regular files of sane size (a FIFO named *.ttf in ~/.fonts
  hung start-up), with depth and entry caps.
- AutoRecover skips non-regular entries and reopens at most 32 per start, newest first.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 03:27:57 +03:00
Nikita Rakitin 5bdfc3228d Add a performance baseline: deckcraft-cli bench and cargo xtask bench
Times open, per-slide render, save, the PPTX round trip and PDF export, and
reports peak memory; xtask builds the CLI in release, runs it on the sample
and any given decks, and compares with docs/benchmarks/baseline.json.
2026-10-14 00:05:47 +03:00
Nikita RakitinandCursor 30c2fe4b6d Design: Browse for Themes from a .thmx, .pptx or .potx file
deckcraft_pptx::import_theme reads the theme of a .thmx (its main document is
a theme part) or of a presentation's first master, with the media its format
scheme uses. design.browseTheme {path | name, data} applies it to the current
master as one undo step, giving the theme's pictures ids of this deck.

Design tab: Browse for Themes… next to the theme gallery and in the Slide
Master Themes menu; the desktop picker offers Office Theme (.thmx) and
presentations. Ribbon small buttons expose their label to accessibility (same
change as #512). Parity row Browse themes M → D.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 23:04:41 +03:00
Nikita RakitinandCursor 8bab5c2053 Web: keep a picked file on the document and slide that asked for it
The browser file picker only queued a name and bytes. When the read
finished, DeckCraft guessed the command and ran it on whichever
document and slide were active, so a picture, sound or outline could
land in the wrong place, and a later pick could finish first.

The request now keeps the document, the slide or master, the operation
and a cancellation id. A completion applies there, or is dropped when
that target is gone or the picker was dismissed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 20:53:10 +03:00
Nikita RakitinandCursor 8dc068e0ba Control server: bound connections, line length, queue and socket timeouts (#418)
The loopback control server spawned a thread per connection, read
unbounded lines, queued requests without limit and set no socket
deadlines. It now caps simultaneous clients (16) and request lines
(16 MiB), uses a bounded request queue (64) that answers busy when full,
closes sockets idle for 10 minutes or blocked on a write for 30 seconds,
and frees a connection slot whenever a client thread ends.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 20:39:36 +03:00
Nikita RakitinandCursor 952ebad3cf Media: a failed or stalled audio output hands the clock back to wall time (#417)
A cpal stream error was only kept and logged on stop, and the player kept
`streaming` true, so a device that died mid-play froze the voice and video.

AudioOut gains `failure()` (CpalOut reports DeviceNotAvailable), and
Player::tick also treats a stream with no callbacks for a second while a
voice plays as stalled. Either way the stream is stopped, voices continue on
the wall clock, and the next play retries the device; after three failures
the player gives up on the device and plays silently.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 20:27:21 +03:00
MarekSpodBiedry eff88eaf59 CLI: render-transition refuses --t values that would share one file name (#423) 2026-10-13 17:34:17 +02:00
NikitaandCursor 503ee5d67e A tabbed slide body is an outline, and --help exits (#360)
slide.new kept a leading tab as text, while text.set already turned it into a bullet level. The desktop --help flag was opened as a missing file.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 12:38:57 +03:00
Brandon ThomasandClaude Opus 5.5 d5e30557eb Transitions like PowerPoint: measured frame by frame and retuned (#366)
Every transition and Effect Option was built in PowerPoint (COM), exported as
video and compared frame by frame with DeckCraft at the same progress
(mean abs diff over 150 variants 35.7 -> 15.0, 0-255).

- anim: transition_frame(kind, option, t, aspect) with measured curves
  (smoothstep fades, ease-in-out moves, Cover/Uncover/Pan curves), directions
  and option meanings, soft edges as per-corner opacity, 3-D effects as
  perspective-projected cards, Dynamic Content moving slide contents over
  cross-fading backgrounds (Source::OldBack/NewBack/OldContent/NewContent);
  layer_mesh subdivides perspective quads so textures stay straight.
- New options: Page Curl Single, Glitter Hexagons, Shred In/Out, Zoom and
  Rotate; PowerPoint-style Effect Options labels.
- render: composite_transition (CPU twin of the show), render_slide_part,
  render_transition; deckcraft-cli render-transition FILE --slide N --t T.
- show: per-vertex opacity meshes, slide parts rendered once per transition.
- pptx: PowerPoint's elements and defaults (p:strips diagonal wipes, p14:warp
  and p:newsflash for Zoom, p:zoom for Shape In/Out, glitter pattern, shred
  rectangle/dir, prstTrans invX per preset, pageCurlSingle, defaults for
  randomBar/doors/window/pan/zoom); PowerPoint reopens DeckCraft's files with
  the same effects.
- Tests: measured curves, probes of which slide shows where at t, option
  coverage, per-frame triangle budget, PowerPoint XML and defaults round trip.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 05:31:13 -04:00
NikitaandCursor 18e47d1af7 CLI: say that render --slide counts from 0 (#359)
--all names files slide-01.png onward, so --slide 8 on an 8-slide deck looked like an off-by-one. The index stays 0-based, matching slide.go, and the error now gives the range and the file names.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 11:55:00 +03:00
Yevhenii Hurin 922445300b describe keeps a remark with its option and allows a bare call
animation.remove's remark belongs to its `ids` option, so describe shows
it there instead of as a note on the whole command. A command with an
all-optional set of parameters is suggested as a bare id.

[claude-opus-5-5] on behalf of hoblin
2026-10-13 09:55:19 +03:00
Yevhenii Hurin 66f7e6e1ed Self-review: no ID[=JSON] left, params grammar documented
A --cmd without a value now asks for COMMAND[=PARAMS]. The params field
says how describe reads it, table.split's row and col are optional as
the command reads them, and the MCP instructions name only shape
commands for `ids`.

[claude-opus-5-5] on behalf of hoblin
2026-10-13 00:15:53 +03:00
Marco Arnulfo e3d9803069 macOS: end the process in on_exit so closing the window doesn't crash (fixes #279)
Same fix as storytold/gridcraft#117 (storytold/gridcraft#316): eframe drops
the window while AppKit's run loop still runs, AccessKit restores the
content view's class and AppKit's Touch Bar KVO observer throws on the
next display cycle. on_exit now ends the process on macOS once the
preferences are saved.
2026-10-12 23:12:03 +02:00
Yevhenii Hurin 717e855cec deckcraft-cli help explains the CLI to an agent
`deckcraft-cli help` and each subcommand's `--help` say what it does,
with a working example; `--help` never runs the subcommand. `describe`
spells out a command's parameters and what it acts on, `commands` lists
one command per line, and the MCP instructions say what format.* acts on.

[claude-opus-5-5] on behalf of hoblin
2026-10-12 23:41:42 +03:00
Ryan C. ShoemakerandClaude Opus 5.5 30a5ee202d fix(cli): render refuses an unknown option instead of writing it as a file (#235)
`deckcraft-cli render` took any argument it didn't recognise as the output
path, so `render deck.pptx --help` rendered the slide into a file named
`--help`, and a mistyped option was silently ignored. An argument starting
with `-` that render doesn't know is now an error naming it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 10:42:53 -06:00
Isaac Levine f3ae32d920 CLI: add --automation-read-root and --automation-write-root to mcp 2026-10-12 09:58:07 -04:00
MarekSpodBiedry c1ab5d3c43 CLI: --help prints usage and unknown render flags are rejected (#163) 2026-10-11 23:37:38 +02:00
Matúš LacoandClaude Opus 5.5 c871c5f634 Export: animated GIF of the deck (Export… dialog, CLI, MCP) (#171)
There was no way to turn a presentation into an animated GIF. file.export now writes one: format
`gif` (or a .gif path), one frame per slide drawn by the slide renderer and shown for
secondsPerSlide, encoded with the `image` crate's GIF encoder (already a dependency, no new
crates) with a 256-colour palette per frame: exact when a slide has 256 colours or fewer,
NeuQuant otherwise. Slides are composited onto white.

Options: width (small 640, medium 960 (default), large 1280, extraLarge 1920, or 16-3840 px; the
height follows the slide's aspect ratio, no side over 3840), secondsPerSlide (0.1-600, default 5,
written in GIF hundredths), loop (forever by default, or once: no NETSCAPE2.0 block), slides (a
list of indices, in play order) and includeHidden (hidden slides are skipped by default).
Out-of-range or wrongly typed values, NaN and infinities are BadParams errors, never panics; at
most 500 frames and 200 million pixels in total, checked before anything is rendered.

- Engine: crates/engine/src/gif_export.rs (options, frame list, size, encoder);
  cmd::file::gif_bytes, save_bytes("gif"), format_for_path(".gif").
- UI: the Export… dialog (Command palette; the app has no File menu yet) gets "Animated GIF (.gif)" with Size, Seconds per slide, From/To slide,
  Loop forever and Include hidden slides; an invalid range or value keeps the dialog open with a
  message. The web build downloads the bytes (image/gif).
- CLI: convert IN OUT.gif, run --export OUT.gif --export-params JSON; usage lists the format and
  options.
- MCP: the export tool lists gif and width/secondsPerSlide/loop (slides and includeHidden now
  apply to PDF and GIF).
- Docs: file-format parity GIF row, gaps (video export remains), parity checklist row M -> P
  (P2 breadth 36% -> 37%, overall 79%), control protocol, MCP, README, ROADMAP progress log.

Transitions and build animations are not animated in the GIF (tracked with video export).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:00:33 +02:00
Fabio LussiandClaude Opus 5.5 b14cf1da70 Windows: compile DX12 shaders with FXC
wgpu's default DX12 compiler (Auto) loads whichever dxcompiler.dll the DLL
search path finds. DeckCraft ships none, and without a matching dxil.dll the
unsigned-DXIL warning fails wgpu's indirect-validation pipeline, the device
is lost and the app exits before the first frame. Pin the compiler to FXC,
which is part of Windows; WGPU_DX12_COMPILER still overrides it.

Fixes #153

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 22:25:06 +02:00