Skip to content

add pptx export suppport to workspace-slides blueprint - #434

Open
maxwellpeterson wants to merge 7 commits into
mainfrom
mpeterson/pptx-export
Open

add pptx export suppport to workspace-slides blueprint#434
maxwellpeterson wants to merge 7 commits into
mainfrom
mpeterson/pptx-export

Conversation

@maxwellpeterson

Copy link
Copy Markdown
Member

update built-in slides blueprint to support pptx export

@github-actions github-actions Bot added the kernel Changes to the Workshop kernel label Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

Preview: pr434-mpeterson-pptx-export

https://pr434-mpeterson-pptx-export-router.cloudflare-os-previews.workers.dev

Dashboard · deleted when this PR closes

@ask-bonk

ask-bonk Bot commented Sep 3, 2026

Copy link
Copy Markdown

@maxwellpeterson Bonk workflow failed. Check the logs for details.

View workflow run · To retry, trigger Bonk again.

ask-bonk[bot]

This comment was marked as resolved.

@ask-bonk

ask-bonk Bot commented Sep 3, 2026

Copy link
Copy Markdown

Posted 2 actionable inline findings.

github run

…atim

- Replace the slides ZIP writer with the workspace-sheets copy and adapt
  deckToPptx to its string/stream entry contract; batch slide XML into
  64 KiB chunks like xlsx.js.
- Parse highlight terms incrementally (max 128 comma-delimited entries),
  bound search work and highlight run transitions per title and per deck
  before any stream is returned, and stream runs directly from a shared
  mark array instead of materializing segments.
- Drop the duplicated ZIP32 and determinism tests; add regressions for the
  reported attacks, boundaries, cross-line highlights, and bundled
  blueprint dependency wiring.
@ask-bonk

ask-bonk Bot commented Sep 8, 2026

Copy link
Copy Markdown

APIError: You do not have access to the organization tied to the API key.

github run

2 similar comments
@ask-bonk

ask-bonk Bot commented Sep 8, 2026

Copy link
Copy Markdown

APIError: You do not have access to the organization tied to the API key.

github run

@ask-bonk

ask-bonk Bot commented Sep 8, 2026

Copy link
Copy Markdown

APIError: You do not have access to the organization tied to the API key.

github run

@maxwellpeterson
maxwellpeterson marked this pull request as ready for review September 8, 2026 20:51

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

🔍 Devin Review: 1 flag

Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Google Slides renders exported decks with loose paragraphs and wrapped
logo/section labels. Emit CSS line-height as exact spcPts (spcPct is
relative to Arial's ~115% line gap), size single-line boxes from Arial
advance widths (Google ignores wrap="none"), keep the accent dot at the
browser's 3px gap, and enlarge the bullet glyph to the browser's 6px dot.
@ask-bonk

ask-bonk Bot commented Sep 8, 2026

Copy link
Copy Markdown

APIError: You do not have access to the organization tied to the API key.

github run

2 similar comments
@ask-bonk

ask-bonk Bot commented Sep 8, 2026

Copy link
Copy Markdown

APIError: You do not have access to the organization tied to the API key.

github run

@ask-bonk

ask-bonk Bot commented Sep 8, 2026

Copy link
Copy Markdown

APIError: You do not have access to the organization tied to the API key.

github run

devin-ai-integration[bot]

This comment was marked as resolved.

@ask-bonk

ask-bonk Bot commented Sep 8, 2026

Copy link
Copy Markdown
  • [P1] server.js:539 PowerPoint export calls mutating getDeck(). A documented deck saved without themeVersion is replaced and persisted as the starter deck during export. Normalize setDeck() or use a non-mutating snapshot.

  • [P2] pptx.js:770 Any 1200x12 SVG containing the three brand colors is treated as the canonical brand bar. Additional authored content, such as text, is silently replaced by a plain gradient. Match the canonical SVG exactly or use explicit metadata.

  • [P2] pptx.js:1062, pptx.js:1085 Empty card/box titles still reserve a full estimated line, unlike the browser’s zero-height empty title element. Body-only components are displaced or mis-centered. Treat empty titles as zero-height.

github run

…etDeck schema stamp

- estimateTextHeight wraps greedily at spaces with Arial metrics and the
  run's tracking; auto-height text shapes also use spAutoFit so a
  consumer's own wrapping can only grow the box, never clip.
- The brand-bar shortcut requires the SVG to be built only from
  svg/defs/linearGradient/stop/rect; authored content keeps the placeholder.
- Empty card/box titles occupy no height and emit no shape.
- setDeck stamps themeVersion so a deck written over the GADGET binding
  is not discarded by the next getDeck (client boot or export).
@maxwellpeterson

Copy link
Copy Markdown
Member Author

Re Bonk's three findings (addressed in 2ca67ed):

  • P1 getDeck() mutates during export — root cause was setDeck() persisting a caller-built deck without the themeVersion schema marker that getDeck() checks, so the next read (client boot or export) discarded it. setDeck() now stamps themeVersion: "workspace.1"; export still reads through getDeck() like every other consumer, and only a genuinely malformed store gets reseeded.
  • P2 brand-bar heuristicisBrandBar() additionally requires the SVG to contain only svg/defs/linearGradient/stop/rect elements; any authored content (text, paths) keeps the visible SVG placeholder. Test: a 1200×12 three-color SVG with a <text> child renders the placeholder, not a gradient.
  • P2 empty card/box titles — an empty title now has zero height and emits no shape; the body sits at padding + one flex gap, as in the browser. Tests assert the body offsets.

devin-ai-integration[bot]

This comment was marked as resolved.

Google Slides converts spcPts back into a percentage of the font's natural
line height, so exact points rendered ~15% loose there; a percentage divided
by Arial's 1.15em natural height is what both PowerPoint and Google honour.
@ask-bonk

ask-bonk Bot commented Sep 9, 2026

Copy link
Copy Markdown
  • [P1] pptx.js:77 normalizeXml() builds rope-heavy strings character-by-character. A 100 KB structured-clone deck containing 79 references to one 100,000-character block passes limits but OOMs under a 128 MB heap. Normalize by spans/chunks instead.
  • [P2] pptx.js:1106 Card text shapes are not clipped to the card. Long titles or short resized cards export text beyond the surface, unlike the browser’s overflow: hidden.
  • [P2] pptx.js:1146 Box-body newlines become hard PowerPoint breaks, while the browser collapses them under normal whitespace. Multiline content can therefore overflow only after export.
  • [P2] pptx.js:197 Only hex colors are parsed. Named or functional CSS colors accepted by the editor render correctly in-browser but become fallback colors or transparent in PowerPoint.

Targeted PPTX tests pass.

github run

…ce, card shrink-to-fit

- normalizeXml and the run escaper copy clean spans instead of concatenating
  characters, so decks that alias one large block many times no longer build
  ropes the size of the deck text.
- parseColor accepts rgb()/rgba() and the basic CSS named colors.
- Props the browser renders with white-space normal/nowrap (section label,
  logo, pill, card eyebrow/title, box title/body, arrow label) collapse line
  breaks to spaces instead of becoming hard breaks.
- Card text shapes emit normAutofit so consumers shrink text into the card,
  the nearest native equivalent of overflow: hidden.
@maxwellpeterson

Copy link
Copy Markdown
Member Author

Re Bonk's latest four (addressed in 9611593):

  • P1 normalizeXml ropesnormalizeXml() now copies clean spans and returns the input untouched when nothing needs changing; the run escaper (escapedText) likewise yields spans between &/</>. Test: 79 aliases of a 100 KB block (7.9 MB of text with escapes) export in the normal suite budget.
  • P2 card text not clipped — PresentationML has no text clipping. Card eyebrow/title/body now emit <a:normAutofit/> so consumers shrink text into the card surface; documented as the nearest native equivalent of overflow: hidden.
  • P2 box body newlines — props the browser renders with white-space: normal/nowrap (box title/body, card eyebrow/title, section label, logo, pill, arrow label) now collapse runs of space/tab/newline to one space before export; card body/title/subtitle/text keep hard breaks as they are pre-wrap in the browser.
  • P2 non-hex colorsparseColor accepts rgb()/rgba() (numeric or percentage channels, optional alpha) and the basic CSS named colors; other names still fall back to the component default rather than guessing.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

}
if (options.bullet) {
properties += `<a:buClr><a:srgbClr val="${COLORS.tangerine}"/></a:buClr>` +
'<a:buSzPts val="1000"/><a:buFont typeface="Arial"/><a:buChar char="&#x25CF;"/>';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Bullet markers export oversized

The buSzPts value makes each marker 10 points, while the editor's 6-pixel marker maps to 4.8 points. Exported lists show dots over twice their authored size.

Suggested change
'<a:buSzPts val="1000"/><a:buFont typeface="Arial"/><a:buChar char="&#x25CF;"/>';
'<a:buSzPts val="480"/><a:buFont typeface="Arial"/><a:buChar char="&#x25CF;"/>';
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kernel Changes to the Workshop kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant