feat(x): create and edit presentations from chat - #848
Conversation
Synthesizes a complete minimal OOXML package from strings — theme with three built-in palettes, one master, two layouts, one title slide — validated structurally and round-tripped through our own parser and serializer. New presentation entry in the workspace Add menu opens the created deck directly in the editor.
…nders them The typed text was always in the written bytes - generated packages validated against ECMA-376 and rendered in Keynote and QuickLook, but desktop PowerPoint silently renders schema-minimal packages blank. The synthesizer now emits PowerPoint's own scaffolding: presProps, viewProps, tableStyles, the full Office theme matrix with font script tables, nine-level master txStyles, a presentation defaultTextStyle, and bgRef backgrounds. Scaffolding adapted from python-pptx's default template (MIT), attributed in NOTICE.md.
Core generateDeckOutline turns a prompt into a zod-validated outline (clarifying questions, slides with headings/bullets) following the existing knowledge-task model pattern, exposed via deck:generateOutline IPC. The dialog gains a Generate mode: prompt, optional clarify round, editable outline review, then deterministic synthesis through newDeckPptx + planNewSlide in one writeDeck call.
Shared FACT_RULES across all three generation prompts: only user-supplied facts, bracketed placeholders for missing numbers/quotes, big-number and quote patterns gated on real input, needsInput chips surfacing what the user should fill in. Clarifying questions sized to the gap (2-5 typical, cap 8) instead of a hard cap of 2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the sparkle popover out of pptx-editor.tsx into its own module and add the first tests for it, covering the Edit/New mode switch (the 'New slide after this' tab), Suggest/Generate/Apply routing, and the tabless rail-header variant. Behaviour unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gamma-style cards with drag reorder, per-card pattern switcher, inline theme strip and staggered entrance; two-pane review where every card carries a real rendered thumbnail and the selected slide previews large, rebuilt in memory through the same synthesis path Create uses - nothing touches disk until Create.
Eleven engine modules plus edit-slide relocate from the renderer to shared (git mv, history preserved) so core can use them; renderer deep-imports repoint following the existing @x/shared/dist convention. Five new builtin tools - deck-create/add-slide/edit-slide/restyle/review - mirror the spreadsheet tools pattern: file-boundary permission, errorEnvelope, structured inputs, honesty contract in the descriptions. writeBuffer ported byte-identical from the spreadsheet branch. Node parse path skips blob URLs via a MediaSink; tools dispose decks in finally.
Deck tools announce writes via a rowboat:deck-touched event mirroring the spreadsheet pattern; the editor reloads in place when clean and shows a Reload/Keep-mine banner when dirty. Every editor write path now carries the snapshot's etag, verified under the main-process file lock, so a stale editor can never silently overwrite an assistant's write. Auto-open fires only on deck-create so an assistant edit never steals the user's view.
The deck tools were in no skill and not in base tools, so the model never saw them, while both prompt surfaces pointed presentations at the PDF pipeline. A new create-presentations skill attaches all five deck tools; the old PDF skill moves to pdf-slides, gated behind an explicit PDF ask. Tool descriptions lead with the user's own vocabulary.
Drops the slide-rail sparkles and the dialog's Generate mode (prompt, clarify, outline review, live previews) now that the deck tools work from chat. Blank creation, the theme popover and every non-AI editor control stay; shared/core machinery is untouched since the tools depend on it.
Adds a deck kind to the middlePane user-context union, so every message carries the open deck's path and slide position. The agent now targets the open deck for 'this deck' / 'slide 2' instead of guessing or creating a new file; deck-create is explicitly guarded against edit-like requests. Follows the existing note/browser context pattern - no new IPC, no core-to-renderer query, no capability changes, and the prompt snapshots gain only the new paragraph.
Assistant-created decks opened in Keynote/PowerPoint because the file card always called shell:openPath. Workspace files with an in-app viewer now route through onOpenKnowledgeFile, using the same getViewerType predicate that mounts the viewers so the card and the router can't drift. Files outside the workspace and types with no viewer keep the OS opener.
New decks get a single compact intake - purpose and audience, length, and the facts the deck depends on - offered as answerable options, plus deck-type slide arcs so the outline follows a known structure. Editing an open deck gets a lighter path: review first, at most one clarifying question, and never a full regenerate.
…ntake Inline emphasis from the model becomes real bold/italic runs instead of literal asterisks on the slide. Editing a slide now diffs paragraphs, so formatting the user applied by hand survives on paragraphs the edit didn't touch. deck-create requires purpose, audience and length in its schema, so a new deck can't be built without asking first.
The renderer bundle now includes the shared pptx engine; rollup's chunk-rendering phase crossed the runner's default heap and the vite build died with heap out of memory. Local builds pass because node sizes its heap from full machine memory. 6GB headroom on a 16GB runner.
The intake questions now come as clickable cards (rowboatlabs#853) instead of prose: purpose and length as single-select options, audience and facts as one open question after purpose is known. Skip follows the card's sentinel and proceeds with placeholders rather than re-asking. At most two cards per message, two rounds total.
|
Reviewed the branch locally — great feature overall. One thing I hit while testing, plus a suggestions list from a deep review pass. Observed while testing: assistant edits are not visible live — with the deck open in the editor, chat edits land on disk but the editor doesn't refresh to show them (may be related to items 1–2 below, since the reload path only fires when the pipeline is idle and classifies the change as external). Correctness — should fix before merge
Cleanup — fine as follow-ups
|
Deck tools now read and write transactionally - readBuffer returns an etag, every tool write is guarded, and a concurrent editor save makes the tool fail with a conflict instead of clobbering it. The editor's reload only adopts the new etag after the idle check passes, and a deleted file becomes a proper conflict instead of endless ENOENT toasts. Bullet edits on a single-text-shape slide rebuild instead of silently no-oping. New deck-restructure tool exposes the slide delete and reorder the prompts already promised. Theme changes and theme undo persist before touching history or the screen. Base instructions no longer route .pptx reads to parseFile. Also fixes the symptom the reviewer hit: scheduleSave never cleared its timer handle when the debounce fired, so isIdle stayed false for the session and every assistant write showed the banner instead of reloading.
|
@Gagancreates Thanks for running it locally — the live-reload symptom you hit was the All 8 correctness items are fixed with a regression test each, and every
Cleanup items (dead IPC, deck-review latency, the duplication pass) — |
You can now create and edit PowerPoint presentations by talking to the
assistant.
What it does
questions as clickable option cards (purpose, length, then audience and
facts), then writes a real .pptx into the workspace and opens it in the
editor.
pricing", "restyle this deck to midnight" all work — the assistant
knows which deck you're looking at, and the open editor updates in
place.
visible placeholders like "[X]% growth" instead of made-up values.
Keynote/PowerPoint.
How to test
Setup:
pnpm installfirst — this adds jszip and fast-xml-parser topackages/shared. Thennpm run deps && npm run dev.startup". You should get question cards — pick the options, then
answer the facts question. A .pptx appears in the workspace and opens
in the editor. Try Skip on one card too: it should build with
bracketed placeholders instead of asking again.
midnight", then "make slide 2's heading shorter", then "add a slide
about pricing". Each should hit the deck you're looking at.
Canva or PowerPoint is the better test). "make this deck better" —
the assistant should look at what's there before suggesting changes.
"shorten slide 3" should just do it.
for Saved, then ask the assistant to change a different paragraph on
that slide. Your bold should still be there.
save, then ask for a restyle in chat. A banner appears — try both
Reload and Keep mine.
theme intact. Worth doing on the edited existing deck too — untouched
slides, charts and tables should be exactly as they were. This is the
most important step.
produce a PDF.
Changes worth knowing about
renderer into
packages/sharedso the assistant's tools can use it.Moved with
git mv, history preserved; jszip and fast-xml-parseradded to shared's deps. No pnpm-workspace or tsconfig changes.
the PDF pipeline, and the new deck tools weren't attached to any skill
so the model never saw them. Presentations now go to the deck tools;
the PDF pipeline still exists but only fires on an explicit PDF
request. This changes behavior for anyone who was getting PDFs.
are removed — chat is the AI surface now. Blank deck creation and all
normal editor controls stay.
outgrew the runner default. Code-splitting the engine is the real fix.
Known limits
their data is preserved untouched on save.
a model can still slip. Real user-supplied numbers have to pass
through, so a hard validator isn't possible.
navigate away without choosing — your unsaved edits are lost (there's
no UI left to ask at that point).
Verified
Ran all seven steps end to end in the app on macOS. Test suites: shared
296, core 687, renderer 265 — all green, typecheck, eslint and builds
clean.