| 1 | --- |
| 2 | description: Optional post-processing stage for per-slide and per-object animation overrides. |
| 3 | --- |
| 4 | |
| 5 | # Customize Animations Stage |
| 6 | |
| 7 | > Optional Generate-PPTX post-processing stage for per-slide or per-object |
| 8 | > animation control. Run when `<project_path>/animations.json` already exists, |
| 9 | > when the user explicitly asks to customize slide-specific motion, object |
| 10 | > order, effects, timing, or reveals, or when the effective Custom Animations |
| 11 | > outcome in `design_spec.md §I` is enabled. Deck-wide transitions, |
| 12 | > auto-advance, and deck-wide per-element settings without page-specific motion |
| 13 | > or an existing sidecar use [`animations.md`](../../references/animations.md) |
| 14 | > directly and do not activate this stage. In Quick Generate, the current agent |
| 15 | > may activate either path from the request/deck in active context without a |
| 16 | > Design Spec or user interaction. |
| 17 | |
| 18 | ## When to Run |
| 19 | |
| 20 | | Condition | Action | |
| 21 | |---|---| |
| 22 | | Effective Custom Animations outcome in `design_spec.md §I` is enabled | Run this stage after the final SVG quality gate and any enabled speaker-note pass, before Generate Step 7; use §IX suggestions as advice | |
| 23 | | User asks for per-slide or per-object animation, reveal order, timing, or effect changes | Run this stage | |
| 24 | | `<project_path>/animations.json` already exists | Run this stage to resolve preserve/adjust/replace/suppress intent before export | |
| 25 | | §IX contains `Motion suggestion`, but no trigger above is active | Do not run; retain the suggestion as Strategist advice and keep normal export defaults | |
| 26 | | No motion request, enabled outcome, or existing sidecar; user only wants the default deck | Do not run; normal export keeps page transitions and no element builds | |
| 27 | | No existing sidecar; user only wants deck-wide page transitions, auto-advance, or one per-element object animation policy | Do not run; apply [`animations.md`](../../references/animations.md) with exporter flags such as `-a auto` or `-a emphasis_spin` | |
| 28 | | `svg_output/*.svg` is missing | Complete the main Executor phase first | |
| 29 | |
| 30 | **Decision precedence**: latest explicit instruction → final Stage-2 policy → |
| 31 | workflow default `false`; provenance stays in Design Spec §I, never the |
| 32 | lock. Final Stage-2 `false` blocks creation, not an existing sidecar. Existing |
| 33 | sidecars enter this stage; explicit disables follow the table without deletion. |
| 34 | |
| 35 | --- |
| 36 | |
| 37 | ## 1. Resolve Intent and Read Semantic Context |
| 38 | |
| 39 | **Context read**: before editing `animations.json`, read every semantic planning file below that exists. |
| 40 | |
| 41 | | File | Use | |
| 42 | |---|---| |
| 43 | | `<project_path>/design_spec.md` | Understand each slide's content intent, narrative role, and visual emphasis | |
| 44 | | `<project_path>/spec_lock.md` | Confirm page rhythm, layout role, chart/template constraints, and execution contract | |
| 45 | | `<project_path>/notes/total.md` or `<project_path>/notes/*.md` | Use speaker flow to tune reveal order, delays, and emphasis | |
| 46 | |
| 47 | **Existing sidecar intent gate**: |
| 48 | |
| 49 | | User intent | Action | |
| 50 | |---|---| |
| 51 | | Explicit Custom Animations disable | Preserve and validate the sidecar; return `-a none` | |
| 52 | | Explicit all-motion disable | Preserve and bypass the sidecar; return `--no-animations` | |
| 53 | | Explicit regeneration / rewrite / replacement | Rebuild the semantic grouping plan and replace `animations.json`; the previous choreography is not a constraint | |
| 54 | | Explicit adjustment / tuning / repair | Validate first, preserve the existing choreography where its semantic units remain valid, and migrate affected group references after any required regrouping | |
| 55 | | Stage activated with an existing sidecar and new §IX suggestions but no user replacement request | Validate first; preserve valid existing choreography and adjust only the affected semantic units | |
| 56 | | Existing sidecar with no new motion instruction | Validate and preserve it unchanged; if invalid, repair the owning sidecar/group reference before export | |
| 57 | | Ambiguous generation request | Default Generate asks whether to regenerate or modify; Quick Generate decides from the request, visible SVG, and existing sidecar, then continues | |
| 58 | |
| 59 | Unless explicit all-motion disable bypasses it, validate an existing sidecar |
| 60 | before deciding to preserve, modify, or suppress object motion: |
| 61 | |
| 62 | ```bash |
| 63 | python3 skills/ppt-master/scripts/animation_config.py validate <project_path> |
| 64 | ``` |
| 65 | |
| 66 | **Hard rule**: semantic files determine both animation intent and animation |
| 67 | unit boundaries. The current `svg_output/*.svg` supplies visible content and |
| 68 | implementation structure, but its existing `<g>` hierarchy is not accepted as |
| 69 | the animation plan merely because it already exists. |
| 70 | |
| 71 | **Optional-context fallback**: these semantic files inform this supporting stage but are not its gate artifacts. If any are absent, state what is missing and proceed with every remaining file plus visible SVG content. If all three context inputs are absent, use only explicit user instructions, visible SVG content, and the resolution rules in [`animations.md`](../../references/animations.md); do not infer detailed choreography beyond what the page itself expresses. |
| 72 | |
| 73 | **Decision ownership — understand, then design**: A §IX `Motion suggestion` |
| 74 | expresses the Strategist's communication job and semantic relationship; it |
| 75 | neither activates this stage nor locks implementation. Once active, understand |
| 76 | that intent, then develop the motion brief from the final SVG's semantic units, |
| 77 | visible states, composition, and speaker flow. Do not mechanically map it to |
| 78 | groups, effects, order, or timing. Executor may preserve, adapt, simplify, |
| 79 | decline, or choose `none`; an unchanged realization is valid and requires no |
| 80 | novelty. Explicit user motion requirements bind. Never change page |
| 81 | content merely to justify animation. |
| 82 | |
| 83 | **Hard rule — existing visible-layer boundary**: This stage may regroup existing content only under §2 visual equivalence; it MUST NOT create or modify a crop, comparison layer, scrim, lens, hotspot, annotation, or other visible image state to satisfy motion intent. When a required state is missing and ordinary Slide-local authoring can supply it, return to Generate Step 6, rerun the final SVG gate and regenerate notes only when speaker notes are enabled, then resume here. If a structural boundary prevents that repair, simplify a non-binding suggestion to legal existing units, a page transition, or `none`; an explicit requirement follows failure recovery instead of changing structure. |
| 84 | |
| 85 | **No-op is complete**: Evaluate suggestions before regrouping SVG content. If |
| 86 | no `animations.json` exists, every page should retain the normal `fade` |
| 87 | transition and no object builds, and no explicit user requirement remains |
| 88 | unmet, change no SVG, create no sidecar, and return to Generate Step 7. Never |
| 89 | author motion merely to expose a capability. |
| 90 | |
| 91 | --- |
| 92 | |
| 93 | ## 2. Rebuild Semantic Motion Units When Needed, Then List IDs |
| 94 | |
| 95 | **Mandatory when object-targeted motion is in scope — content-first grouping |
| 96 | audit**: inspect each affected slide's visible content against its communication |
| 97 | job and speaker flow before treating any top-level `<g>` as an animation |
| 98 | anchor. The affected set is the page named by an adopted suggestion or explicit |
| 99 | object-motion request, plus both endpoints of each deterministic Morph pair. |
| 100 | Untouched pages need no animation audit. Existing groups are implementation |
| 101 | evidence only. Keep a current group unchanged only after confirming that it |
| 102 | already represents exactly one audience-facing motion unit or one continuing |
| 103 | Morph object. A page-transition-only plan without explicit Morph pairs skips |
| 104 | regrouping and group listing. |
| 105 | |
| 106 | | Content condition | Required grouping action | |
| 107 | |---|---| |
| 108 | | One current group contains several independently narrated rows, cards, steps, claims, or stages | Split it into descriptive direct-root sibling groups, one per motion unit | |
| 109 | | One motion unit is scattered across groups or root primitives | Merge or wrap its background, icon, label, value, and supporting text into one direct-root group | |
| 110 | | A connector or arrow explains entry into a node or stage | Keep it with the relationship or target unit that makes the connection intelligible | |
| 111 | | A hero visual, overview graphic, takeaway, or warning has its own communication role | Give it its own semantic group | |
| 112 | | The same semantic object continues across adjacent Morph pages | Isolate each endpoint as one direct-root group and keep both endpoints as compatible object kinds | |
| 113 | | Several atoms express one inseparable idea | Keep them together; do not animate the atoms separately | |
| 114 | | Page chrome, structural layers, or static framing | Preserve their structure and exclude them from ordinary animation targets | |
| 115 | |
| 116 | **Hard rule — visual equivalence**: regrouping changes object boundaries only. |
| 117 | Preserve all visible content, paint order, coordinates, transforms, inherited |
| 118 | paint, opacity, clipping, filters, references, and native metadata. Keep |
| 119 | rendering-bearing implementation wrappers nested inside the new semantic group |
| 120 | when flattening or distributing their attributes could change appearance. |
| 121 | |
| 122 | **Hard rule — structural boundary**: never split or merge across |
| 123 | `data-pptx-layer`, `data-pptx-placeholder`, native chart/table carrier, native |
| 124 | preset, or imported logical-object boundaries. Structural/static objects remain |
| 125 | non-animatable. Ordinary Slide-local content groups follow |
| 126 | [`shared-standards-core.md`](../../references/shared-standards-core.md) §4.3: |
| 127 | every visible direct-root group has a descriptive unique `id` and positive |
| 128 | root-coordinate `data-pptx-bounds`; nested implementation groups carry no |
| 129 | bounds. |
| 130 | |
| 131 | **Forbidden — group-list-first choreography**: |
| 132 | |
| 133 | - Choosing effects or order from the pre-existing `list-groups` output before the content-first audit |
| 134 | - Keeping a coarse wrapper only because it already has an `id` |
| 135 | - Splitting one semantic idea into individual shapes or text lines to increase animation count |
| 136 | - Merging unrelated ideas to reduce animation count |
| 137 | - Adding animation-specific `data-*` attributes to SVG |
| 138 | |
| 139 | There is no target group count. Granularity follows the page's actual claims, |
| 140 | comparisons, sequence, causality, and narration beats. |
| 141 | |
| 142 | After any regrouping, rerun the final SVG quality gate because `svg_output/` |
| 143 | changed. Use the owning route's checker form; Quick Generate must add its |
| 144 | lockless profile flag: |
| 145 | |
| 146 | ```bash |
| 147 | python3 skills/ppt-master/scripts/svg_quality_checker.py <project_path> --stage final --json |
| 148 | # Quick Generate: insert --quick-generate before --stage. |
| 149 | ``` |
| 150 | |
| 151 | Then list the **post-regroup** anchors: |
| 152 | |
| 153 | ```bash |
| 154 | python3 skills/ppt-master/scripts/animation_config.py list-groups <project_path> |
| 155 | ``` |
| 156 | |
| 157 | Output is one line per slide: `<slide_basename>: id1, id2, id3`. Default chrome |
| 158 | groups (`bg` / `*-header` / `*-footer` / `*-decor` / `nav` / `watermark` / |
| 159 | `logo` / `pagenumber`) are excluded. This post-regroup list is the source of |
| 160 | truth when planning §3 and editing §4; never invent a slide or group key. |
| 161 | |
| 162 | An explicit sidecar entry may override only the marker-free legacy id-name |
| 163 | heuristic. A group carrying `data-pptx-layer` or an explicit static |
| 164 | role/placeholder marker can never animate, even when it is named explicitly. |
| 165 | |
| 166 | If `animations.json` does not exist and a starting file is useful, scaffold |
| 167 | only after semantic regrouping: |
| 168 | |
| 169 | ```bash |
| 170 | python3 skills/ppt-master/scripts/animation_config.py scaffold <project_path> |
| 171 | ``` |
| 172 | |
| 173 | The scaffold is neutral: its default object effect is `none`, and listed groups |
| 174 | may remain empty `{}` placeholders until adopted. Creating it does not select |
| 175 | generic entrance animation. Do not read the full scaffold unless it is needed |
| 176 | as an editing starting point. |
| 177 | |
| 178 | --- |
| 179 | |
| 180 | ## 3. Plan Slide and Object Motion |
| 181 | |
| 182 | **Mandatory**: plan the requested motion layers for each affected slide before |
| 183 | editing `animations.json`. A local object-animation request does not require a |
| 184 | deck-wide transition review. |
| 185 | |
| 186 | | Layer | Config path | Use | |
| 187 | |---|---|---| |
| 188 | | Page transition | `defaults.transition` or `slides.<slide>.transition` | Control how one slide enters from the previous slide | |
| 189 | | Deterministic Morph pair | `slides.<destination>.morph` | Bind one real source group to one real destination group when semantic identity continues across adjacent slides | |
| 190 | | Page animation defaults | `defaults.animation` or `slides.<slide>.animation` | Control the default object-animation behavior for animated groups on a slide | |
| 191 | | Object lifecycle | `slides.<slide>.groups.<group_id>` | Assign one legacy effect row or an ordered `effects[]` sequence to a real SVG motion unit | |
| 192 | |
| 193 | **Per-affected-page motion brief**: classify the communication job—including |
| 194 | none—and each unit's lifecycle. Choose only the required transition, effect, |
| 195 | order, timing, and one dominant Start rhythm; mix modes or add emphasis and |
| 196 | exit only for a distinct job with a restrained, fitting effect. Read |
| 197 | `design_spec.md`, `spec_lock.md`, speaker notes, and SVG group ids for role, |
| 198 | rhythm, order, and target validity. |
| 199 | |
| 200 | **Mandatory — select from meaning, not catalog coverage**: run the |
| 201 | page-relationship and lifecycle selection playbooks in |
| 202 | [`animations.md`](../../references/animations.md) §3 and §4 before choosing any |
| 203 | specific effect. Their candidates are recall aids, not coverage targets; this |
| 204 | stage binds the selected duties to real targets. |
| 205 | |
| 206 | **Title motion decision**: when a title participates, classify its lifecycle, |
| 207 | then choose immediate, delayed, synchronized, post-hero, or narration-cued |
| 208 | timing from slide intent. Use the sidecar override for a marker-free legacy |
| 209 | chrome-like id; repair an incorrect explicit structural/static marker before |
| 210 | animating it. |
| 211 | |
| 212 | **Default — inherit unaffected motion layers (may override when the page's |
| 213 | communication job requires it)**: a custom object-animation pass may leave the |
| 214 | page transition and every untouched page on exporter or sidecar defaults. Add a |
| 215 | slide-specific `transition` only when the affected page needs one; never add |
| 216 | variation for coverage. |
| 217 | |
| 218 | **Timing guidance**: use shorter motion for dense/repeated scan content and |
| 219 | longer motion for conceptual pivots, hero diagrams, section boundaries, and |
| 220 | final takeaways. Uniform timing is valid when it fits the requested style. |
| 221 | |
| 222 | **Reference — not a constraint: motion judgment.** Decide the communication |
| 223 | job, lifecycle, tone, audience order, and whether direction carries meaning |
| 224 | before using geometry. If motion adds no clarity or intended feeling, classify |
| 225 | the unit `static`; use `none`, `entrance_appear`, or `entrance_fade` only when |
| 226 | that result matches the lifecycle. Layout direction alone does not require |
| 227 | special motion; variation follows a real content/tone change, never a quota. |
| 228 | |
| 229 | ### 3.1 Supported Page Transitions |
| 230 | |
| 231 | Use one of the 48 canonical native effects from the complete shared registry in |
| 232 | [`animations.md`](../../references/animations.md) §3. It covers all current |
| 233 | PowerPoint Subtle, Exciting, and Dynamic Content gallery effects. The eight old |
| 234 | names are readable only as compatibility inputs; do not write them in new |
| 235 | plans or sidecars. They normalize to a canonical effect plus native |
| 236 | `effect_options` before writing. `none` removes the visual page transition |
| 237 | while allowing timed advance to remain. |
| 238 | |
| 239 | **Transition fields**: |
| 240 | |
| 241 | | Field | Behavior | |
| 242 | |---|---| |
| 243 | | `effect` | One supported page transition effect; `none` removes only the visual effect | |
| 244 | | `effect_options` | Optional object containing only the selected native effect's PowerPoint Effect Options; requires an explicit `effect` | |
| 245 | | `duration` | Finite transition duration in seconds; must be greater than zero | |
| 246 | | `auto_advance` | Optional finite non-negative seconds before automatic slide advance; click remains enabled, and this field is valid with `effect: none` | |
| 247 | |
| 248 | Run |
| 249 | `python3 skills/ppt-master/scripts/pptx_animations.py --describe-transition <effect>` |
| 250 | before authoring Effect Options. Never infer that one effect accepts another |
| 251 | effect's direction, shape, pattern, or boolean fields. |
| 252 | |
| 253 | For a cross-slide object continuation that must not depend on PowerPoint's |
| 254 | automatic matching, put one explicit `morph` block on the destination slide. |
| 255 | Its `from` slide must be the immediately preceding exported SVG; each stable |
| 256 | pair key binds one source direct-root group id to one destination direct-root |
| 257 | group id. The exporter supplies PowerPoint's `!!` prefix. Use Morph by object; |
| 258 | word/character Morph does not accept this object-pair contract. |
| 259 | |
| 260 | ### 3.2 Supported In-Slide Animations |
| 261 | |
| 262 | Use the 203 canonical PowerPoint-native keys: 53 `entrance_*`, 33 |
| 263 | `emphasis_*`, 64 `path_*`, and 53 `exit_*`. Run |
| 264 | `python3 skills/ppt-master/scripts/pptx_animations.py --list` for the exact |
| 265 | categorized names. Each key preserves PowerPoint's complete authored behavior |
| 266 | tree. Media-only commands remain in the audio/video workflows. |
| 267 | |
| 268 | | Choice | Behavior | |
| 269 | |---|---| |
| 270 | | `entrance_*` / `emphasis_*` / `path_*` / `exit_*` | Select one explicit canonical PowerPoint object effect | |
| 271 | | `auto` | Generic `enter` only: map content roles to canonical entrances; image-like ids use a richer canonical pool | |
| 272 | | `mixed` | Generic `enter` only: cycle 16 canonical entrance presets by group order | |
| 273 | | `random` | Generic `enter` only: select deterministically from the same canonical entrance pool | |
| 274 | | `none` | Exclude the object or slide from in-slide animation | |
| 275 | |
| 276 | The 29 old short names remain readable only as compatibility inputs; do not use |
| 277 | them in new plans or sidecars. All Fly direction names normalize to |
| 278 | `entrance_fly`, all Wipe direction names normalize to `entrance_wipe`, and the |
| 279 | other old names normalize to their matching `entrance_*` preset. `cut` |
| 280 | normalizes to `entrance_appear`. Compatibility Fly/Wipe aliases preserve their |
| 281 | direction as `effect_options.direction`; legacy `wheel` preserves its historical |
| 282 | four-spoke amount. |
| 283 | |
| 284 | `auto`, `mixed`, and `random` never choose emphasis, motion-path, or exit |
| 285 | effects implicitly. Use them only after classifying a unit as a generic |
| 286 | `enter`; select an explicit canonical key for every adopted `emphasize`, |
| 287 | `move`, or `exit` duty. |
| 288 | |
| 289 | **Hard rule — explicit semantic choreography**: When an adopted plan depends |
| 290 | on a specific lifecycle, relationship, or order, target its real groups with |
| 291 | explicit canonical effects and order; do not delegate those material decisions |
| 292 | to `auto`, `mixed`, or `random`. Those modes remain valid only when generic |
| 293 | entrance treatment is sufficient. |
| 294 | |
| 295 | **Start modes**: |
| 296 | |
| 297 | | Trigger | Behavior | |
| 298 | |---|---| |
| 299 | | `after-previous` | Default click-free cascade | |
| 300 | | `with-previous` | One coordinated beat together | |
| 301 | | `on-click` | Controlled semantic reveal | |
| 302 | |
| 303 | --- |
| 304 | |
| 305 | ## 4. Edit `animations.json` |
| 306 | |
| 307 | **Hard rule — sparse overrides reference real targets**: write only affected |
| 308 | slides and only fields that differ from exporter or sidecar defaults. An |
| 309 | unlisted SVG inherits the resolved deck-wide settings; a listed slide may |
| 310 | contain only `transition`, `animation`, `groups`, or `morph` fields that it |
| 311 | actually overrides. `defaults` is optional and belongs only to intentional |
| 312 | deck-wide settings. Group-level overrides remain opt-in. Chrome groups stay out |
| 313 | (the exporter pins them to `none` by default). Name a legacy chrome-like id only |
| 314 | when the user explicitly wants that content animated and the SVG has no |
| 315 | explicit structural layer, role, or placeholder marker. |
| 316 | |
| 317 | **Forbidden**: |
| 318 | |
| 319 | - Referencing a slide that does not exist in `svg_output/` |
| 320 | - Referencing a missing, ambiguous, or structural group |
| 321 | - Enumerating every content group in a slide just to restate the slide-level default effect |
| 322 | - Listing a group with `data-pptx-layer` or an explicit static role/placeholder marker |
| 323 | - Listing a legacy chrome-like id without an explicit, reviewed intent to override the name heuristic |
| 324 | |
| 325 | | Field | Behavior | |
| 326 | |---|---| |
| 327 | | `transition.effect` | Slide-specific page transition effect | |
| 328 | | `transition.effect_options` | Effect-specific native PowerPoint options; requires an explicit slide-specific `transition.effect` | |
| 329 | | `transition.duration` | Slide-specific page transition duration | |
| 330 | | `morph.from` | Immediately preceding SVG stem for an explicit deterministic Morph transition | |
| 331 | | `morph.pairs.<key>.from` / `.to` | Unique source/destination direct-root group ids that receive the shared PowerPoint name `!!<key>` | |
| 332 | | `animation.effect` | Slide-specific default object animation effect | |
| 333 | | `animation.duration` | Slide-specific default object schedule duration | |
| 334 | | `animation.stagger` | Slide-specific delay between object animation rows | |
| 335 | | `animation.trigger` | Slide-specific start mode | |
| 336 | | `groups.<id>.effects` | Non-empty ordered array for a multi-duty lifecycle; every row explicitly names `effect`, and `effects` cannot coexist with legacy single-effect fields in the same group block | |
| 337 | | `groups.<id>.effect` | Backward-compatible single-row form: one canonical native effect, `auto`, `mixed`, `random`, or `none`; old names are read-only compatibility inputs | |
| 338 | | `effects[].trigger` / legacy `trigger` | Row-specific Start mode; omitted values inherit `animation.trigger` | |
| 339 | | `order` | Page-wide order for ordinary rows; ties retain SVG group order and then `effects[]` index. `trigger_shape` rows keep relative order in separate interactive sequences; SVG layer order never changes | |
| 340 | | `delay` | Row-specific seconds added to the resolved Start or shape trigger | |
| 341 | | `duration` | Per-row schedule duration in seconds; scalable native behavior trees keep their internal timing ratios, while `entrance_appear` and instantaneous native presets retain their PowerPoint-authored duration and use this value for subsequent `after-previous` spacing | |
| 342 | | `effect_options` | Effect-specific PowerPoint parameters; requires an explicit canonical `effect` in the same legacy block or `effects[]` row | |
| 343 | | `trigger_shape` | Different top-level group id for native **On Click of**; row-only and not inherited. It implies `on-click`; an explicit row `trigger` may accompany it only when also `on-click` | |
| 344 | | `repeat_count` / `repeat_duration` | Repeat count or total repeat span; mutually exclusive | |
| 345 | | `auto_reverse`, `rewind` | Reverse each cycle and/or restore the pre-animation state | |
| 346 | | `accelerate`, `decelerate`, `bounce_end` | `0..1` timing ratios; acceleration plus deceleration must not exceed `1`; bounce requires an interpolated effect and cannot combine with deceleration | |
| 347 | | `restart` | `always`, `when-not-active`, or `never` | |
| 348 | | `after_effect` | `none`, `dim` with `color`, `hide`, or `hide-on-next-click` | |
| 349 | | `sound` | Project-relative or absolute `.m4a`, `.mp3`, or `.wav` path | |
| 350 | |
| 351 | **Hard rule — one group representation**: A populated |
| 352 | `groups.<id>` object uses either the backward-compatible single-effect fields |
| 353 | or `effects[]`, never both. `effects[]` must contain at least one object, and |
| 354 | every row explicitly names `effect`. An untouched scaffold `{}` is a neutral |
| 355 | placeholder. Omitted row duration, Start, timing/completion controls, and sound |
| 356 | inherit the resolved slide animation values exactly as the legacy form does. |
| 357 | |
| 358 | `effect_options` may contain `direction`, `amount`, `color`, `font_name`, |
| 359 | `relative`, or `size`, but validation permits only fields supported by the |
| 360 | selected effect. Before writing a parameterized effect, run |
| 361 | `python3 skills/ppt-master/scripts/pptx_animations.py --describe |
| 362 | <canonical_effect>` and use the returned values exactly. `duration` owns |
| 363 | PowerPoint Speed; `accelerate`/`decelerate` own smooth start/end, so do not |
| 364 | invent duplicate fields. Change Font's `font_name` is one concrete |
| 365 | target-installed PowerPoint face, never a CSS font stack. |
| 366 | |
| 367 | Use the coherent multi-category `effects[]` example in |
| 368 | [`animations.md`](../../references/animations.md) §2. Its static frame stays |
| 369 | unlisted while one real unit runs enter → move → emphasize → exit. Keep the |
| 370 | legacy object for one-row overrides; never convert old sidecars mechanically. |
| 371 | |
| 372 | Use the complete two-slide deterministic Morph example in |
| 373 | [`animations.md`](../../references/animations.md) §2.1; do not copy the source |
| 374 | group into the destination slide's `groups` block merely to establish identity. |
| 375 | |
| 376 | **Forbidden — SVG pollution**: do not add `data-*` animation attributes to SVG files. Animation customization belongs in `animations.json`. |
| 377 | |
| 378 | --- |
| 379 | |
| 380 | ## 5. Validate and Return to Generate Export |
| 381 | |
| 382 | When `animations.json` was newly created or changed after the §1 validation, |
| 383 | run: |
| 384 | |
| 385 | ```bash |
| 386 | python3 skills/ppt-master/scripts/animation_config.py validate <project_path> |
| 387 | ``` |
| 388 | |
| 389 | After validation succeeds, return to the owning export path: |
| 390 | |
| 391 | - Default Generate → [`generate-pptx.md`](../generate-pptx.md) Step 7.1, which |
| 392 | owns note splitting, `finalize_svg.py`, native export, and the published |
| 393 | postflight receipt. |
| 394 | - Quick Generate → [`quick-generate.md`](../profiles/quick-generate.md) §4, |
| 395 | which skips finalization and exports with `--quick-generate`. |
| 396 | |
| 397 | Both exporters read `<project_path>/animations.json` automatically. If §2 |
| 398 | changed `svg_output/`, complete the owning route's required final SVG quality |
| 399 | rerun before returning. Do not finalize or export independently from this |
| 400 | stage. |
| 401 | |
| 402 | **Validation**: The later native export must reflect the per-slide and |
| 403 | per-object overrides. `--animation none` still disables all per-element |
| 404 | animation and overrides `animations.json`. Unknown animation |
| 405 | effects/modes/triggers; unsupported effect options; incompatible, boolean, |
| 406 | non-finite, or out-of-range timing parameters; non-positive durations; negative |
| 407 | delay/stagger; invalid order; missing slides/groups; and structural-layer |
| 408 | targets fail validation. Transition validation remains strict. None of these |
| 409 | failures substitutes a fallback effect or silently drops a requested target. |
| 410 | Deterministic Morph also rejects non-adjacent source slides, missing or |
| 411 | ambiguous direct-root groups, conflicting or undeclared shared keys, non-object |
| 412 | Morph, and any target that does not remain one compatible Slide-local object |
| 413 | after structure processing. |
| 414 | |
| 415 | Generate Step 7 export reads back row order, including repeated rows targeting |
| 416 | one shape, trigger, target, resolved effect, duration, offset, timing placement, |
| 417 | IDs, and shape references. Narration |
| 418 | preserves these rows. Direct-PPTX routes fingerprint and preserve source object |
| 419 | animation; they never author it. See |
| 420 | [`pptx-animations.md`](../../scripts/docs/pptx-animations.md). |
| 421 | |
| 422 | ### 5.1 Optional Video Motion Handoff |
| 423 | |
| 424 | When a downstream video renderer will enhance the deck, have Generate Step 7.3 |
| 425 | append `--conversion-trace`. After that final export succeeds, derive the motion |
| 426 | plan from its resolved trace: |
| 427 | |
| 428 | ```bash |
| 429 | python3 skills/ppt-master/scripts/video_motion_plan.py \ |
| 430 | <project_path>/validation/<output_stem>.trace.json \ |
| 431 | -o <project_path>/validation/video_motion_plan.json \ |
| 432 | --style adaptive \ |
| 433 | --force |
| 434 | ``` |
| 435 | |
| 436 | For narrated output, use the final `--recorded-narration` trace. The video plan |
| 437 | locks identity, effect, direction, order, bounds, and timing; it may refine |
| 438 | renderer parameters but cannot replace the source effect. See |
| 439 | [`video-motion-plan.md`](../../scripts/docs/video-motion-plan.md). |
| 440 | |
| 441 | --- |
| 442 | |
| 443 | ## ✅ Customize Animations Complete |
| 444 | |
| 445 | - [x] Applicable semantic context and motion intent were resolved |
| 446 | - [x] Adopted object targets use real post-regroup SVG ids when object motion is in scope |
| 447 | - [x] Sparse `animations.json` overrides are valid when present; a no-op path creates none |
| 448 | - [x] Any regrouped SVG passed the final quality gate |
| 449 | - [x] Control returned to Generate Step 7 for preview, export, read-back, and package validation |
| 450 | - [x] Any requested video plan waits for the final resolved conversion trace |
| 451 |