Commit Graph
14 Commits
Author SHA1 Message Date
Brandon ThomasandClaude Opus 5.5 67e1ab6373 Merge PR #438 from albayazid: Model: an exhausted id space refuses growth instead of duplicating ids (#407)
Conflicts resolved onto main's newer shape, and the PR's policy applied to
every alloc_id/add_media/new_slide call site main has grown since: commands
answer bad(cmd, NO_ID_SPACE) (slide.reuse, insert.zoom, SmartArt, photo
album, review.accept, handout/notes masters, master placeholders,
background/artistic/compress pictures, transition sound, ink to shape,
paste special, file.new templates); reid/bring_media/renumber/regenerate
and compare::adopt/accept are fallible; outline import keeps what fit.
Tests use expect() on the now-Option results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:24:26 -04:00
Brandon ThomasandClaude Opus 5.5 b9f112a6e4 Merge PR #670 from NikitkaRa: Format: never save a .deckcraft that cannot be reopened over a NaN
Fix-up in the merge (review): reading older files that hold null numbers re-parses at most
256 MB in all and slices without indexing, so a hostile file can't hang the open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:11:25 -04:00
Brandon Thomas b3c9cc099c Merge the PPTX writer, notes/handout master, PDF and slide-show PRs integrated on land-r3 (#518 #531 #535 #533 #572 #573 #577 #580 #583 #592 #685 #528 #483 #490 #441 #671 #679 #649 #656 #660 #664 #224)
# Conflicts:
#	crates/engine/src/tests.rs
#	crates/model/src/lib.rs
#	crates/pptx/src/write/mod.rs
#	crates/render/src/lib.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/thumbs.rs
2026-10-14 13:56:41 -04:00
Brandon Thomas 9b8871c86b Merge PR #528 from NikitkaRa: Format: bound total embedded media when opening a .deckcraft
# Conflicts:
#	crates/format/src/lib.rs
2026-10-14 13:31:49 -04:00
Brandon Thomas d4d352622a Merge PR #665 from NikitkaRa: Format: repair degenerate slide sizes on load
# Conflicts:
#	crates/ui-egui/src/lib.rs
2026-10-14 13:22:57 -04:00
Brandon Thomas c201a62e72 Merge PR #526 from NikitkaRa: Format: report damaged embedded media and open such files as a repaired copy
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-14 13:08:49 -04:00
Nikita RakitinandCursor 8fde746211 Format: never save a .deckcraft that can't be reopened over a NaN
serde_json writes NaN and infinity as null, which doesn't read back as a number, so one NaN
anywhere in the model (a rotation, position, crop, stroke width…) made the saved file (and its
AutoRecover copy) fail to open as "damaged".

- Writer: presentation.json goes through finite::Finite, a serializer adapter that writes
  non-finite floats as 0.
- Loader: files already written that way open; each null where a number belongs reads as 0
  (inside tagged enums, where serde only reports the enclosing object, candidates are tried
  nearest first and kept only when the parse gets further). Other damage still fails.
- repair() brings shape geometry into range: positions and sizes finite and within ±1e6 pt,
  rotation 0–360, picture crop -10..1, font sizes 1–4000 pt, line widths 0–1584 pt.

Animation timings are u32 and can't carry NaN.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 04:45:32 +03:00
Nikita RakitinandCursor 22074c4c69 Format: repair degenerate slide sizes on load
repair() brings each slide side into PowerPoint's 72–4032 pt (as Design › Slide Size allows;
it accepted 1–4000 before), and replaces a zero, negative or non-finite size with 16:9; a bad
notes size gets the default. The native reader takes a null, string or missing slide/notes
size as NaN for repair to fix, so such a file opens instead of failing as damaged (NaN and
infinity are saved as null). The canvas fit and slide show fit treat a zero or non-finite side
as 1 pt, so an in-memory bad size can't make layout infinite.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 04:35:13 +03:00
Nikita RakitinandCursor 24622bf94d Format: bound total embedded media when opening a .deckcraft
Only each member was capped (2 GiB), so a compact archive with many
media items, or one large member listed under many items, could
inflate without limit and exhaust memory while opening.

Loading now caps all embedded media together (4 GiB) and the number
of media items (100,000), refuses a member before inflating it when it
declares more than is left, and keeps one item per media id, so a
repeated id inflates its member once and the deck can still be saved
(a zip can't hold two media/<id> entries).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 23:00:17 +03:00
Nikita RakitinandCursor 3489c3b22d Format: report damaged embedded media and open such files as a repaired copy
load() ignored every failed media read, so a .deckcraft with a missing,
oversized or bad-CRC media member opened silently with empty pictures,
and the next Save overwrote the original with that loss.

load_checked() now lists each unreadable member (linked media saved
without bytes is not damage). file.open/openBytes return damagedMedia,
show a message, and open the deck as an untitled "(Repaired)" copy so
Save asks for a new name and the original file stays intact.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 22:55:52 +03:00
Sazid Al Bayazid e70fce996b Model: an exhausted id space refuses growth instead of duplicating ids (#407)
alloc_id bumped next_id with saturating_add: a presentation whose
next_id reached u32::MAX (a hostile file can arrive that way;
fix_next_id imports it) handed out that same id to every new slide,
shape, layout and media - duplicate ids, ambiguous references, silent
corruption on every later insert.

alloc_id now returns Option<u32> via checked_add, and every caller
refuses: the engine's insert/duplicate/media/layout commands answer
with a clear error naming the command, paste and duplicate re-id
helpers propagate it, media addition is fallible, and a fresh slide is
Option. The pptx export's synthesized blank layout is guarded the same
way. Loading keeps such a deck viewable: repair re-ids duplicate
slides while it can, and a duplicate it cannot re-id stays as it is -
growth is refused, and only that duplicate keeps its ambiguous id.

Renumbering the loaded graph was rejected: it needs the
cross-document reference remapping that issue #406 tracks.

Tests: model exhaustion (alloc_id None, fresh media refused, a new
slide refused), engine (slide.new, shape.insert, slide.duplicate and
edit.duplicate all refuse; the document holds no duplicate ids),
format repair (an unre-id-able duplicate stays visible).
2026-10-13 21:13:25 +06:00
lloydandClaude Opus 5.5 9c64754f20 Read Markdown outlines as Markdown (#211)
File ▸ Open's Outline filter accepts `.md`, but a `.md` was read with the
plain outline format (unindented line = slide, indent = bullet), so a
Markdown outline written the usual way kept `#` in its titles and made
every top-level list item a slide of its own.

`deckcraft_format::markdown_to_slides` reads ATX headings (`#`–`######`,
closing `#`s dropped) as slide titles, list items (`-`, `*`, `+`, `1.`,
`1)`) as bullets nested by their indentation, and other lines under a
heading as body paragraphs. A `.md` without headings is still read as a
plain outline, so existing indented `.md` outlines open as before; `.txt`
is unchanged. Opening a `.md` and dropping one on the window
(`slide.fromOutline {markdown: true}`) use it. Both readers now share the
slide builder.

Tests: the outline from the issue (2 slides, nested bullets), numbered and
`*`/`+` lists with text under a heading, `slide.fromOutline` with
`markdown`, plain `.txt`/`.md` outlines unchanged, and heading / list-item
edge cases (not-a-heading forms, closing hashes, Unicode, long digit runs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:22:47 +02:00
Brandon ThomasandClaude Opus 5.5 ae9d525bce Rename SlideCraft to DeckCraft: crates, apps, binaries, app id, file extension (.deckcraft; .slidecraft files still open), packaging, docs; ROADMAP alpha and parity estimates
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:46:40 -04:00
Brandon ThomasandClaude Opus 5.5 6078b68e97 M0: workspace, model, geometry, fonts, text, renderer, engine, MCP and CLI
Clean-room PowerPoint-class presentation engine in pure Rust:
- geom: units, transforms and 150+ re-derived preset shapes with adjust handles
- color: theme slots and colour transforms
- model: presentations, masters, 11 layouts, placeholder inheritance, themes,
  text, tables, charts, transitions, animations, text edit operations
- fonts: font DB with craft-fonts, system fonts and open substitutes
- text: shaping, line breaking, bullets/numbering, alignment, autofit, caret hit tests
- render: vello_cpu slides with fills, gradients, pictures, effects, tables, charts
- format: native .slidecraft (zip + JSON)
- engine: ~200 commands, undo/redo, clipboard, pointer tools, keys, sample deck
- mcp: MCP server (headless or bridged to the app); slidecraft-cli

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 23:27:20 -04:00