返回 ppt-master
pptx-animations.md
根目录 / skills / ppt-master / scripts / docs / pptx-animations.md
1 # PPTX Animation Core
2
3 The shared animation core owns the object-effect vocabulary, trigger
4 semantics, OOXML timing writer, semantic read-back, and package validation for
5 PowerPoint OOXML. Per-element animation remains opt-in: generated PPTX export
6 defaults to `none`, exactly as before this validation upgrade.
7
8 ## 1. Ownership
9
10 | Concern | Owner |
11 |---|---|
12 | Effect registry, timing writer, and read-back | `scripts/pptx_animations.py` |
13 | Sidecar parsing and SVG target discovery | `svg_to_pptx/animation_config.py` |
14 | SVG group-to-shape mapping | `svg_to_pptx/drawingml/converter.py` |
15 | Generated PPTX resolution and validation | `svg_to_pptx/pptx_package/builder.py` |
16 | Narration timing merge | `svg_to_pptx/pptx_package/narration.py` |
17 | Public authoring contract | `references/animations.md` |
18 | Customization stage | `workflows/stages/customize-animations.md` |
19
20 **Hard rule**: only the generated SVG-to-PPTX route writes object
21 animations. Direct-PPTX routes preserve source animations and run structural
22 package validation; they do not resolve or author animation effects.
23
24 ---
25
26 ## 2. Domain Model
27
28 `groups.<id>` accepts either one backward-compatible effect object or one
29 non-empty `effects[]` array; the forms are exclusive and every array row names
30 `effect`. Both expand into the same row model, so repeated shape targets are
31 valid. Legacy rows also accept `trigger`; omitted row settings inherit the
32 resolved slide animation.
33
34 One resolved row contains these fields:
35
36 | Field | Meaning |
37 |---|---|
38 | Target | Positive PowerPoint shape id written to `p:spTgt@spid` |
39 | Effect | One canonical PowerPoint-authored preset class / id / subtype / behavior-tree signature |
40 | Trigger | Row-specific `on-click`, `with-previous`, or `after-previous`; omitted values inherit the resolved slide Start mode |
41 | Trigger shape | Optional different top-level group; maps to PowerPoint `On Click of` |
42 | Duration | Finite positive schedule duration; scalable native behavior trees preserve their internal timing ratios |
43 | Delay | Finite non-negative row offset; shape-trigger rows use it as `TriggerDelayTime` |
44 | Order | Positive integer sidecar order; ties retain stable SVG group order, then `effects[]` index |
45 | Effect options | Effect-specific `direction`, `amount`, `color`, `font_name` (one installed PowerPoint face, required for Change Font; not a CSS list), `relative`, or `size` values from PowerPoint `EffectParameters` |
46 | Timing options | Repeat count/span, auto-reverse, rewind, accelerate/decelerate, bounce-end ratio, and restart policy |
47 | Completion / cue | Optional dim/hide behavior and packaged `.m4a`/`.mp3`/`.wav` sound |
48
49 Modes resolve before XML writing:
50
51 | Mode | Resolution |
52 |---|---|
53 | `auto` | Generic entrance only: deterministic semantic mapping from the SVG group id |
54 | `mixed` | Generic entrance only: deterministic cycle over canonical PowerPoint entrance presets |
55 | `random` | Generic entrance only: stable seeded choice from the same canonical entrance pool |
56 | `none` | No object-animation sequence |
57
58 The same effective input produces the same `random` choices. When enabled,
59 `--conversion-trace` records each resolved row and effect, so a generated deck
60 can be audited without replaying the resolver.
61
62 `animation_config.py scaffold` is neutral: object defaults are `none`, and
63 empty `{}` group placeholders inherit no motion until populated.
64
65 Bundled sound discovery/materialization is a workflow concern, not part of the
66 animation core. After the SVG and object-motion solution are complete,
67 `sound_sync.py` may copy only selected namespaced ids into
68 `<project>/sounds/`; new sidecars then reference those project-relative WAV
69 paths. Existing low-level project-relative/absolute `.m4a`, `.mp3`, and `.wav`
70 inputs remain compatible. The core never resolves a library id or reads
71 `templates/sounds/` directly; see [`animations.md`](../../references/animations.md)
72 §2.2.
73
74 ---
75
76 ## 3. Canonical Registry and Compatibility Inputs
77
78 The canonical registry contains 203 PowerPoint-authored presets:
79
80 | Category | Key prefix | Count | Example |
81 |---|---|---:|---|
82 | Entrance | `entrance_*` | 53 | `entrance_bounce` |
83 | Emphasis | `emphasis_*` | 33 | `emphasis_spin` |
84 | Motion path | `path_*` | 64 | `path_circle` |
85 | Exit | `exit_*` | 53 | `exit_faded_zoom` |
86
87 The 29 established short names remain valid only as compatibility inputs.
88 Normalization resolves them to canonical PowerPoint-authored presets before
89 selection, XML writing, read-back, tracing, or validation.
90
91 | Compatibility input | Canonical preset |
92 |---|---|
93 | `appear`, `cut` | `entrance_appear` |
94 | `fade` | `entrance_fade` |
95 | `fly`, `fly_left`, `fly_right`, `fly_top` | `entrance_fly` |
96 | `zoom` | `entrance_zoom` |
97 | `wipe`, `wipe_left`, `wipe_right`, `wipe_up`, `wipe_down` | `entrance_wipe` |
98 | `split`, `blinds`, `checkerboard`, `dissolve`, `random_bars`, `peek` | matching `entrance_*` preset |
99 | `wheel`, `box`, `circle`, `diamond`, `plus`, `strips`, `wedge`, `stretch`, `expand`, `swivel` | matching `entrance_*` preset |
100
101 `cut` maps to `entrance_appear` because current PowerPoint exposes no separate
102 Cut object-animation preset. Old Fly/Wipe names desugar to the canonical effect
103 plus `effect_options.direction`; legacy `wheel` desugars to
104 `entrance_wheel` plus `amount: 4`. New output never writes those aliases.
105
106 Together with the 29 accepted compatibility names, the public input surface
107 contains 232 keys. New selections, generated sidecars, conversion traces,
108 writers, and documentation examples use canonical keys; short names exist only
109 at compatibility input boundaries.
110
111 The shipped `pptx_animation_presets.json` contains the PowerPoint-authored
112 `p:cTn` row for every native effect. Complex effects use combinations of
113 `p:set`, `p:anim`, `p:animClr`, `p:animEffect`, `p:animMotion`, `p:animRot`,
114 and `p:animScale`; reducing them to one filter would silently change the
115 effect. `pptx_animations.py --list` prints the full categorized public
116 registry; `pptx_animations.py --describe <effect>` prints that effect's exact
117 option values and shared timing/completion contract.
118
119 Native presets map to the object-capable `MsoAnimEffect` values. Media play,
120 pause, stop, and play-from-bookmark are excluded because they require a
121 media/bookmark target rather than an SVG-derived shape. Exit effects use the
122 same entrance-capable `MsoAnimEffect` identity with PowerPoint's exit flag and
123 serialize as `presetClass="exit"`.
124
125 Paragraph/text-range build controls are likewise outside this writer: generated
126 targets are top-level SVG groups, not paragraph ranges. For that target model,
127 the public contract covers all PowerPoint effect parameters, timing modifiers,
128 completion controls, sound, and object-trigger linkage; Speed and smooth
129 start/end remain derived rather than duplicated.
130
131 **Hard rule — no downgrade**:
132
133 - Keep all 29 established short names accepted as compatibility inputs.
134 - Reject an unknown effect, mode, or trigger; never substitute another value.
135 - Reject booleans and non-finite, out-of-range, or invalidly ordered values.
136 - Reject a missing slide, missing group, or structural-layer target.
137 - Keep the generated-route default at `none`; validation does not opt a deck in.
138
139 ---
140
141 ## 4. Target Resolution
142
143 Generated object animation targets top-level SVG content groups. Explicit SVG
144 semantics are authoritative; the group-id chrome heuristic applies only to a
145 top-level group that itself lacks `data-pptx-layer`, `data-pptx-role`, and
146 `data-pptx-placeholder` semantics.
147
148 | Target state | Behavior |
149 |---|---|
150 | Ordinary content group | Animatable; a legacy block resolves one row and `effects[]` may resolve several rows against the same final shape |
151 | Legacy chrome-like id | Skipped unless explicitly named in `animations.json` |
152 | Explicit sidecar group override | May override only the legacy chrome-name heuristic |
153 | `data-pptx-layer` or explicit static role/placeholder | Structural and never animatable |
154
155 An explicit sidecar entry cannot turn a Master/Layout/Slide structural layer or
156 an explicitly marked static page-frame role/placeholder into an animation
157 target. This boundary preserves PPTX structure even when a legacy id resembles
158 content.
159
160 ---
161
162 ## 5. OOXML Rules
163
164 The writer emits animation timing after `p:transition` and before `p:extLst`.
165 Normally this is one root `p:timing`; nonzero `bounce_end` uses PowerPoint's
166 native `mc:AlternateContent` with a p14 Choice and non-bounce Fallback. Each
167 branch contains a `tmRoot`, a `mainSeq` when ordinary Start rows exist, one
168 `interactiveSeq` per trigger-shape row, unique branch-local `p:cTn@id` values,
169 and same-slide `p:spTgt` references.
170
171 Trigger mapping:
172
173 | Public trigger | Object row `p:cTn@nodeType` |
174 |---|---|
175 | `on-click` | `clickEffect` |
176 | `with-previous` | `withEffect` |
177 | `after-previous` | `afterEffect` |
178
179 A row-level `trigger_shape` resolves to a different shape id and writes
180 PowerPoint's native `interactiveSeq` with `onClick` shape conditions. Its row
181 remains `clickEffect`; row `delay` becomes `TriggerDelayTime`. Ordinary rows
182 remain in `mainSeq` and keep the slide Start mode.
183
184 Row `trigger` overrides slide Start in both forms. `trigger_shape` implies
185 `on-click` and conflicts with an explicit non-`on-click` Start. Repeated
186 `p:spTgt@spid` values are valid distinct Animation Pane rows. Ordinary rows
187 retain page-wide `order`; trigger-shape rows retain their relative order in
188 separate `interactiveSeq` branches and do not interleave with `mainSeq`.
189
190 The writer does not emit `p:bldP` for grouped content or pictures. Microsoft
191 defines `p:bldP@spid` for a text-bearing `p:sp`; using it for `p:grpSp` or
192 `p:pic` creates an invalid build reference. Package validation still accepts a
193 valid source `p:bldP` that targets a text-bearing shape.
194
195 Direct-PPTX preserve mode also tolerates an unchanged legacy `p:bldP` that
196 targets an existing group/picture. Earlier PPT Master exports wrote this form;
197 the direct routes fingerprint and preserve it instead of blocking those decks.
198 New generated output never writes it, and generated-package validation remains
199 strict.
200
201 `entrance_appear` is the visibility-flip exception: its `p:set` behavior is
202 always 1ms. The configured positive duration remains the row's scheduling span
203 used when computing the next `after-previous` offset; read-back verifies the
204 1ms behavior and the resulting timeline offset separately. The compatibility
205 inputs `appear` and `cut` normalize to this canonical preset.
206
207 Other native presets with a
208 finite duration scale every finite behavior duration and start delay
209 proportionally, preserving multi-step timing such as bounce and teeter.
210 PowerPoint-authored instantaneous emphasis presets keep their `indefinite`
211 behavior duration; their configured duration remains the scheduling span for
212 the next `after-previous` row.
213
214 ---
215
216 ## 6. Validation and Read-Back
217
218 Before export, `animation_config.py validate` uses the writer's effect-behavior
219 test for `bounce_end` and resolves declared sound paths against the project
220 root. Missing paths, non-files, and unsupported audio extensions fail this
221 project-level preflight; field-only validation remains filesystem-independent.
222
223 Generated export reads every slide back before packaging and compares each
224 requested row with the serialized result:
225
226 - row count and row order, including stable repeated-target rows;
227 - trigger, optional trigger shape, and shape target;
228 - resolved effect key, preset class, filter, `presetID`, and `presetSubtype`;
229 - exact effect options, repeat/reverse/rewind/acceleration/bounce/restart
230 semantics, completion behavior, sound relationship, and playback span;
231 - native behavior-tree signature, serialized behavior duration, and computed
232 timeline offset (`entrance_appear` and instantaneous native presets use the
233 exceptions above).
234
235 After packaging, validation scans every slide part for root timing placement,
236 duplicate or malformed `p:cTn` ids, missing `p:spTgt` shapes, invalid build
237 targets, and unsupported generated effect tuples. A mismatch fails export
238 before the requested output file replaces an existing deck.
239
240 `pptx_to_svg.py` reuses that semantic reader and behavior-tree validator for a
241 finite reverse projection. A row enters `animations.json` only when its current
242 registry effect/options, pane order, Start trigger, exact behavior duration,
243 relative delay, and target/optional trigger shape can be represented by unique
244 top-level slide SVG groups. Repeated targets become `effects[]`. Duration-less
245 native rows, advanced timing modifiers, sounds, build/media commands, unknown
246 trees, and unmapped targets remain explicit import diagnostics. This is not a
247 general PowerPoint timing-tree normalizer.
248
249 Narration injection parses and merges the slide DOM. It adds audio timing under
250 the existing `tmRoot`, allocates fresh ids, and preserves object animation.
251 For bounce timing it updates both p14 Choice and Fallback; unsupported nested
252 timing containers still fail safely instead of being duplicated.
253
254 Direct-PPTX routes run the structural package validator with generated-effect
255 enforcement disabled. This permits preservation of source/extension effects and
256 legacy group build rows while still rejecting corrupt timing IDs or missing
257 targets. Template fill and native enhancement fingerprint the source
258 object-animation tree before and after their allowed edits; any semantic change
259 fails. These routes have no object-animation write ownership.
260
261 The conversion trace is also the authoritative input for downstream video
262 motion. `video_motion_plan.py` preserves the resolved effect/options, direction,
263 row order, base and repeat-aware playback duration, absolute offset, object
264 bounds, and narration-derived slide advance while adding only renderer-specific enhancement parameters. Video
265 renderers must not bypass this read-back result and infer motion from sidecar
266 delay values alone.
267
268 ---
269
270 ## 7. Compatibility Scope
271
272 The compatibility contract covers PowerPoint OOXML and PowerPoint read-back.
273 Other presentation applications may interpret timing trees or filter values
274 differently; the exporter does not make an unconditional Keynote guarantee.
275
276 Official references:
277
278 - [Microsoft `MsoAnimEffect` enumeration](https://learn.microsoft.com/en-us/office/vba/api/powerpoint.msoanimeffect)
279 - [Microsoft `Sequence.AddEffect`](https://learn.microsoft.com/en-us/office/vba/api/powerpoint.sequence.addeffect)
280 - [Microsoft `Effect.Exit`](https://learn.microsoft.com/en-us/office/vba/api/powerpoint.effect.exit)
281 - [Microsoft animation-filter implementation notes](https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oe376/a96dab70-2e72-4319-928d-0eb4b275ce58)
282 - [Microsoft `p:bldP` implementation restrictions](https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oe376/40d17b6d-30c0-4c10-b042-b2597824a820)
283 - [Open XML SDK time-node values](https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.presentation.timenodevalues?view=openxml-3.0.1)
284 - [Open XML SDK shape target](https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.presentation.shapetarget?view=openxml-3.0.1)
285
286 See [`pptx-transitions.md`](./pptx-transitions.md) for the symmetric page-motion
287 core, MCE handling, and slide-advance contract.
288 See [`video-motion-plan.md`](./video-motion-plan.md) for the downstream
289 animation-to-video contract.
290
290 lines MARKDOWN