| 1 | --- |
| 2 | name: oh-my-ppt-data-anim |
| 3 | description: Must be read before adding or modifying Oh My PPT slide animations. Defines exportable data-anim usage, trigger decisions, and how to replace unsupported scripted/anime.js animation. |
| 4 | --- |
| 5 | |
| 6 | # Oh My PPT Data Anim |
| 7 | |
| 8 | For deeper examples (trigger choice guide, scripted animation patterns, timing tips), read `references/data-anim.md`. |
| 9 | |
| 10 | ## When to use |
| 11 | |
| 12 | - Adding entrance or emphasis animation to slide elements |
| 13 | - Creating staggered reveal sequences for cards, steps, or list items |
| 14 | - Repairing broken or unsupported animation |
| 15 | |
| 16 | ## When not to use |
| 17 | |
| 18 | - Layout-only changes with no motion intent |
| 19 | - Adding animation in edit mode unless the user asks, the page already has animation, or you are fixing broken animation |
| 20 | |
| 21 | ## 30-second decision checklist |
| 22 | |
| 23 | Before adding animation, answer these: |
| 24 | |
| 25 | 1. **Reading path**: which elements should appear first, second, third? Animation follows the reading path. |
| 26 | 2. **Trigger**: load (default), stagger (repeated items), with (group together), after (sequence), click (presentation control only)? |
| 27 | 3. **Type**: fade, slide, scale, fly, wipe, zoom, bounded emphasis — match the visual intent. |
| 28 | 4. **Duration**: 300–1200ms. Shorter for subtle, longer for dramatic. |
| 29 | |
| 30 | ## How to add animation |
| 31 | |
| 32 | ### 1. Declarative data-anim — preferred |
| 33 | |
| 34 | Add `data-anim` attributes directly on HTML elements. This works in preview and exports deterministically to PPTX. |
| 35 | |
| 36 | ```html |
| 37 | <div data-anim="fade-up" data-anim-delay="stagger(90)">Card 1</div> |
| 38 | <div data-anim="fade-up" data-anim-delay="stagger(90)">Card 2</div> |
| 39 | <div data-anim="fade-up" data-anim-delay="stagger(90)">Card 3</div> |
| 40 | ``` |
| 41 | |
| 42 | ### 2. Supported animation types |
| 43 | |
| 44 | `fade`, `fade-up`, `fade-down`, `fade-left`, `fade-right`, `scale-in`, `slide-up`, `slide-down`, `slide-left`, `slide-right`, `fly-in`, `wipe`, `zoom-in`, `spin-in`, `grow-shrink-soft`, `grow-shrink`, `grow-shrink-strong`, `pulse-soft`, `pulse`, `pulse-strong`, `exit-fade`, `exit-scale`, `exit-zoom`, `exit-wipe`, `exit-fly`, `path` |
| 45 | |
| 46 | ### 3. Attributes |
| 47 | |
| 48 | | Attribute | Values | Notes | |
| 49 | |---|---|---| |
| 50 | | `data-anim` | type from supported list | required | |
| 51 | | `data-anim-trigger` | `load`, `click`, `with`, `after` | omit for `load` | |
| 52 | | `data-anim-sequence` | `with`, `after` | preferred load-order control for new content | |
| 53 | | `data-anim-click-group` | stable token such as `step-1` | only for contiguous `click` animations that should reveal on the same click | |
| 54 | | `data-anim-from` | `left`, `right`, `top`, `bottom`, `center` | direction/origin | |
| 55 | | `data-anim-delay` | ms or `stagger(N)` | stagger for repeated items | |
| 56 | | `data-anim-stagger` | ms | preferred new declarative stagger gap | |
| 57 | | `data-anim-duration` | ms | prefer 300–1200 | |
| 58 | | `data-anim-path` | inline linear path string such as `M 0 0 L 120 30` | only for `path` type | |
| 59 | |
| 60 | ### 4. Trigger patterns |
| 61 | |
| 62 | **stagger(N)** — repeated items appearing in sequence: |
| 63 | ```html |
| 64 | <div data-anim="fade-up" data-anim-delay="stagger(90)">Point 1</div> |
| 65 | <div data-anim="fade-up" data-anim-delay="stagger(90)">Point 2</div> |
| 66 | ``` |
| 67 | |
| 68 | **data-anim-stagger="N"** — preferred new syntax for repeated items: |
| 69 | ```html |
| 70 | <div data-anim="fade-up" data-anim-stagger="90">Point 1</div> |
| 71 | <div data-anim="fade-up" data-anim-stagger="90">Point 2</div> |
| 72 | ``` |
| 73 | |
| 74 | **with** — group starts together with previous animated element: |
| 75 | ```html |
| 76 | <h2 data-anim="fade-up">Market Signal</h2> |
| 77 | <p data-anim="fade" data-anim-trigger="with" data-anim-delay="120">Supporting text.</p> |
| 78 | ``` |
| 79 | |
| 80 | **after** — short auto-playing sequence: |
| 81 | ```html |
| 82 | <div data-anim="fade-up">1. First</div> |
| 83 | <div data-anim="fade-up" data-anim-trigger="after">2. Second</div> |
| 84 | <div data-anim="fade-up" data-anim-trigger="after">3. Third</div> |
| 85 | ``` |
| 86 | |
| 87 | For new content, prefer `data-anim-sequence` so trigger semantics stay separate from load ordering: |
| 88 | ```html |
| 89 | <div data-anim="fade-up">1. First</div> |
| 90 | <div data-anim="fade" data-anim-sequence="with" data-anim-delay="80">Supporting note</div> |
| 91 | <div data-anim="fade-up" data-anim-sequence="after">2. Second</div> |
| 92 | ``` |
| 93 | |
| 94 | **click** — only for explicit presentation control (step-by-step, one-by-one reveal). Use `load`, `stagger`, `with`, or `after` for timelines, processes, steps, and flows. |
| 95 | |
| 96 | **click-group** — multiple contiguous click-triggered elements on the same build step: |
| 97 | ```html |
| 98 | <div data-anim="fade-up" data-anim-trigger="click" data-anim-click-group="reveal">Headline</div> |
| 99 | <div data-anim="pulse-soft" data-anim-trigger="click" data-anim-click-group="reveal">Badge</div> |
| 100 | <div data-anim="fade" data-anim-trigger="click">Next click step</div> |
| 101 | ``` |
| 102 | |
| 103 | - Use only on `data-anim-trigger="click"` elements. |
| 104 | - Keep the grouped elements contiguous in DOM order. |
| 105 | - Do not use click-group as a timeline DSL or to jump across unrelated click steps. |
| 106 | |
| 107 | ## Preview-only boundary |
| 108 | |
| 109 | - Keep the standard editable lane focused on whole-element motion. |
| 110 | - `splitText`, per-letter/per-word choreography, SVG draw/morph helpers, and arbitrary path choreography are not part of the normal editable contract. |
| 111 | - The only supported path-like public motion in the editable lane is the constrained `data-anim="path"` semantic with an inline linear path string such as `M 0 0 L 120 30`. Richer path/draw/morph ideas belong to a future preview-only lane. |
| 112 | - `data-anim-easing`, `data-anim-repeat`, and `data-anim-direction` are runtime-only compatibility attributes. Do not use them in standard generated editable/exportable pages because PPTX export/import does not preserve them semantically. |
| 113 | |
| 114 | ### 5. Directional examples |
| 115 | |
| 116 | ```html |
| 117 | <div data-anim="fly-in" data-anim-from="left">Side metric</div> |
| 118 | <div data-anim="wipe" data-anim-from="right">Process bar</div> |
| 119 | <div data-anim="slide-right">Supporting card</div> |
| 120 | <div data-anim="exit-wipe" data-anim-from="top">Dismissed panel</div> |
| 121 | <div data-anim="exit-scale">Quietly de-emphasized chip</div> |
| 122 | <div data-anim="exit-zoom">Dramatic hero outro</div> |
| 123 | <div data-anim="zoom-in">Hero number</div> |
| 124 | <div data-anim="pulse">Key risk</div> |
| 125 | <div data-anim="pulse-strong" data-anim-trigger="click">Escalation callout</div> |
| 126 | <div data-anim="grow-shrink-soft">Subtle confirmation</div> |
| 127 | ``` |
| 128 | |
| 129 | ## Scripted animation escape hatch |
| 130 | |
| 131 | Use `PPT.animate(targets, params)` only when `data-anim` cannot express a complex timeline or synchronized choreography: |
| 132 | |
| 133 | ```js |
| 134 | PPT.animate(".card", { |
| 135 | opacity: [0, 1], |
| 136 | translateY: [20, 0], |
| 137 | duration: 500, |
| 138 | delay: PPT.stagger(100) |
| 139 | }) |
| 140 | ``` |
| 141 | |
| 142 | - Targets is the first argument (a CSS selector string or DOM element), not an object property. |
| 143 | - Create timelines with `PPT.createTimeline(targets, params)`. |
| 144 | - Use `PPT.stagger(ms)` for staggered scripted delays. |
| 145 | |
| 146 | ## Hard rules |
| 147 | |
| 148 | - Prefer no animation, `load`, `stagger`, `with`, or `after` before `click`. |
| 149 | - Use `data-anim-click-group="name"` only for contiguous `click` animations that share one reveal step. |
| 150 | - Keep emphasis choices bounded: `pulse-soft|pulse|pulse-strong` and `grow-shrink-soft|grow-shrink|grow-shrink-strong`. |
| 151 | - Do not use `data-anim-easing`, `data-anim-repeat`, or `data-anim-direction` in normal generated editable pages. Those attributes are runtime-only compatibility and are not part of the export-friendly contract. |
| 152 | - Use `PPT.animate(selector, params)` — targets is the first argument, not an object property. Call `PPT.animate(...)`, never `anime(...)` or `anime.timeline(...)`. |
| 153 | - The runtime handles initial hidden states automatically. Do not set `opacity-0`, `invisible`, `visibility:hidden`, `display:none`, or inline `opacity:0` on animated elements. |
| 154 | - Use only the supported data-anim types listed above. |
| 155 | |
| 156 | ## Failure repair strategy |
| 157 | |
| 158 | When animation is broken or not playing: |
| 159 | |
| 160 | 1. **Check the type value**: must be from the supported list. Values like `typewriter`, `glitch-in`, `path-draw` are not supported. |
| 161 | 2. **Check for conflicting initial states**: remove any manual `opacity-0`, `invisible`, `visibility:hidden`, `display:none`, or inline `opacity:0` — the runtime sets these automatically. |
| 162 | 3. **Check for direct anime() calls**: replace `anime(...)` or `anime.timeline(...)` with `PPT.animate(...)` or `PPT.createTimeline(...)`. |
| 163 | 4. **Check targets argument format**: `PPT.animate` takes targets as the first argument, not as an object property like `{ targets: ".card" }`. |
| 164 | |
| 165 | ## Chart animation boundary |
| 166 | |
| 167 | Two levels of chart animation, each handled by a different system: |
| 168 | |
| 169 | - **Chart container entrance** (the whole chart block fading/sliding in): add `data-anim` on the `.ppt-chart-frame` div. |
| 170 | - **Chart internal drawing** (bars growing, lines drawing): controlled by Chart.js `options.animation`. The runtime defaults handle this. |
| 171 | - **Do not** write custom JS timelines that animate individual chart elements. Use `data-anim` for the container, and Chart.js options for the internals. |
| 172 | |
| 173 | ## Cross-skill references |
| 174 | |
| 175 | - Animation follows the reading path defined by layout (see layout skill). Do not animate elements in an order that contradicts the visual hierarchy. |
| 176 | |
| 177 | ## Export Contract Notes |
| 178 | |
| 179 | ### from="center" compatibility |
| 180 | `data-anim-from="center"` cannot roundtrip reliably with trace-based motions (`fly-in`, `wipe`, `exit-fly`, `exit-wipe`). The validator will reject these incompatible combinations. Use `center` only with fade/zoom/path animations that don't depend on directional motion paths. |
| 181 | |
| 182 | ### Click-group token identity |
| 183 | `data-anim-click-group` values preserve **grouping structure and click timing** when roundtripping through PPTX, but the token text itself may change (e.g., `reveal` → `1`). The semantic behavior (elements grouped into the same click step) is preserved. **Do not rely on token name identity** across export/import — only structural grouping is guaranteed. |
| 184 | |
| 185 | ### Sequence roundtrip boundary |
| 186 | `data-anim-sequence="with|after"` controls HTML→PPTX export timing, but PPTX import does **not** reconstruct this attribute. Sequence semantics are **HTML→PPTX only**, not roundtrip. Imported animations use trigger/delay to express timing. |
| 187 | |
| 188 | ### Scale value approximation |
| 189 | External PPTX files with custom animation scale values (e.g., `scaleTo=80000`) are projected to the nearest built-in preset bucket via distance-based matching. The resulting `data-anim` type (e.g., `exit-scale` vs `exit-zoom`) is a best-fit approximation, not an identity-preserving roundtrip value. This applies to both entrance (zoom-in/scale-in/spin-in) and exit (exit-scale/exit-zoom) scale animations. |
| 190 | |
| 191 | ### Path animation constraints |
| 192 | `data-anim="path"` requires `data-anim-path` with a constrained linear path format: `M x y L dx dy` (integer or decimal coordinates). More complex SVG path commands are not supported in the editable contract. |
| 193 |