返回 ppt-master
animations.md
根目录 / skills / ppt-master / references / animations.md
1 # Page Transitions & Per-Element Animations
2
3 Execution contract for generated-PPTX **page transitions** and **per-element
4 object animations**, including deterministic Morph object pairing. This file
5 owns defaults, sidecar semantics, anchor selection, validation, and package
6 read-back.
7
8 ## Capability Menu — Open Here
9
10 Motion here is several separate capabilities, not one dial. Two of them are
11 decided **upstream, while pages are still being authored** — read this menu
12 before the page plan is frozen, not only when a deck is already exported.
13
14 | What the deck needs | Reach for | Decided at |
15 |---|---|---|
16 | A generic deck-wide entrance build | `-a auto`; with the default `after-previous` Start mode, groups use fixed `--animation-stagger` timing rather than narration cues | Post-processing; §2, §4 |
17 | Explicit object lifecycle choreography | An `animations.json` sidecar for selected enter/emphasize/move/exit/static duties, order, Start mode, and timing | Post-processing; §2, §4, [`customize-animations`](../workflows/stages/customize-animations.md) |
18 | Object reveals semantically synchronized to recorded narration | Narration-cue sync derives `narration_animations.json` from canonical `animations.json`, page-local SRT, and `narration_timing.json`; `-a auto` alone does not provide this mapping | Audio stage; [`generate-audio`](../workflows/stages/generate-audio.md) |
19 | A continuous action — slide-in, flip, camera push-in, progressive reveal, camera pan | **Morph: author the action as two static pages, then select Morph and add explicit pairs when identity must be deterministic.** There is no keyframe timeline anywhere in this pipeline; the difference between two ordinary editable slides *is* the animation | **Page authoring (Step 6), then motion post-processing** — §2.1, §3.1 |
20 | A static full-bleed page that should stop looking frozen | Consider slow `path_*` motion on a visually subordinate image or atmospheric layer; §4.1 gives one starting recipe | Post-processing; §4.1 |
21 | Carousel, counting numerals, parallax depth, click-to-reveal flip card | Four recurring recipes assembled from the mechanisms above | §4.2 — the carousel and odometer both need paired pages |
22 | Kiosk or unattended playback | `--auto-advance <seconds>`, optionally with `-t none` | Export; §3 |
23 | A transition or object animation needs an audible cue | Optional `transition.sound` or object-animation `sound`; select it only after the visual motion solution is complete, then sync the chosen global-library ids into the project. For direct narrated MP4 delivery, [`generate-audio`](../workflows/stages/generate-audio.md) selects either the verified native-export mix or explicit real-time slideshow capture; never combine them | Post-motion; §2.2 |
24 | Nothing should move | `-t none`, and leave per-element animation at its default `none` | Export; §1 |
25
26 **Hard rule — Morph geometry is an authoring decision; pairing is a later
27 execution decision**: export cannot invent the two visible endpoint states.
28 Author both consecutive pages while `svg_output/` is still being built. For
29 deterministic identity, expose each endpoint as a compatible direct-root group
30 and declare the pair in `animations.json` (§2.1); the source and destination ids
31 and geometry may differ. `-t morph` without explicit pairs leaves matching to
32 PowerPoint's heuristic and is not proof that the intended objects will tween.
33
34 **Reference — not a constraint**: per-element animation stays off by default
35 (§1). Auto-firing element builds on every page are an unsolicited "AI deck"
36 tell; each capability above earns its place per page, not per deck.
37
38 ---
39
40 ## 1. Defaults
41
42 | Layer | Default | Why |
43 |---|---|---|
44 | Page transition | CLI: `fade`, 0.4s | Calm baseline that suits most decks; the public Python builder retains its legacy 0.5s default |
45 | Per-element animation | **`none` (off)** | A page appears as a whole. Auto-firing element builds are an unsolicited "AI deck" tell, so object animation is opt-in. Turn on the content-aware canonical entrance policy with `-a auto`, or select one PowerPoint-native `entrance_*`, `emphasis_*`, `path_*`, or `exit_*` key explicitly |
46 | Sound effects | **`none` (off)** | No global sound is copied and no `<project>/sounds/` directory is created unless a resolved transition or object-animation cue actually selects one |
47
48 To regenerate a deck with different settings, rerun the final checker when its current matching report is absent or stale, then rerun `svg_to_pptx.py` against the same `svg_output/`; the content-generation LLM need not rerun unless authored SVG requires repair. `-s final` is reserved for diagnostic comparison and is not a supported release source. To turn per-element animation on for the whole deck, pass `-a auto`.
49
50 ---
51
52 ## 2. Custom Object-Level Animation
53
54 Per-element animation is off by default. To enable generic entrance reveals
55 deck-wide, pass `-a auto` at export (no config needed). When a deck instead
56 needs a specific object lifecycle—for example enter, move, emphasize, then
57 exit—use the optional `animations.json` sidecar. The SVG remains the visual
58 source; the custom stage may rewrite its grouping hierarchy, ids, and bounds to
59 create better semantic anchors without changing visible output, while the
60 sidecar controls PPTX animation behavior.
61
62 Run the [`customize-animations`](../workflows/stages/customize-animations.md)
63 post-processing stage when the project already carries `animations.json`, when
64 the user explicitly asks to tune animation order/effects/timing/object-level
65 reveals, or when the effective Custom Animations outcome in
66 `design_spec.md §I` is enabled. A §IX `Motion suggestion` remains Strategist
67 advice and informs an active pass, but never triggers the stage alone.
68
69 **Hard rule — semantic anchors before object-targeted sidecar entries**: when
70 object animation is in scope, derive motion units and their lifecycle duties
71 from page meaning and narration, then regroup coarse/fragmented Slide-local
72 content without changing its appearance. Only post-regroup top-level ids are
73 valid object targets.
74
75 ```bash
76 # Inspect the real anchors after the semantic regrouping pass
77 python3 skills/ppt-master/scripts/animation_config.py list-groups <project>
78
79 # Build a neutral editable scaffold from the post-regroup anchors when useful
80 python3 skills/ppt-master/scripts/animation_config.py scaffold <project>
81
82 # Validate references before export
83 python3 skills/ppt-master/scripts/animation_config.py validate <project>
84
85 # Export reads <project>/animations.json automatically when present
86 python3 skills/ppt-master/scripts/svg_to_pptx.py <project>
87 ```
88
89 The scaffold keeps `defaults.animation.effect: none` and may list untouched
90 groups as empty `{}` placeholders; creating it does not opt the deck into
91 object motion. Populate only adopted motion units.
92
93 Sparse sidecar excerpt (unlisted slides inherit resolved defaults):
94
95 ```json
96 {
97 "version": 1,
98 "slides": {
99 "03_threshold": {
100 "groups": {
101 "risk-marker": {
102 "effects": [
103 { "effect": "entrance_fade", "order": 1, "duration": 0.25 },
104 { "effect": "path_right", "effect_options": { "relative": true }, "order": 2, "duration": 0.7 },
105 { "effect": "emphasis_teeter", "order": 3, "duration": 0.45 },
106 { "effect": "exit_fade", "order": 4, "duration": 0.3 }
107 ]
108 }
109 }
110 }
111 }
112 }
113 ```
114
115 Rules:
116
117 - `slides` keys match SVG stems (`03_market.svg` → `03_market`).
118 - `groups` keys match top-level `<g id="...">` anchors.
119 - A populated group block chooses exactly one representation: the
120 backward-compatible single-effect object, or
121 `{ "effects": [row, ...] }`. `effects` is non-empty and mutually exclusive
122 with every legacy single-effect field; each row explicitly names `effect`.
123 An untouched scaffold `{}` remains a neutral placeholder.
124 - `effect: none` in the legacy form removes that group from the object-animation
125 sequence and is useful for overriding inherited generic animation.
126 - `effects[]` permits the same PowerPoint shape to carry several Animation Pane
127 rows. `order` sorts ordinary rows across the slide; ties retain SVG group
128 order and then array order. `trigger_shape` rows keep that relative ordering
129 in separate interactive sequences rather than interleaving with the main
130 sequence. Ordering never changes slide layering.
131 - `delay` is seconds added to that row's resolved Start.
132 - `trigger` may be set per legacy row or `effects[]` row; otherwise it inherits
133 the resolved slide Start mode.
134 - `trigger_shape` is a row-specific reference to another unique, triggerable
135 top-level group. It maps to PowerPoint **Trigger → On Click of**, makes only
136 that row interactive, and uses `delay` as `TriggerDelayTime`. It implies
137 `on-click`; an explicit row `trigger` may accompany it only when also
138 `on-click`.
139 - `duration` overrides the per-row schedule duration. `entrance_appear`
140 remains a 1ms visibility flip, and instantaneous native emphasis presets
141 retain their PowerPoint-authored duration; the configured value still spaces
142 the next `after-previous` row.
143 - `effect_options` requires an explicit canonical `effect` in the same legacy
144 block or `effects[]` row and accepts only parameters PowerPoint exposes for
145 that effect:
146
147 | Option | Applies to |
148 |---|---|
149 | `direction` | Directional Fly/Crawl/Wipe/Peek/Strips/Split/Stretch/Zoom and related entrance/exit effects |
150 | `amount` | Wheel spokes (`1`, `2`, `3`, `4`, `8`), emphasis Spin degrees, or Transparency ratio |
151 | `color` | Color-capable emphasis effects; `#RRGGBB` or `theme:<scheme-color>` |
152 | `font_name` | Change Font; required for `emphasis_change_font`; one installed PowerPoint face, not a CSS list |
153 | `size` | Grow/Shrink |
154 | `relative` | Motion paths (`true` = shape-relative, `false` = fixed slide path) |
155 - Any animation block or effect row may set `repeat_count` or `repeat_duration`
156 (mutually exclusive), `auto_reverse`, `rewind`, `accelerate`, `decelerate`,
157 `bounce_end`, `restart`, `after_effect`, and `sound`. Ratios are `0..1`;
158 `bounce_end` requires an interpolated behavior and cannot combine with
159 `decelerate`; `restart` is `always`, `when-not-active`, or `never`;
160 `after_effect` is `none`, `dim` (with `color`), `hide`, or
161 `hide-on-next-click`; `sound` is a project-relative or absolute `.m4a`,
162 `.mp3`, or `.wav` path. New generated configurations use a project-relative
163 path. A bundled library choice first follows §2.2 and resolves to a
164 project-local `.wav`; never point new output at `templates/sounds/`.
165 - `Speed` and smooth start/end are not duplicate sidecar fields: they are
166 derived from `duration` and `accelerate`/`decelerate`.
167 - This is the complete parameter surface for the generated top-level-group
168 target model, including multiple ordered effects on one group. PowerPoint
169 paragraph/text-range build fields are intentionally absent because grouped
170 SVG content is not emitted as paragraph builds; media play/pause/stop
171 commands remain in the audio/video workflows.
172 - Run `python3 skills/ppt-master/scripts/pptx_animations.py --describe
173 <canonical_effect>` for that effect's exact option values and full parameter
174 contract.
175 - `--animation none` overrides the sidecar and disables all per-element animation.
176 - An explicit sidecar group may override the legacy chrome-name heuristic, but it cannot override `data-pptx-layer` or an explicit static role/placeholder marker.
177 - Unknown effects, modes, or triggers and invalid numeric/order fields fail validation; no fallback effect is substituted.
178
179 **Inheritance**: the sidecar and its `defaults` block are optional. Unlisted
180 slides and omitted slide fields inherit `defaults.transition` /
181 `defaults.animation`, then CLI/exporter resolution. Explicit CLI flags override
182 the corresponding sidecar default/slide fields; explicit group overrides remain
183 unless `-a none` hard-disables all object motion. Groups inherit the resolved
184 slide duration, Start mode, timing modifiers, after-effect, and sound into each
185 legacy or `effects[]` row. `effect_options` remains coupled to an explicit
186 effect; `trigger_shape` is never inherited; omitted `order`/`delay` use
187 exporter defaults.
188
189 ### 2.1 Deterministic Morph Object Pairing
190
191 When one semantic object continues across two adjacent slides, the destination
192 slide may declare explicit forced-Morph pairs. This is separate from `groups`:
193 Morph owns cross-slide identity, while `groups` owns Animation Pane rows.
194 The generated names follow Microsoft's
195 [forced object-matching convention](https://support.microsoft.com/en-us/powerpoint/morph-transition-tips-and-tricks).
196
197 ```json
198 {
199 "version": 1,
200 "slides": {
201 "02_detail": {
202 "transition": {
203 "effect": "morph",
204 "effect_options": { "morph_by": "object" },
205 "duration": 0.8
206 },
207 "morph": {
208 "from": "01_overview",
209 "pairs": {
210 "hero-image": {
211 "from": "hero-overview",
212 "to": "hero-detail"
213 }
214 }
215 }
216 }
217 }
218 }
219 ```
220
221 - `morph` belongs to the destination slide. `morph.from` must be the
222 immediately preceding SVG stem in export order.
223 - `animation_config.py scaffold` never guesses cross-slide identity. Add pairs
224 from the semantic motion plan after inspecting the final direct-root ids.
225 - Each `pairs` key is a stable identity; its `from` and `to` values are unique
226 direct-root `<g id>` values on the source and destination slides. Supply the
227 key without `!!`; export writes the PowerPoint Selection Pane name
228 `!!<key>` on both objects.
229 - A destination with explicit pairs must explicitly set `effect: morph`.
230 `morph_by` may be omitted for its `object` default or set to `object`;
231 `word`/`character` are rejected. A CLI transition override that changes the
232 resolved effect fails export.
233 - A middle slide may continue the same object into another Morph transition,
234 but the same group must retain the same key. One key cannot name two objects
235 on one slide, and one object cannot carry two keys. Every `!!` key shared by
236 two adjacent Morph pages must be declared in that destination's `pairs`;
237 undeclared forced matches are rejected.
238 - Explicit pairing can coexist with in-slide object animation and remains
239 active when `-a none` disables Animation Pane rows. `--no-animations`
240 disables the sidecar and all page/object motion.
241 - The exporter resolves both group ids to final Slide-local PowerPoint shapes,
242 writes names only after Master/Layout processing, then reopens the package
243 and verifies adjacency, Morph by object, one name per slide, and matching
244 OOXML object types. Missing, structural, moved, ambiguous, or mismatched
245 targets fail instead of falling back to automatic Morph matching.
246
247 ### 2.2 On-Demand Sound Selection
248
249 **Hard rule — select after motion, materialize after selection**: sound is not a
250 Strategist resource and does not belong in `design_spec.md`, `spec_lock.md`, or
251 pre-SVG resource preparation. First complete the SVG roster and resolve the
252 transition/object-motion solution. Only when a specific cue is then selected,
253 copy its global-library file into the project and reference that local copy.
254
255 | Source | Action |
256 |---|---|
257 | Bundled CC0 library | Read the complete objective [`sound-vocabulary.md`](../templates/sounds/sound-vocabulary.md), select one exact id from the resolved auditory job, sync only that selection, then use the corresponding `sounds/<namespace>/<file>.wav` path |
258 | User-provided audio already inside the project | Reference its existing project-relative `.m4a`, `.mp3`, or `.wav` path for object animation; a transition sound uses `.wav` |
259 | External absolute file | The low-level object-animation path remains compatible, but new generated projects should copy or sync the intended file into the project and use a relative path |
260 | No concrete auditory cue job | Keep `sound` omitted; do not create `<project>/sounds/` and do not copy the library |
261
262 ```bash
263 # Optional exact filtering only after the complete vocabulary is in context
264 python3 skills/ppt-master/scripts/sound_sync.py list --query <term>
265
266 # Materialize only the chosen ids
267 python3 skills/ppt-master/scripts/sound_sync.py \
268 <project_path> <namespace>/<sound_id> [<namespace>/<sound_id> ...]
269 ```
270
271 `sound_sync.py` is the only bundled-library materialization path. Stable ids
272 include their namespace; copied files remain under
273 `<project_path>/sounds/<namespace>/`. The exporter never reads the global
274 `templates/sounds/` library directly, and sidecars store paths rather than
275 library ids.
276
277 **Default — silence (may override for a specific cue)**: do not add sound to
278 demonstrate capability or spread it across a deck for coverage. A sound may
279 support a named transition, reveal, confirmation, warning, or drawn/moving
280 gesture after the corresponding visual behavior is already selected.
281
282 **Hard rule — PPTX and MP4 are separate sound deliveries**: sound fields and
283 package read-back prove the editable PPTX contains the intended native cue;
284 they do not prove PowerPoint's video encoder placed it in the MP4 audio track.
285 For direct narrated MP4 delivery with resolved cues, follow `generate-audio`
286 and choose exactly one branch: mix from the final narrated trace plus final
287 PPTX after native encoding, or explicitly capture the live PowerPoint Slide
288 Show with system audio. Never mix the capture again. Keep post-production gain
289 and limiter settings out of `animations.json`.
290
291 ---
292
293 ## 3. Page Transitions
294
295 **Reference — not a constraint**: choose a transition from the relationship
296 between adjacent pages, not from gallery coverage. Run this playbook before
297 selecting a canonical key:
298
299 | Pass | Decision |
300 |---|---|
301 | Relate | Decide whether the destination continues the same object or space, advances in a meaningful direction, opens a new section, or intentionally breaks continuity. |
302 | Diagnose | Name the transition's job: neutral continuity, immediate cut, directional progress, object/state continuity, spatial movement, or a deliberate thematic beat. |
303 | Select | Use the smallest family that performs that job; keep `fade` when no stronger relationship exists. |
304 | Coordinate | Align direction, duration, and recurrence with reading order, narration, and the deck's established motion language. |
305 | Stop | Keep `fade` or `none` when another effect adds no meaning; never vary transitions for catalog coverage. |
306
307 | Page relationship | Candidate family |
308 |---|---|
309 | Ordinary continuation within one section | `fade` |
310 | Immediate change with no continuity to preserve | `none` or `cut` |
311 | Directional steps, timeline, or layer progression | `push` / `wipe`; use `cover` / `uncover` when an overlay relationship is visible |
312 | The same semantic object or scene changes across adjacent pages | `morph`; use §2.1 pairs when identity must be deterministic |
313 | Section opening, key reveal, or marked state boundary | Selective `split` / `reveal` / `shape` / `flash` / `random_bars` |
314 | A repeated collection advances through one spatial frame | `pan` / `conveyor` / `ferris_wheel`; use the §4.2 Morph carousel when individual cards need deterministic identity |
315 | The viewpoint travels around or through a continuous space | `rotate` / `window` / `orbit` / `fly_through` |
316 | The narrative or theme supports a stage, paper, or physical-page metaphor | Selective `fall_over` / `drape` / `curtains` / `wind` / `prestige` / `peel_off` / `page_curl` / `airplane` / `origami` / `doors` |
317 | A disruptive beat represents breakage, collapse, or dispersal | Selective `fracture` / `crush` / `dissolve` / `vortex` / `shred` |
318 | A marked reveal benefits from a geometric, timed, or textured pattern | Selective `checkerboard` / `blinds` / `clock` / `ripple` / `honeycomb` / `glitter` / `comb` |
319 | A card, panel, gallery, or viewpoint visibly turns or changes face | Selective `switch` / `flip` / `gallery` / `cube` / `box` / `zoom` |
320 | Unpredictability is itself the requested behavior | `random`; never use it merely to create variety |
321
322 ```bash
323 # Pick a different effect
324 python3 skills/ppt-master/scripts/svg_to_pptx.py <project> -t push --transition-duration 0.6
325
326 # Remove the visual transition
327 python3 skills/ppt-master/scripts/svg_to_pptx.py <project> -t none
328
329 # Auto-advance every 5 seconds (kiosk-style playback)
330 python3 skills/ppt-master/scripts/svg_to_pptx.py <project> --auto-advance 5
331
332 # Auto-advance with no visual transition
333 python3 skills/ppt-master/scripts/svg_to_pptx.py <project> -t none --auto-advance 5
334 ```
335
336 The native registry covers PowerPoint's complete Subtle, Exciting, and Dynamic
337 Content gallery: 48 canonical keys. New selection, sidecars, plans, conversion
338 traces, and writers use only those keys. Run `pptx_animations.py --list` for
339 the categorized identifiers.
340
341 Eight old low-level names remain accepted only as compatibility inputs. They
342 desugar to a native key plus native `effect_options`: for example, `diamond`
343 becomes `shape` with `shape: diamond`, and `wedge` becomes `clock` with
344 `style: wedge`. They are never selected for new output.
345
346 Effects expose their real PowerPoint Effect Options through
347 `transition.effect_options`. Common examples include Push/Wipe direction,
348 Morph by object/word/character, Reveal through black, Shape geometry, Page
349 Curl direction/pages, Glitter pattern/direction, and Fly Through bounce. Run
350 `pptx_animations.py --describe-transition <effect>` for the exact
351 effect-specific contract; unknown or inapplicable options fail validation.
352 `none` removes the visual effect. Effects that require newer Office namespaces
353 carry a real PowerPoint effect in `mc:Choice` and a `fade` fallback for older
354 consumers; validation requires the requested primary effect and never accepts
355 the fallback as a silent substitute.
356
357 An optional `transition.sound` adds one `.wav` cue to the transition. It is a
358 sidecar field rather than a CLI flag. Bundled choices must first be synced by
359 §2.2 and referenced through their project-relative path. `effect: none` may
360 still carry a transition sound and/or automatic advance without restoring a
361 visual effect. A slide-level `transition.sound: null` explicitly clears an
362 inherited default transition sound for that page.
363
364 Flags:
365
366 - `-t/--transition` — native effect name, compatibility input, or `none` for no visual transition. Default: `fade`. `none` does not remove an explicitly configured automatic advance.
367 - `--transition-duration` — seconds, default `0.4`.
368 - `--auto-advance` — seconds; click remains enabled, so the slide advances on click or when the timer expires. Omit for presenter-controlled advance.
369
370 **Hard rule — no silent downgrade**: an unknown transition effect, unsupported Effect Option, or invalid/non-finite duration fails export. It is never replaced by `fade`. Recorded narration keeps the resolved visual transition; `-t none --recorded-narration ...` writes narration-driven advance timing without restoring a visual effect.
371
372 ### 3.1 Morph — author an action as the difference between two pages
373
374 Morph tweens objects it can match across consecutive slides. That makes it a general mechanism, not just a transition: **any continuous action can be authored as two static pages plus a Morph transition**, with no keyframe timeline anywhere. Duplicate the page, change one property on one object, and PowerPoint interpolates the rest. Use §2.1 explicit pairs when the match must be deterministic.
375
376 | Change between the two pages | Reads as |
377 |---|---|
378 | Object sits off-canvas, then on-canvas | Slide-in, drawer pull, card extending |
379 | Object rotates | Flip, turn, hinge |
380 | Image container scales up | Camera push-in |
381 | Scrim opacity drops, or a cut contour grows | Progressive reveal |
382 | Same wide image at two `x` offsets | Camera pan (see image-layout-patterns `#C2-01`) |
383
384 Chain three or more pages to build a sequence — extend, hold, retract — where each page is still an ordinary editable slide.
385
386 **Hard rule — matching needs compatible object identity, not identical SVG
387 geometry**: for generated decks, prefer §2.1 deterministic pairs. The source
388 and destination direct-root group ids may differ, and position, size, crop, or
389 other visible state is expected to change; both endpoints must still resolve to
390 one compatible top-level PowerPoint object kind. Automatic Morph without pairs
391 is heuristic and may cross-fade instead of tweening.
392
393 **Give text somewhere to come from.** Morph tweens objects present on both pages; text that only exists on the second page can only fade in. The standard fix is to place the *next* page's copy on the current page just outside the canvas (below), and the *previous* page's copy just outside the opposite edge (above). Each block then slides through the frame instead of blinking, and the deck reads as one continuous surface being scrolled. A wholly off-canvas endpoint must be one direct-root `<g id>` with valid `data-pptx-bounds` and `data-pptx-morph-staging="true"`; when Morph remains enabled, pair it explicitly under §2.1. The marker only declares an intentional invisible endpoint; it cannot excuse a partially clipped group or text carrier.
394
395 **When Morph refuses to match**: PowerPoint pairs compatible object kinds; a
396 shape and a picture will cross-fade instead of tweening. For generated pages,
397 declare the identity through the destination slide's `morph` block (§2.1).
398 The exporter writes the shared `!!<key>` name after structure processing and
399 reads the package back. Do not author `data-pptx-shape-name` for this purpose;
400 that attribute remains importer metadata for mirror/preserve packages
401 ([`svg-effects.md`](./svg-effects.md) §6.6).
402
403 **Not supported — Slide Zoom / Summary Zoom.** Click-to-jump navigation built on PowerPoint's Zoom objects (the "click a portrait, zoom into that section" pattern) has no exporter path. Build click-driven navigation with `trigger_shape` on ordinary object animations instead, or with plain hyperlinks.
404
405 **No 3D**: perspective rotation, extrusion, and shear are outside the SVG contract — `skewX` / `skewY` and shear matrices fail closed ([`svg-effects.md`](./svg-effects.md) §6.8). Build the same impression with 2D means — offset, scale, overlap, and per-facet lightness — rather than attempting a 3D tilt.
406
407 ---
408
409 ## 4. Per-Element Animations
410
411 Off by default — enable deck-wide with `-a auto` (or another effect). Once enabled, three Start modes are available — these mirror PowerPoint's animation-pane "Start" dropdown:
412
413 - **`on-click`** — each click reveals the next group. Use only for a controlled semantic reveal; live delivery alone is insufficient. Forbidden with `--recorded-narration`.
414 - **`with-previous`** — groups start together as one coordinated beat. Stagger ignored.
415 - **`after-previous`** (default) — click-free cascade on slide entry with `--animation-stagger` spacing. Use when controlled reveals are unnecessary.
416
417 **Default — coherent Start rhythm (may override when a semantic beat needs
418 different control)**: Keep one dominant deck rhythm and normally one mode per
419 slide. Mix only for a distinct simultaneous or presenter-controlled beat.
420
421 Enable with `-a auto`, select a canonical effect with
422 `--animation entrance_fade`, and choose Start behavior with
423 `--animation-trigger on-click|with-previous|after-previous`.
424
425 PowerPoint's separate **Trigger → On Click of** behavior uses row-specific
426 `trigger_shape`. It links that row to another top-level group while unlinked
427 rows keep the slide Start mode; it is not a fourth deck-wide Start mode.
428
429 **Mandatory — lifecycle before effect selection**: start from `static`, then
430 classify semantic `initial → action → end` before choosing an effect. Generic
431 staged reveals normally use `enter`; narrower communication jobs select their
432 matching lifecycle instead.
433
434 | Duty | State contract | Use when | Effect family |
435 |---|---|---|---|
436 | `static` | present → hold as reference → present | Motion adds no clarity or intended feeling | No row; legacy `effect: none` only suppresses inheritance |
437 | `enter` | absent → introduce → present | Information should be withheld, ordered, or revealed with narration | `entrance_*`; modes only for generic reveal |
438 | `emphasize` | present → redirect attention → present/altered | An already visible object must regain attention or show a local change; never substitute for its first reveal | Explicit `emphasis_*` |
439 | `move` | state/position A → progress → state/position B | The trajectory carries spatial or causal meaning, or §4.1 adopts subordinate ambient motion; use Morph for cross-page continuity | Explicit `path_*`, or endpoint pages + Morph |
440 | `exit` | present → retire → absent | The same slide must remove, replace, or make room for content; an ordinary page change needs no object exit | Explicit `exit_*` |
441
442 **Default — restrained entrance-led choreography (may override for content,
443 tone, or the request)**: Use entrances for ordinary builds. Add emphasis or
444 exit sparingly, only for a real duty and fitting effect. Multiple `effects[]`
445 rows require multiple duties.
446
447 The registry exposes two layers:
448
449 - **203 PowerPoint-native object presets**: 53 `entrance_*` presets, 33
450 `emphasis_*` effects, 64 `path_*` motion paths, and 53 `exit_*` effects.
451 Examples include `entrance_bounce`, `emphasis_spin`, `path_circle`, and
452 `exit_faded_zoom`. Each native key carries the complete PowerPoint-authored
453 behavior tree, not a generic filter approximation.
454 - **29 legacy compatibility inputs**, listed by `--list`; new output never
455 selects them.
456
457 Run the registry command for the exact categorized key list:
458
459 ```bash
460 python3 skills/ppt-master/scripts/pptx_animations.py --list
461 ```
462
463 Compatibility names normalize before selection and writing: for example,
464 `fade` resolves to `entrance_fade`; every old Fly direction name resolves to
465 `entrance_fly`; every old Wipe direction name resolves to `entrance_wipe`; and
466 `cut` resolves to `entrance_appear` because current PowerPoint has no separate
467 Cut object effect. Directional aliases preserve their old direction through
468 `effect_options`; legacy `wheel` maps to `entrance_wheel` with four spokes.
469 These names are accepted only as compatibility inputs.
470 Automatic selection, new sidecars, conversion traces, and writers use
471 canonical keys.
472
473 The native keys mirror the object-capable `MsoAnimEffect` surface. The four
474 media commands—play, pause, stop, and play from bookmark—are not object effects
475 for SVG groups and remain owned by the audio/video workflows.
476
477 - `auto` handles generic `enter` duties only and maps semantic ids to canonical entrances: charts/tables/timelines use
478 `entrance_wipe`; cards/steps use `entrance_fly`; titles/takeaways use
479 `entrance_fade`; image-like ids cycle a richer pool; unmatched ids cycle
480 fade/wipe/fly/zoom.
481 - `mixed` (legacy mode name) handles generic `enter` duties only and is
482 deterministic. The first animated group on each
483 slide uses `entrance_fade`; later groups cycle through a 16-effect canonical
484 PowerPoint entrance pool across the deck. The mode name remains compatible;
485 it no longer selects hand-authored compatibility rows.
486 - `random` handles generic `enter` duties only and samples from the same
487 canonical PowerPoint entrance pool.
488 Resolution is seeded from the effective deck input, so the same input
489 produces the same choices; `--conversion-trace` records every resolved effect
490 when diagnostics are enabled.
491
492 `entrance_appear` is excluded from every variation pool because it has no
493 visible motion. `auto`, `mixed`, and `random` never satisfy an adopted
494 `emphasize`, `move`, or `exit` duty; those require explicit canonical effects.
495
496 Flags: `-a/--animation` selects effect/mode; `--animation-trigger` selects Start;
497 `--animation-duration` and `--animation-stagger` control base timing;
498 `--animation-config` selects a sidecar; `--no-animations` disables page/object
499 motion but preserves narration audio and recorded advance timing.
500
501 > Note: `--recorded-narration` rejects `on-click` and `trigger_shape`. Narration-cue sync uses `narration_animations.json` and blocks when only canonical `animations.json` exists. Narration-independent custom motion explicitly passes `--animation-config animations.json`, even when a derived sidecar also exists. With no sidecar, pass `--inherit-motion-from <base_postflight_report>`; explicit all-motion-off uses `--no-animations`.
502
503 ### 4.1 Slow ambient motion — the page that breathes
504
505 **Reference — not a constraint**: ambient motion can keep a static page from
506 feeling frozen when it remains visually subordinate to the message. A common
507 starting recipe is `path_left` or `path_right` on a background image, started
508 `with-previous` and paced much more slowly than a content reveal. The same
509 principle may suit another atmospheric or non-information-bearing layer. Choose
510 duration, distance, and moving-object count from the composition and delivery
511 context.
512
513 Keep a full-bleed moving image covering the canvas at both endpoints; exposing
514 the slide beneath it is a visible failure.
515
516 It pairs naturally with a fixed foreground: with image-layout-patterns `#M1-07`, the scrim and its cut contour stay locked while the world moves behind the cuts, which reads as looking through windows rather than as a sliding photo. The same logic applies to `#M1-10` and `#P1-09`.
517
518 Motion remains subordinate: avoid competing ambient paths or movement that
519 reduces the readability of body copy or data. Multiple coordinated layers are
520 valid when they express one intentional depth or atmosphere relationship.
521
522 ### 4.2 Recurring recipes
523
524 Four combinations that recur constantly in authored decks. Each is built from
525 mechanisms already defined above — none needs a new capability.
526
527 **Carousel** (Morph, §2.1 and §3.1) — hold a fixed row of card frames and rotate the *content* through them: on each page every image advances one position, so the card at centre changes while the frames stay put. Explicitly pair each moving content unit across adjacent pages; the fixed frames stay static and need no pair. Scales to any number of images with one page each.
528
529 **Odometer / counting numerals** (morph or motion path) — build a vertical strip of digits 0–9 and show one through a fixed window formed by background-filled rectangles above and below ([`image-layout-patterns.md`](./image-layout-patterns.md) `#M1-08`). Shift the strip so the target digit lands in the window, then either morph between two pages or run a `path_up` motion on the strip. A small stagger, such as `0.1s`, can make digit columns settle in sequence; synchronized motion is also valid when it fits the intended rhythm.
530
531 **Parallax depth** (morph) — move a background layer a *short* distance and a foreground layer a longer one between two pages. The differing travel is read as depth. Keep both layers' z-order identical on both pages; a layer that changes stacking between pages breaks the tween and the transition jumps.
532
533 **Flip-card / click-to-reveal** (`trigger_shape`, §4) — pair a face group and a back group at the same position, give the face an exit and the back an entrance, and set the back's `trigger_shape` to the face's id. Clicking the face plays both. This is the supported route for click-driven interaction; PowerPoint's Zoom objects are not (§3.1).
534
535 ---
536
537 ## 5. Anchor Logic — Top-Level `<g id="...">`
538
539 Per-element animations are anchored on **top-level `<g id="...">` content
540 groups** in the SVG (e.g. `<g id="cover-title">`, `<g id="card-1">`). IDs must
541 be unique within the page. A backward-compatible single-effect group produces
542 one Animation Pane row; `effects[]` may produce several ordered rows targeting
543 the same PowerPoint shape. Each row inherits the slide Start mode unless it
544 declares its own `trigger`. Nested implementation groups may remain anonymous
545 because the sidecar does not target them.
546
547 **Hard rule — existing groups are not custom-animation intent**: the
548 pre-existing SVG hierarchy is implementation evidence, not an authoritative
549 motion plan. During the custom-animation stage, derive one group per logical
550 motion unit from claims, comparisons, sequence, causality, and narration beats;
551 split coarse wrappers and merge fragmented atoms when needed, then use
552 `list-groups` only after that rewrite. This is also the granularity PowerPoint
553 uses for group-select / group-move. Do not split or merge units to hit a target
554 count.
555
556 **Chrome stays static.** `data-pptx-layer` and explicit static
557 role/placeholder markers are absolute. The legacy chrome-like ID heuristic
558 (background, header/footer, decor, watermark, page number, nav, logo, rule)
559 applies only to a top-level group that itself lacks `data-pptx-layer`,
560 `data-pptx-role`, and `data-pptx-placeholder` semantics; an explicit sidecar
561 entry may override only this name heuristic. Keep wrappers and use
562 `effect: none` for static content.
563
564 **Fallback for flat SVGs** (no top-level `<g>` wrappers, only raw `<rect>` / `<text>` / `<path>` at the root):
565
566 - ≤ 8 visible top-level primitives → each becomes one anchor (capped to avoid 70+ atom cascades on dense pages).
567 - > 8 → animation is skipped on that slide. The slide still renders, just without object animation.
568
569 Executors should wrap logical sections in `<g id>` regardless of whether you plan to animate. [`shared-standards-core.md`](./shared-standards-core.md) requires it.
570
571 ---
572
573 ## 6. Validation and Read-Back
574
575 Animation configuration is strict. Export fails on an unknown effect, mode, or
576 trigger; invalid timing/order values; a missing slide/group/`trigger_shape`
577 reference; a self-trigger; or any attempt to animate or trigger from a
578 structural layer. These errors never downgrade or silently omit a target.
579
580 Generated export reads each slide's timing tree back and checks row count/order,
581 including repeated rows on one shape, trigger, trigger shape, shape target,
582 preset class, resolved effect tuple, native behavior signature, duration, and
583 timeline offset. Package validation then checks root
584 timing placement, unique and valid `p:cTn` ids, and every `p:spTgt` reference.
585 Deterministic Morph additionally checks the final adjacent slide parts for the
586 requested `!!` names, one-to-one uniqueness, compatible object types, and a
587 real Morph-by-object transition on the destination.
588 The writer does not emit `p:bldP` for groups or pictures. Direct-PPTX preserve
589 mode tolerates unchanged legacy group/picture `p:bldP` rows from earlier PPT
590 Master exports; new generated packages remain strict.
591
592 Narration injection preserves animation and updates both p14 Choice/Fallback
593 when bounce timing is present; unsupported nested timing fails safely.
594 Direct-PPTX routes fingerprint source
595 object-animation timing before and after their allowed edits, then run
596 structural package validation; they do not author or normalize animation
597 effects.
598
599 `pptx_to_svg.py` uses the same generated-transition read-back validator to
600 project supported source `p:transition` into canonical `animations.json` rows.
601 It retains the registry effect, effective options, exact duration, automatic
602 advance, and supported WAV sound; the sidecar defaults to `none` so absent
603 source transitions remain absent on re-export. Unknown or inexact native
604 carriers stay diagnosed/direct-preserve. This is a closed PPT Master-owned
605 contract, not an arbitrary OOXML transition normalizer.
606
607 For source `p:timing`, the importer accepts only current generated behavior
608 trees whose registry effect/options, pane order, Start trigger, exact duration,
609 relative delay, and target/optional trigger shape map to unique top-level slide
610 SVG groups. It emits one group row or `effects[]` in the same sidecar. Rows
611 without a native duration, advanced timing modifiers, sounds, builds/media
612 commands, unknown behavior trees, and unmapped targets remain diagnosed/direct-
613 preserve; no timing value is inferred.
614
615 **Validation boundary**: these checks prove PPTX timing, relationships, and
616 embedded sound parts. They are not final-video audio acceptance. The
617 native-export branch requires a triggered `video_sound_mix.py` receipt; the
618 slideshow-capture branch requires the human picture/audio/all-cue acceptance
619 owned by `generate-audio` and never claims that receipt.
620
621 ---
622
623 ## 7. Video Adaptation Contract
624
625 Video renderers consume the resolved conversion trace through
626 `video_motion_plan.py`, never a raw sidecar or delay-only inference. The plan
627 locks identity, order, effect, direction, and timing; video may refine only its
628 declared renderer parameters. Unsupported families fail visibly. See
629 [`video-motion-plan.md`](../scripts/docs/video-motion-plan.md).
630
631 On the native-export mix branch, direct narrated video sound uses the final
632 resolved trace for cue order and offsets, the final PPTX relationships for the
633 exact embedded audio bytes, and page-level narration correlation for the
634 exported-video clock. It never reads sound timing from a raw sidecar or
635 filename. The explicit slideshow-capture branch records PowerPoint's real-time
636 playback instead and does not consume the trace for sound mixing.
637
638 ---
639
640 ## 8. Limitations
641
642 - Generated animation belongs to the native PPTX built from `svg_output/`.
643 `svg_final/` is a static preview, and inserting it as one SVG picture does
644 not create object anchors.
645 - PowerPoint OOXML is the compatibility target; other presentation apps may
646 reinterpret individual native behavior trees.
647 - PowerPoint's native MP4 encoder may omit transition and object-animation
648 sounds even when the PPTX package is valid. Direct sound-enabled MP4 delivery
649 therefore uses either the post-export mix or the explicit real-time
650 slideshow-capture contract owned by `generate-audio`; the branches never
651 stack.
652 - Direct-PPTX routes preserve unknown transition `AlternateContent`; timing
653 edits keep Choice and Fallback advance attributes synchronized.
654
655 ---
656
657 ## 9. Implementation References
658
659 See [`pptx_transitions.py`](../scripts/pptx_transitions.py),
660 [`svg-pipeline.md`](../scripts/docs/svg-pipeline.md),
661 [`pptx-transitions.md`](../scripts/docs/pptx-transitions.md),
662 [`pptx-animations.md`](../scripts/docs/pptx-animations.md), and
663 [`video-motion-plan.md`](../scripts/docs/video-motion-plan.md).
664
664 lines MARKDOWN