Skip to content

Releases: textcortex/SlideWise

@textcortex/slidewise@1.21.1

12 Jun 11:03
f7273c8

Choose a tag to compare

Patch Changes

  • 94e348b: fix(render): emit a valid SVG <image> for image-fill backgrounds

    renderDeckToSvg rendered a slide's image-fill background as a CSS background
    shorthand inside an SVG fill="…" attribute — fill="center / cover no-repeat url("data:image…")". That is not valid SVG (a non-paint value plus nested
    unescaped quotes); browsers tolerate it, but strict rasterisers
    (@resvg/resvg-js, librsvg, batik) reject it, blocking a Chromium-free
    parsePptx → renderDeckToSvg → resvg → PNG path.

    The pptx importer stores image backgrounds as a CSS shorthand, but the
    renderer's image-ref detection only inspected the start of the value, so the
    shorthand fell through to the fill path. The renderer now recognises a
    url(...) anywhere in the value and emits a real <image> element
    (preserveAspectRatio = slice for cover, meet for contain). A lock-in
    test asserts every rendered slide is valid SVG a strict XML parser accepts,
    with an image-background slide as the regression case.

@textcortex/slidewise@1.21.0

12 Jun 07:17
6c38b79

Choose a tag to compare

Minor Changes

  • 652f804: feat(pptx): layout-instantiation in applyEdits (lossless scale-with-variety)

    applyEdits now supports source: { layoutId, fills? } in a PlannedSlide
    instantiating a fresh slide from one of the template's own layouts inside
    the lossless byte-patch path. Because the layout is already a part of source,
    the new slide binds to ppt/slideLayouts/<layoutId>.xml (inheriting theme /
    master / background chrome) while every other part stays byte-identical. This
    unlocks lossless and scale-with-variety in one deck: clone slides where you
    want the exact thing, instantiate from layouts where you want variety.

    Each layout placeholder is materialised as an addressable, positioned element
    with a deterministic id — layoutSlotElementId(layoutId, key) (exported) where
    key is the placeholderKey / summarizeLayouts slot key. Text/obj slots
    are populated from fills and editable via setText; picture slots become a
    <p:pic> with a transparent placeholder blip so setImage can repoint them;
    chart/table/other slots expose their geometry so the host fills them with
    addChart / addDiagram. Placeholder geometry is read EMU-native from the
    layout (falling back to the matching master slot), so it stays correct without a
    canvas-px round-trip. An unresolvable layoutId is surfaced via onWarning and
    the slide is skipped rather than shipped wrong.

  • 652f804: feat(render): headless renderDeckToImages + deck.fontUsage font transparency

    Headless render-to-image (visual-QA loop). New browser-free renderer that
    draws what the editor draws — native charts (buildChartOption + ECharts
    SSR), diagrams (layoutDiagram), text/shapes/images/backgrounds in z-order —
    not the OOXML raster fallbacks. No Playwright/Chromium/DOM.

    • renderDeckToSvg(deck, opts?) → one composed SVG per slide (ECharts is
      loaded on demand, so it never bloats the editor bundle).
    • renderDeckToImages(deck, opts?) / renderSlideToImage(deck, i, opts?) /
      renderPptxToImages(bytes, opts?) → raster bytes. Rasterisation is an
      injected hook (opts.rasterizeSvg, e.g. @resvg/resvg-js); when omitted the
      default tries a dynamic @resvg/resvg-js import and throws a clear error if
      it isn't installed — so there's no hard native dependency.
    • opts: slides (1-based subset), dpi (canvas scales by dpi/96),
      format, maxWidth (thumbnail cap). Deterministic (no animation).

    Enables the host's render → fresh-eyes inspect → targeted applyEdits fix →
    re-render cycle, rendering a final applyEdits output directly.

    Font transparency. parsePptx now stamps deck.fontUsage: { family, embedded }[] — every font family the deck's text uses, flagged
    whether the source PPTX actually embeds it (<p:embeddedFontLst> → a real
    ppt/fonts/* part) or merely references it (system-fallback risk on
    viewers that don't ship the brand font). Hosts use it to warn at generation
    time ("missing fonts for some ppts"). It's a read-only diagnostic, distinct from
    deck.fonts (the embeddable payloads).

@textcortex/slidewise@1.20.0

12 Jun 07:03
9142445

Choose a tag to compare

Minor Changes

  • e56ddd2: feat(pptx): applyEdits — lossless surgical-edit API

    Add applyEdits(source, plan, options?): a patch on the original .pptx bytes
    rather than a full re-serialize. The create flow can now emit an EditPlan
    (subset/reorder/repeat of template slides, each with edits) and get back a valid
    package where everything not named by an edit is byte-identical to the source —
    masters, layouts, theme, embedded fonts, ppt/tags/*, notes, embeddings, and
    any untouched element. This removes the lossy round-trip that produced the
    custGeom/SVG-fallback/dangling-rel fidelity bugs and lets hosts drop their
    defensive cleanup. serializeDeck stays for the live editor / from-scratch decks.

    Edits address elements by the same stable ids parsePptx returns; slides by
    1-based template index. Supported ops: setText/clearText (preserve the
    template box + run styling, or rebuild from supplied runs), setChartData
    (repopulate a native chart in place — type/colours kept, caches and the
    embedded xlsx workbook updated so Edit-Data still works), setTableData,
    setImage, removeElement, addChart, addDiagram, plus per-slide
    background and deck title. Removed slides and any parts that become
    exclusive to them are reclaimed by a package-wide reachability sweep, then
    dangling relationships and content-types are reconciled. Unresolved element ids
    and unsupported layout-instantiation are surfaced via onWarning instead of
    throwing.

@textcortex/slidewise@1.19.1

11 Jun 11:14
d330c77

Choose a tag to compare

Patch Changes

  • 305dc0f: fix(pptx): emit a structurally valid package on serialize

    Three serializeDeck bugs corrupted the generated .pptx (missing parts /
    invalid image bytes) even from clean source templates, triggering a PowerPoint
    repair prompt and outright rejection by stricter consumers (Google Slides,
    LibreOffice, OOXML validators):

    • Dangling tags relationships: the chrome-preserve path re-pointed a
      slide's tag rel at a slidewise_preserved_* name, then clobbered that part by
      re-copying the source tags under their original names. The rel now resolves
      to the de-prefixed part it should always have pointed at.
    • Dangling notesMaster relationships: pptxgenjs writes a notesSlide per
      slide linked to a notes master, which chrome preservation removed without a
      source replacement. The orphaned (implicit, non-body-referenced) relationship
      is now dropped.
    • SVG markup in .png raster fallbacks: dual SVG images (<a:blip> raster
      • <asvg:svgBlip> vector) had the SVG source written into the .png
        fallback. The fallback is now a real rasterized PNG (browser) or a valid
        transparent PNG (SSR/Node); the vector svgBlip part is untouched.

    Adds a final reconcileDanglingRels invariant guard — every internal
    relationship target must resolve to a shipped part — that backstops both
    dangling-rel shapes (repairing recoverable targets, dropping only
    safe-to-remove optional ones, and leaving critical rels untouched). Also runs
    pruneDanglingContentTypes on the source-preservation path so stale
    [Content_Types] overrides (pptxgenjs's slideMaster1..N, leftover notes
    overrides) can't invalidate the package either.

@textcortex/slidewise@1.19.0

10 Jun 17:58
2fd7a26

Choose a tag to compare

Minor Changes

  • 3e7c3f1: First-class diagram element (P3 / F3). A new DiagramElement models
    process / timeline / funnel / matrix / cycle / list visuals as an ordered set
    of labelled nodes instead of a hand-placed cluster of shapes and lines. The
    renderer and the PPTX writer share one layout function (layoutDiagram, also
    exported), so the on-canvas preview and the saved file can't drift. On export a
    diagram serialises to a single labelled <p:grpSp> of real shapes + connectors
    — so it stays grouped and editable in PowerPoint (move/resize as one unit)
    rather than collapsing to anonymous floating shapes. Exposed via the
    DiagramElement / DiagramNode / DiagramKind types and the layoutDiagram
    helper.

  • 3e7c3f1: Host deck-generation ergonomics (review follow-ups for layout instantiation):

    • summarizeLayouts(deck, options){ compact: true } returns the minimal
      { id, name?, role, fillable } shape (no geometry) for a tight model-context
      budget; { dedupe: true } collapses layouts that share a role + full
      placeholder-slot inventory (text and non-text chart/picture/table slots)
      into one representative carrying the rest as aliases, so an 85-layout
      template surfaces as its handful of distinct kinds — and a chart-bearing
      layout never collapses into a text-only twin. Composable.
    • Robust sourceLayoutId resolution — a host-authored slide's
      sourceLayoutId now resolves from deck.layouts or, when the host didn't
      carry the layouts array, by the ppt/slideLayouts/<id>.xml id convention
      against the { source } archive. When it resolves to nothing, serializeDeck
      emits a structured { code: "layout-unresolved", slideIndex, layoutId }
      warning instead of silently falling back.
    • Richer chrome-skipped warning — now carries the detected sourceAspect
      and outputAspect so a host can explain why chrome was dropped.

    Plus README: the host "author-a-slide" contract ({ sourceLayoutId, background: "transparent", elements } without a JS call), the recipe for
    placing non-text slots from summarizeLayouts geometry, and the server-side
    layoutDiagram render recipe with its DOM-free guarantee.

  • 3e7c3f1: Round-trip fidelity fixes (P4):

    • Image crop / radius now round-trip. Previously an image's crop
      (<a:srcRect>) was read on import but silently dropped on export, and corner
      radius was neither parsed nor written. serializeDeck now routes any image
      carrying a crop or radius through a dedicated <p:pic> writer (emitting
      <a:srcRect> and roundRect geometry) instead of pptxgenjs — whose
      cover/contain sizing emits its own <a:srcRect> and would fight a user crop —
      and parsePptx reads a rounded picture's corner radius back. Plain
      (uncropped, square-cornered) images keep the existing path unchanged.
    • Text-run letter-case (cap) now round-trips. A run's cap
      ("all" / "small", OOXML <a:rPr cap>) was parsed on import but dropped on
      export (pptxgenjs has no cap option). It's now re-applied per run in
      post-process, so all-caps / small-caps styling survives a save.
  • 3e7c3f1: Harden layout instantiation for AI deck generation (P1 / F1):

    • Layout-instantiated slides now inherit their layout's background. A slide minted by addSlideFromLayout with the default transparent background no longer serialises an explicit <a:noFill/> <p:bg> — that empty background was overriding the layout/master/theme inheritance, so instantiated slides lost their on-brand background. They now stay <p:bg>-less and paint from their sourceLayoutId layout's chrome (matching the source-slide guarantee for cloned/reordered slides).
    • Layout-selection metadata. DeckLayout.type now carries the raw OOXML <p:sldLayout type> role, and the new summarizeLayouts(deck) returns a compact, model-context-friendly layout menu (friendly role label, fillable fills keys, per-placeholder kind/category/geometry) so a host can have a model pick a layout per slide. placeholderKey(ph) exposes the exact fills key for a placeholder.
  • 3e7c3f1: Machine-readable serialization diagnostics (P2 / B3). serializeDeck now
    accepts SerializeOptions.onWarning, a callback invoked with a structured
    SerializeWarning when the output degrades. The key case is
    "chrome-skipped" — emitted when a source template's masters / layouts /
    theme / fonts can't be carried over because its slide size is unreadable, so
    the deck falls back to generic chrome. Hosts can now detect and surface the
    degradation instead of only seeing a console line. (Non-16:9 sizing for 4:3 /
    16:10 / custom templates already drives the output slide size; this adds the
    escape-hatch signal when it can't.)

@textcortex/slidewise@1.18.1

10 Jun 07:51
a8ccfb8

Choose a tag to compare

Patch Changes

  • f16cfa5: fix(pptx): respect z-order for synthesised content (charts, custGeom shapes, connectors)

    Synthesised spTree content was always inserted at the back of the slide, so an
    in-app chart / custGeom "SVG" / connector with a higher z than its background
    card was buried behind that card (and its shadow) and rendered invisible. Each
    synth item now anchors directly on top of the pptxgenjs node it sits above
    (matched by shape name), preserving the deck's z-order, and only falls to the
    back when it is genuinely below every model element.

@textcortex/slidewise@1.18.0

10 Jun 06:30
247ee75

Choose a tag to compare

Minor Changes

  • 17c069f: Template-faithful serialization fixes and new authoring primitives for AI deck generation:

    • Per-slide source mappingSlide.sourceSlideIndex lets a host that clones / reorders / subsets imported slides declare which source slide each output slide replays its background and layout from, instead of mapping by output position (fixes blank/white-on-white slides on reordered decks).
    • Deep chart preservation — preserved charts now carry their full dependency tree (embedded workbook, colors/style parts, rels, content types), so they no longer trigger a PowerPoint repair and keep "Edit Data" + custom styling.
    • Non-16:9 templates — a source's real slide size now drives the output (4:3, 16:10, custom), preserving its masters / layouts / theme / fonts and inverting the authoring-canvas fit for emitted elements, instead of silently falling back to a generic 16:9 deck.
    • Instantiable layoutsparsePptx exposes master layouts on Deck.layouts, and the new addSlideFromLayout(deck, layoutId, opts) mints a fresh slide bound to a layout with its text placeholders ready to fill.
    • Chart-option helpersbuildChartOption, defaultPaletteColor, and makeValueFormatter are exported so hosts can build the exact ECharts options Slidewise renders (e.g. for server-side previews).
    • Connector primitive — a first-class connector element (straight / bent / curved, arrowheads, flips) with renderer + <p:cxnSp> writer support.

@textcortex/slidewise@1.17.1

09 Jun 10:36
f155641

Choose a tag to compare

Patch Changes

  • 83683e3: fix(pptx): render <a:grpFill/> shapes by inheriting the group's fill

    Decorative line-art (e.g. the swoosh graphic on a title slide) is often
    authored as many <a:custGeom> segments inside a single <p:grpSp>, with every
    segment declaring <a:grpFill/> so they share the group's one translucent
    colour. parsePptx had no grpFill branch, so each segment fell through to
    transparent and the entire graphic disappeared on import — present in the
    source but invisible in the deck.

    The group's resolved fill is now threaded down to descendants, and a shape with
    <a:grpFill/> paints with it (walking up the group chain when an inner group
    defines no fill of its own). Geometry was already preserved; only the paint was
    being dropped.

@textcortex/slidewise@1.17.0

03 Jun 16:41
30e4a06

Choose a tag to compare

Minor Changes

  • 019e000: feat(pptx): support PowerPoint templates (.potx)

    .potx and .pptx share an identical OOXML package; only the main part's
    content type in [Content_Types].xml differs. This adds first-class template
    support across import and export:

    • parsePptx already parsed .potx transparently (it reads parts by path, not
      by content type) — now the rest of the pipeline preserves template-ness.
    • New exported isPptxTemplate(blob) detects a template by inspecting the
      package content type rather than trusting a filename extension (a mis-named
      .pptx that is really a template is detected correctly).
    • serializeDeck gains an asTemplate?: boolean option. When omitted,
      template-ness is inherited from the source archive, so a parsed .potx
      round-trips back to a .potx; pass true/false to force the output kind.
      Templates are emitted with the …presentationml.template.main+xml main-part
      content type and the .potx MIME type.

@textcortex/slidewise@1.16.4

03 Jun 12:35
a3bc116

Choose a tag to compare

Patch Changes

  • a085c8d: fix(pptx): import-fidelity fixes for think-cell / brand-template decks

    • Skip shapes flagged hidden="1" (e.g. think-cell "do not delete" data objects)
    • Render run-level text highlight (<a:rPr><a:highlight>) end to end
    • Apply cap="all"/"small" (including when inherited from a placeholder list style) as a render-time letter-case transform
    • Derive font weight from weight-named families ("Gilroy ExtraBold" → 800, "… Medium" → 500, …) so substitute fonts render at the right heaviness
    • Tables: per-cell fills, text colours, per-side borders, proportional column widths / row heights, cell spans (gridSpan/hMerge/rowSpan/vMerge), per-cell vertical anchor, and rich per-cell runs (highlight / bold / ✓ glyphs / bullet line breaks). Unfilled cells stay transparent instead of inheriting a sibling fill
    • Map Wingdings bullet glyphs to Unicode (ü→✓, q→☐, §→▪, …)
    • Bullets: repeat a character bullet across in-paragraph line breaks, suppress the glyph on empty paragraphs, and trim trailing empty paragraphs
    • Synthesise block-arrow paths (down/up/left/rightArrow) and resolve outline colour from <p:style><a:lnRef> so dashed/outlined shapes draw
    • Keep a text-bearing preset or custom-geometry shape's fill, border, and corner radius behind its text (roundRect callouts, outlined chevrons)
    • Honour <a:bodyPr><a:spAutoFit> no-wrap for short single-line labels; skip the arrow-tip text inset on no-fill label shapes
    • Render per-paragraph hanging-indent bullets as one block per line so multi-line items align correctly