fix(desktop): preserve layered PPTX backgrounds - #6845
Conversation
|
🧪 Queued for QA validation — this PR changes the editable PPTX export output users open in WPS/PowerPoint, so we want a manual QA pass before merge. Nothing needed from you right now; we'll update here once it's validated. Thanks! |
nettee
left a comment
There was a problem hiding this comment.
Two correctness blockers remain in apps/desktop/src/main/deck-capture.ts. The focused regression test passes, and pnpm run typecheck / pnpm run build pass in apps/desktop, but the changed gradient allowlist and layout mutation still regress existing deck content. See the inline comments for the concrete cases.
Keep unsupported gradients and static nested panels on their authored elements, and avoid duplicating the slide background shim when Chromium capture owns the layer.\n\nGenerated-By: looper 0.11.8 (runner=fixer, agent=codex)
|
Looper fixer round complete — 8cd874e
🔁 Powered by Looper · runner=fixer · agent=codex · An autonomous AI dev team for your GitHub repos. |
nettee
left a comment
There was a problem hiding this comment.
Fresh pass over the current head found two correctness blockers in apps/desktop/src/main/deck-capture.ts. The positioned-layer case is isolated correctly, but the new preprocessing still drops or mis-renders other authored gradient content; the inline comments describe the failing paths and the concrete fixes needed.
Generated-By: looper 0.11.8 (runner=fixer, agent=codex)
|
Looper fixer round complete — fad335c
🔁 Powered by Looper · runner=fixer · agent=codex · An autonomous AI dev team for your GitHub repos. |
nettee
left a comment
There was a problem hiding this comment.
Two correctness issues remain in the layered-background extraction: it changes masked gradient layers and does not collect pseudo-element gradient layers. The focused desktop suite, desktop typecheck/build, workspace typecheck, and guard pass, but the output-fidelity cases below still need a fix before merge.
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.Generated-By: looper 0.11.8 (runner=fixer, agent=codex)
|
Looper fixer round complete — d3d0b3b
🔁 Powered by Looper · runner=fixer · agent=codex · An autonomous AI dev team for your GitHub repos. |
nettee
left a comment
There was a problem hiding this comment.
Fresh implementation pass found three blocking output-fidelity issues in the new layered-background extraction. The focused desktop suite (334 passed, 1 skipped), desktop typecheck/build, guard, and workspace typecheck all pass locally, but these cases are not covered by the current media-extension assertions.
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.Generated-By: looper 0.11.8 (runner=fixer, agent=codex)
|
Looper fixer round complete — 6b17766
🔁 Powered by Looper · runner=fixer · agent=codex · An autonomous AI dev team for your GitHub repos. |
Generated-By: looper 0.11.8 (runner=fixer, agent=codex)
Generated-By: looper 0.11.8 (runner=fixer, agent=codex)
|
Looper fixer round complete — 4a05094
🔁 Powered by Looper · runner=fixer · agent=codex · An autonomous AI dev team for your GitHub repos. |
nettee
left a comment
There was a problem hiding this comment.
The Chromium isolation work and expanded Electron/PPTX coverage are a strong step toward preserving editable layered backgrounds. One blocking output-fidelity failure remains on this head: pnpm --filter @open-design/desktop test reports 375 passed, 1 failed, and 1 skipped because the clipped-stripe blend case emits [128,128,128] instead of Chromium's [117,117,117] (mean channel delta 8.195 vs. the threshold of 1). Please correct the clipped-backdrop capture before merge; the detailed reproduction and fix direction are anchored below.
Use full-coverage clip and mask probe values so Chromium paint-order sampling preserves the candidates' stacking contexts before authored styles are restored.\n\nGenerated-By: looper 0.11.8 (runner=fixer, agent=codex)
|
Looper fixer round complete — d778871
🔁 Powered by Looper · runner=fixer · agent=codex · An autonomous AI dev team for your GitHub repos. |
nettee
left a comment
There was a problem hiding this comment.
The current head still has one blocking output-fidelity regression in the clipped-stripe blend path. I reproduced it with the changed desktop suite; the detailed failure and fix direction are inline.
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.Expand paint-order probes across standard and prefixed clip or mask ancestors, then keep the focused Chromium-to-PPTX stripe regression on that path. Generated-By: looper 0.11.8 (runner=fixer, agent=codex)
|
Looper fixer round complete — ddc7933
🔁 Powered by Looper · runner=fixer · agent=codex · An autonomous AI dev team for your GitHub repos. |
nettee
left a comment
There was a problem hiding this comment.
The latest ancestor-clipped backdrop change still leaves the focused editable-PPTX regression red. The local focused Electron suite reports 375 passing, 1 skipped, with .clipped-stripe-target exporting [128,128,128] instead of Chromium [117,117,117]; the inline finding below explains why the new probe still drops those backdrop pixels.
Probe non-member compositor descendants against the actual backdrop-dependent capture members and keep selected backdrop paint visible during isolation. Generated-By: looper 0.11.8 (runner=fixer, agent=codex)
|
Thanks for the contribution. I completed QA validation for this PR. QA Acceptance Record Scope:
Scope-to-evidence:
Verified:
Not verified:
Risks / notes:
Conclusion:
|
|
Successfully created backport PR for |
* fix(desktop): preserve layered PPTX backgrounds * fix(desktop): constrain layered PPTX rasterization Keep unsupported gradients and static nested panels on their authored elements, and avoid duplicating the slide background shim when Chromium capture owns the layer.\n\nGenerated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve layered panel edge cases Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve pseudo and masked PPTX layers Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve composed PPTX background layers Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * test(desktop): batch layered PPTX export probe Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * test(desktop): consolidate layered PPTX probe slide Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * test(desktop): terminate layered PPTX probe cleanly Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve layered PPTX capture visibility and order Filter Chromium capture targets to rendered slide intersections, and keep rasterized ::before backgrounds below native pseudo content. Extend the Electron export fixture and give its Linux subprocess enough concurrent-run budget. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * test(desktop): expose layered PPTX probe stage Emit the active Electron renderer stage so CI-side subprocess timeouts identify the blocked boundary instead of returning an empty error. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * test(desktop): paint layered PPTX probe window Mirror the production transparent showInactive lifecycle so requestAnimationFrame advances under Linux/Xvfb. Restore the original probe budgets and remove temporary stage diagnostics. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): layer slide backgrounds below pseudos Reserve explicit and captured slide-background sort slots below rasterized ::before layers so opaque slide fills cannot hide authored gradients. Cover the slide-root pattern with decoded PNG and PPTX media-order assertions. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): keep layered PPTX captures background-only Order positive-z ::after background captures below native pseudo content, and suppress replaced foreground objects only while Chromium captures their layered backgrounds. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): flatten blended PPTX backgrounds Preserve the authored backdrop while Chromium captures non-normal blend layers, including materialized pseudo-element backgrounds, and verify the resulting multiply-composited PPTX pixel. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve blended PPTX backdrops Keep preceding sibling and ancestor pseudo backgrounds visible while Chromium flattens non-normal blend layers, without capturing their foreground content. Extend the real Electron export fixture with a layered pseudo backdrop pixel assertion. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve composited PPTX capture fidelity Normalize the export DOM before Chromium measures layered backgrounds, flatten backdrop-filter dependencies, and preserve per-layer background blending for pseudo captures. Extend the Electron export probe with geometry and decoded-pixel regressions. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * test(desktop): tolerate Chromium color rounding Allow a one-level RGB tolerance for backdrop-filter output so platform-specific Chromium quantization does not fail an otherwise faithful export. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve nested blend backdrops Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): honor paint order and pseudo masks Use Chromium paint-stack hit testing for backdrop selection and preserve complete computed mask geometry on layered pseudos. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve layered PPTX compositing boundaries Flatten nested layered backgrounds through a shared ancestor compositor, and materialize masked pseudo content and borders in the same Chromium capture while suppressing native duplicates. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve native PPTX foreground layers Keep compositor foreground descendants editable while rasterizing only layered backgrounds, suppress captured pseudo helpers, and fully capture masked elements whose foreground cannot be serialized natively. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve PPTX backdrop and pseudo fills Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve PPTX compositor root paint Capture solid compositor-root backgrounds and ancestor backdrop effects with layered descendants, and suppress duplicate native fills for materialized pseudos. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): capture composited pseudo foregrounds Capture generated pseudo content and borders with layered mix-blend or backdrop-filter backgrounds so Chromium preserves their complete compositing before native pseudo suppression. Add an Electron/PPTX pixel comparison against the authored Chromium rendering and verify no duplicate native pseudo text remains. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * test(desktop): normalize composited pseudo capture scale Sample the Chromium reference at two CSS pixels regardless of host device pixel ratio so Linux/Xvfb and Retina runners compare equal-sized images. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve nested PPTX compositor paint Capture intermediate compositor paint and real mix-blend foregrounds in Chromium while suppressing their duplicate native output. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve whole-paint PPTX captures Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): capture unsupported PPTX foreground effects Capture text-clipped layers, unsupported ancestor-effect subtrees, and self-composited pseudos as whole Chromium paint so the editable exporter cannot emit mismatched native foregrounds. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve layered PPTX capture fidelity Normalize Chromium capture scale by renderer DPR, capture text-clipped generated pseudos as complete paint, and retain pseudo box shadows in raster helpers. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve PPTX compositor roots Capture slide-root effects with their layered foregrounds and use paint-aware full-overlap sampling for clipped blend backdrops. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): bound layered PPTX paint groups Preserve intermediate wrapper fills inside compositor captures so raster replacements keep authored paint order. Bound clipped-backdrop fallback work with stratified sampling instead of area-scaled hit testing. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve clipped PPTX blend backdrops Replace the fixed paint-membership grid with a clip-aware Chromium paint-order probe so narrow masked or clipped backdrops cannot fall between sample centers. Cover the 1920x1080 DPR-2 case with a focused 1px stripe pixel comparison. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): capture clipped PPTX foreground groups Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): recheck clipped PPTX backdrop order Let clip and mask candidates reach the clip-free paint-order probe, and clear the first probe state before evaluating the second pass. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * test(desktop): map PPTX captures to exported media Resolve each Chromium capture through its slide picture geometry and relationship, using pixel similarity only to disambiguate overlapping images. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * test(desktop): make PPTX probe scale DPR-aware Match the Electron media probe capture scale to the production 2-physical-pixels-per-CSS-pixel formula across DPR 1 and DPR 2 renderers. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): retain clipped PPTX backdrop order Use full-coverage clip and mask probe values so Chromium paint-order sampling preserves the candidates' stacking contexts before authored styles are restored.\n\nGenerated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): retain ancestor-clipped PPTX backdrops Expand paint-order probes across standard and prefixed clip or mask ancestors, then keep the focused Chromium-to-PPTX stripe regression on that path. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) * fix(desktop): preserve nested PPTX blend backdrops Probe non-member compositor descendants against the actual backdrop-dependent capture members and keep selected backdrop paint visible during isolation. Generated-By: looper 0.11.8 (runner=fixer, agent=codex) (cherry picked from commit 12de3ed) Co-authored-by: Ray Xi <2667192167@qq.com>
Why
An editable PPTX exported from a real Open Design deck rendered its cream paper background as black in WPS and macOS Quick Look. The source deck uses two CSS
linear-gradient(...)background layers for its paper texture. The vendoreddom-to-pptxgradient parser assumes a single gradient and greedily combines the two layers into one invalid SVG gradient, producing the dark fallback image.This fixes the reported export without changing the deck source or flattening the whole slide. It is intentionally scoped to the layered-background problem; the font and heading fidelity work remains in #6840.
What users will see
Exporting a deck with layered CSS gradients through the existing editable PPTX action preserves the authored background instead of turning it black. The background-only layer is rasterized with Chromium, while authored text and shapes remain native editable PowerPoint objects.
Surface area
apps/weborapps/desktop(including Electron menu bar)odsubcommand or flag, newtools-dev/tools-packflag, or newOD_*env var/api/*endpoint, new SSE event, or changed shape inpackages/contractsskills/,design-systems/,design-templates/, orcraft/, or change to the skills protocolTRANSLATIONS.mdfor the locale workflow)package.json(dependenciesordevDependencies); workspace-packagepackage.jsonfiles are out of scope. Include a paragraph on what we get vs. what bytes we ship (seeCONTRIBUTING.md→ Code style)Screenshots
No new UI entry point. Manual visual verification used the reported 10-page deck: the exported slide background changed from the black fallback to the authored cream paper texture in macOS Quick Look, and the PPTX package contains native text/shape objects alongside the isolated background image.
Bug fix verification
apps/desktop/tests/main/pptx-layered-background.test.tsmain: yes — the converter received the original two-layer gradient and the assertion failed because no isolated Chromium-capture layer existed.Validation
pnpm --filter @open-design/desktop test— 327 passed, 1 skippedpnpm --filter @open-design/desktop typecheckpnpm --filter @open-design/desktop buildpnpm guardpnpm typecheck