pptx-kit 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,169 @@
1
1
  # pptx-kit
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6060afc: `setShapeRunFormat` / `getShapeRunFormat` / `getShapeRunFormatEffective` now
8
+ support `fontEastAsian`, a per-run East Asian typeface override (`<a:ea>`),
9
+ alongside the existing `font` (`<a:latin>`). Previously a run's CJK glyphs
10
+ always fell back to whichever East Asian font the theme's major/minor font
11
+ scheme happened to carry, with no way to set a distinct typeface (e.g. a
12
+ serif headline vs. a sans-serif body) on an individual run. `fontEastAsian`
13
+ resolves theme `+mj-ea`/`+mn-ea` tokens and falls back to the theme's major/
14
+ minor East Asian font the same way `font` already does for Latin text.
15
+ - fa5e53f: Added two authoring capabilities aimed at complex, dense slide layouts
16
+ (process diagrams, KPI cards, branded decks):
17
+
18
+ - `groupShapes` / `ungroupShapes` compose a selection of top-level shapes
19
+ into a single `<p:grpSp>` (and reverse it). The group's bounds are the
20
+ union of its members; moving or resizing the group afterwards rescales
21
+ every member on ungroup, so a "KPI card" or diagram node built from a
22
+ rectangle + label can be treated — and repositioned — as one unit.
23
+ - `setPresentationTheme` / `setPresentationFonts` patch a deck's color
24
+ scheme and font scheme in place, so a from-scratch deck can be branded
25
+ with a custom palette and typography without hand-authoring a template.
26
+ Only the slots passed in are overwritten; every other slot keeps its
27
+ existing value.
28
+
29
+ ## 0.9.0
30
+
31
+ ### Minor Changes
32
+
33
+ - eeb8659: Validate authoring inputs at the API boundary so out-of-range values throw a
34
+ clear `RangeError` instead of silently emitting a schema-invalid `.pptx` that
35
+ PowerPoint marks corrupt and "repairs".
36
+
37
+ A generative schema-validation sweep surfaced a whole class of defects where a
38
+ caller-supplied number/string was serialized straight into a constrained
39
+ ECMA-376 attribute. These now reject (or, for GUIDs, normalize) at the boundary:
40
+
41
+ - Run formatting: `setShapeRunFormat` font `size` (ST_TextFontSize, 1..4000 pt)
42
+ and `spc` (ST_TextPoint). It also now accepts the 3-digit hex shorthand for
43
+ run `color` / `highlight`, matching `setShapeFill` / `setShapeStroke`.
44
+ - Tables: `setTableStyleId` / `addSlideTable` `styleId` (ST_Guid — a lowercase
45
+ GUID from `crypto.randomUUID()` is now accepted and normalized to uppercase;
46
+ a non-GUID string throws); `setTableCellBorders` `widthEmu` (ST_LineWidth);
47
+ `setTableColumnWidth` / `setTableRowHeight` / `addSlideTable` `w`/`h`
48
+ (ST_PositiveCoordinate); `setTableCellMargins` (ST_Coordinate32).
49
+ - Charts: bar/column `overlapPct` (ST_Overlap), `gapWidthPct` (ST_GapAmount),
50
+ and series `lineWidthEmu` (ST_LineWidth).
51
+ - Animations / transitions: `setShapeAnimation` `durationMs` and
52
+ `setSlideTransition` `advanceAfterMs` (xsd:unsignedInt); the transition
53
+ `effect` token is validated against the spec's effect set (an empty or unknown
54
+ string previously produced non-well-formed or schema-invalid XML).
55
+ - Connectors / strokes: `addSlideLine` and `setShapeStroke` `widthEmu`
56
+ (ST_LineWidth) and `addSlideLine` endpoint coordinates.
57
+ - Text boxes: `setShapeTextColumns` `count` (ST_TextColumnCount, 2..16) and
58
+ `gapEmu` (ST_PositiveCoordinate32); `setShapeTextMargins` insets
59
+ (ST_Coordinate32); `setShapeTextBodyRotationDeg` (guards the ST_Angle overflow).
60
+ - Fills: `setShapePatternFill` `preset` is validated against ST_PresetPatternVal
61
+ (and the `PatternPreset` type is now the exact token union, not `string`).
62
+ - Shape / image / chart geometry: `addSlideShape` / `addSlideTextBox` /
63
+ `addSlideImage` / `addSlideChart` and `setShapePosition` / `setShapeSize`
64
+ `x`/`y` (ST_Coordinate) and `w`/`h` (ST_PositiveCoordinate).
65
+
66
+ - eeb8659: Fix a batch of "generates but is schema-invalid / wrong" authoring bugs, add an
67
+ AI-agent authoring skill, and smooth several LLM-facing rough edges.
68
+
69
+ Correctness fixes (output is now schema-valid in these cases):
70
+
71
+ - Notes slides emitted a `<p:notesSlide>` root instead of the spec's `<p:notes>`,
72
+ failing schema validation.
73
+ - Combining a run's text `color` with `highlight` emitted them out of order.
74
+ - Combining stroke dash / arrowheads / join, or a paragraph's bullet with
75
+ `setParagraphSpacing`, or a table cell's fill with `setTableCellBorders`,
76
+ emitted child elements out of their schema-mandated order.
77
+ - Table cells containing leading/trailing spaces, tabs, or newlines emitted an
78
+ illegal `xml:space` attribute (and a newline now correctly splits a cell into
79
+ multiple lines).
80
+ - `setSlideTransition({ effect: 'none' })` emitted an invalid `<p:none/>`; per-effect
81
+ attributes (`direction`/`orientation`/`thruBlack`) are now only emitted on
82
+ effects that allow them, and `direction` is validated against the effect's own
83
+ value domain (e.g. `blinds` takes `horz`/`vert`, `push` takes `l`/`r`/`u`/`d`) —
84
+ a mismatched pair like `{ effect: 'blinds', direction: 'l' }` now throws instead
85
+ of emitting schema-invalid XML.
86
+ - Charts emitted `<c:marker>`, `<c:smooth>`, `<c:invertIfNegative>`, and
87
+ `<c:trendline>` on series kinds that don't permit them (e.g. a trendline on a
88
+ `pie`/`doughnut`/`radar` series, which `CT_PieSer`/`CT_RadarSer` reject), and
89
+ `valueAxis` `min`/`max` in the wrong order.
90
+ - `setShapeImageBrightness` / `setShapeImageContrast` emitted `<a:lumOff>` /
91
+ `<a:lumMod>`, which aren't valid `<a:blip>` children; both now write a single
92
+ schema-valid `<a:lum bright/contrast>`.
93
+ - `setShapeGradientFill` ignored its documented `path` / `focus` options, silently
94
+ downgrading radial/shape gradients to linear.
95
+ - `importSlide` could emit a duplicate `rId` when the source slide's layout
96
+ relationship wasn't `rId1`.
97
+ - `setShapeAnimation` wiped any pre-existing `<p:timing>` on the slide (losing a
98
+ template's authored animations); it now merges, so multiple shapes can animate.
99
+ - `compactPackage` / `readPackagePart` / `setMediaPartBytes` matched part names
100
+ case-sensitively, unlike the rest of the package layer — a referenced image
101
+ whose rel-target case differed could be wrongly deleted or missed.
102
+
103
+ Behavior change:
104
+
105
+ - `setShapeImageContrast` now takes a `[-1, 1]` offset (`0` = no change) instead
106
+ of the previous `[0, 2]` multiplier, matching the underlying `<a:lum contrast>`.
107
+ - Unstyled connectors (`addSlideLine` without an explicit stroke) previously
108
+ emitted no line style and rendered invisibly; they now carry a default
109
+ `<p:style>` (`lnRef`/`fillRef`/`effectRef`/`fontRef`) so the line is visible.
110
+
111
+ Ergonomics:
112
+
113
+ - Colors accept the CSS-style 3-digit hex shorthand (`#f0a` → `FF00AA`).
114
+ - New `setParagraphLineSpacing(shape, p, { kind, value })` (the writer counterpart
115
+ to the existing getter).
116
+ - `setTableCellBorders` accepts a partial border per side, so `{ color, widthEmu }`
117
+ type-checks without spelling out `dash` (the read type `getTableCellBorders`
118
+ returns stays strict — all fields populated).
119
+ - `addSlideShape` `textAnchor` is narrowed to the valid vertical anchors
120
+ (`'t' | 'ctr' | 'b'`).
121
+
122
+ Docs:
123
+
124
+ - New `skill/SKILL.md` — a guide for driving pptx-kit from an AI agent (canonical
125
+ calls, design rules, footguns, and a QA protocol), with a verified worked
126
+ example.
127
+
128
+ - eeb8659: Close a final batch of correctness defects a generative schema sweep surfaced,
129
+ where the writer emitted a `.pptx` PowerPoint marks corrupt:
130
+
131
+ - **XML-illegal control characters** in any text field (shape text, table cells,
132
+ notes, chart titles/categories/series, hyperlink tooltip/URL, section names,
133
+ comments) used to serialize raw, producing a non-well-formed part that
134
+ corrupts the whole package. They are now rejected at serialization with a
135
+ clear error; the XML-legal whitespace controls (tab / LF / CR) still pass
136
+ through. (XML 1.0 forbids the other C0 controls outright — they cannot even be
137
+ escaped as numeric references.)
138
+ - **Chart percentages** are now range-checked at the boundary: `gapWidthPct`
139
+ (ST_GapAmount, 0..500 — the previous limit of 65535 let 501..65535 through),
140
+ doughnut `holeSizePct` (ST_HoleSize, 1..90), and pie/doughnut
141
+ `firstSliceAngleDeg` (ST_FirstSliceAng, 0..360).
142
+ - **Shape effects**: `setShapeShadow` `blurEmu`/`offsetEmu` and `setShapeGlow`
143
+ `radiusEmu` are validated as ST_PositiveCoordinate (fractional rounds;
144
+ negative / non-finite / over-max throws) instead of emitting an invalid value.
145
+ - **Scheme-color round-trip**: the read-back getters return `scheme:<token>`, but
146
+ the setters rejected that string. `setShapeFill` / `setShapeStroke` /
147
+ `setSlideBackground` now accept the `scheme:` prefix, so `setX(getX(...))`
148
+ round-trips. (An unknown `scheme:` token still throws.)
149
+ - **`importSlide` / `mergePresentations`**: importing a slide that contains a
150
+ chart left a dangling `r:id` (the chart frame referenced a relationship the
151
+ imported slide no longer carried), producing a corrupt package. The orphaned
152
+ graphic frame is now dropped, matching the documented "charts are not imported
153
+ in v1" behavior.
154
+ - **`addSlideShape` presets**: the math-operator tokens were misspelled
155
+ (`minus`/`mult`/`div`/`equal`/`notEqual`) and not in `ST_ShapeType`, so the
156
+ shape silently vanished on open. They are now the spec names `mathMinus`,
157
+ `mathMultiply`, `mathDivide`, `mathEqual`, `mathNotEqual` (plus `mathPlus`).
158
+
159
+ ### Patch Changes
160
+
161
+ - e9eae5c: Fix `<a:tint>` / `<a:shade>` colour resolution to compute in linear-light RGB,
162
+ matching PowerPoint and LibreOffice. A 75% tint of black now resolves to a mid
163
+ grey (~#8B8B8B) instead of the too-dark #404040, so colours derived from theme
164
+ scheme transforms (subtitle placeholders, table banding, chart fills) render at
165
+ the right lightness.
166
+
3
167
  ## 0.8.0
4
168
 
5
169
  ### Minor Changes
package/README.md CHANGED
@@ -3,10 +3,12 @@
3
3
  Generate and edit `.pptx` (PowerPoint / Office Open XML Presentation) files
4
4
  from TypeScript — in **Node.js or the browser**, from a single ESM bundle.
5
5
 
6
- > **Status: 1.0 public API stabilized.** Every capability in the table
7
- > below works end-to-end against real PPTX fixtures, with every emitted XML
8
- > part validated against the ECMA-376 schemas via `xmllint` in CI. Future
9
- > 1.x releases are SemVer-compatible.
6
+ > **Status: 0.x — pre-1.0, public API still evolving.** The capabilities in
7
+ > the table below are exercised against real PPTX fixtures, and emitted XML is
8
+ > checked against the ECMA-376 schemas with `xmllint` where it is available on
9
+ > the machine running the tests. Until the 1.0 release the public API is not
10
+ > frozen — breaking changes can land in a minor (`0.x`) release, so pin a
11
+ > version or an exact range.
10
12
 
11
13
  ## Why
12
14
 
@@ -31,10 +33,11 @@ one trade-off:
31
33
 
32
34
  ## Scope
33
35
 
34
- The work is split into four levels of completeness. The v1.0 release targets
35
- levels 1-3 in full and level 4 in part:
36
+ The work is split into four levels of completeness. The current `0.x` line
37
+ covers levels 1-3 in full and level 4 in part; the table tracks where each
38
+ capability stands today. Items marked "post-1.0" are not implemented yet:
36
39
 
37
- | Level | Capability | v1.0 |
40
+ | Level | Capability | 0.x |
38
41
  | ----- | ------------------------------------------------------------------- | ------------------------------- |
39
42
  | L1 | Read an existing PPTX, save it back without corruption | ✅ |
40
43
  | L2 | Template edit — text replacement, image swap, add slide from layout | ✅ |
@@ -97,6 +100,16 @@ if (title) setShapeText(title, 'Hello');
97
100
  const out = await savePresentation(pres);
98
101
  ```
99
102
 
103
+ ## Driving pptx-kit from an AI agent
104
+
105
+ [`skill/SKILL.md`](skill/SKILL.md) is a self-contained guide for an LLM agent
106
+ authoring presentations with this library: the canonical call for each
107
+ capability, the design rules that keep output from looking template-generated,
108
+ the handful of API footguns worth memorizing, and a QA loop to run before
109
+ declaring a deck done. Its [worked example](skill/examples/business-deck.md) is
110
+ exercised by the test suite, so the code there is known to produce a
111
+ schema-valid deck.
112
+
100
113
  CI enforces the tree-shake bound in `test/tree-shake.test.ts`.
101
114
 
102
115
  ## Usage
@@ -346,7 +359,7 @@ shown together.
346
359
  | Shape authoring | `addSlideTextBox`, `addSlideShape`, `addSlideLine`, `addSlideTable`, `addSlideImage`, `addSlideChart` |
347
360
  | Shape lookup | `findShapeByName`, `findShapesByName`, `findShapesByKind`, `findShapeInPresentation`, `getAllShapes`, `getSlideShapes` |
348
361
  | Shape text | `setShapeText`, `setShapeBullets`, `setShapeAlignment`, `setShapeTextFormat`, `setShapeHyperlink` / `getShapeHyperlink` |
349
- | Per-paragraph | `setParagraphAlignment` / `getParagraphAlignment`, `setParagraphLevel` / `getParagraphLevel`, `setParagraphBullet` / `getParagraphBullet` |
362
+ | Per-paragraph | `setParagraphAlignment` / `getParagraphAlignment`, `setParagraphLevel` / `getParagraphLevel`, `setParagraphBullet` / `getParagraphBullet`, `setParagraphSpacing` / `getParagraphSpacing`, `setParagraphLineSpacing` / `getParagraphLineSpacing` |
350
363
  | Per-run text | `setShapeRunText` / `getShapeRunText`, `setShapeRunFormat` / `getShapeRunFormat`, `getShapeParagraphCount`, `getShapeRunCount` |
351
364
  | Text frame | `setShapeTextAnchor` / `getShapeTextAnchor`, `setShapeTextMargins` / `getShapeTextMargins` |
352
365
  | Fill | `setShapeFill` / `getShapeFill`, `setShapeGradientFill`, `setShapePatternFill`, `setShapeImageFill`, `setShapeNoFill`, `clearShapeFill` |
@@ -365,12 +378,12 @@ shown together.
365
378
 
366
379
  ## Compatibility
367
380
 
368
- - **Node**: >= 20.
381
+ - **Node**: >= 24.16.
369
382
  - **Browsers**: current and current-1 of Chrome, Firefox, Safari, Edge.
370
383
  - **TypeScript**: >= 5.4 (for strict `satisfies` and `const` type parameters).
371
- - **Output**: PPTX files validated against ECMA-376 schemas, smoke-tested
372
- against PowerPoint (current), Keynote (current), Google Slides, and
373
- LibreOffice Impress.
384
+ - **Output**: PPTX files checked against the ECMA-376 schemas with `xmllint`
385
+ where it is available, and smoke-tested against PowerPoint (current),
386
+ Keynote (current), Google Slides, and LibreOffice Impress.
374
387
 
375
388
  ## Development
376
389