Release standalone PPT template workflow 0.5.0
This commit is contained in:
@@ -0,0 +1,326 @@
|
||||
# PPTX Transition Core
|
||||
|
||||
The shared transition core owns page-transition vocabulary, slide-advance
|
||||
semantics, OOXML mutation, MCE preservation, package timing enablement, and
|
||||
read-back validation for every PPTX route.
|
||||
|
||||
## 1. Ownership
|
||||
|
||||
| Concern | Owner |
|
||||
|---|---|
|
||||
| Page transition registry | scripts/pptx_transitions.py |
|
||||
| In-slide object animation | scripts/pptx_animations.py |
|
||||
| Generated PPTX adapter | svg_to_pptx/pptx_package/builder.py |
|
||||
| Template Fill adapter | template_fill_pptx/transitions.py |
|
||||
| Native Enhance adapter | native_enhance_pptx_core.py |
|
||||
| Public workflow | references/animations.md |
|
||||
|
||||
**Hard rule**: adapters resolve route policy, then call the shared core. They
|
||||
must not build, replace, or patch a transition with route-local XML or regex.
|
||||
|
||||
---
|
||||
|
||||
## 2. Domain Model
|
||||
|
||||
| Layer | Meaning | OOXML |
|
||||
|---|---|---|
|
||||
| Enter | How the current slide appears from the preceding slide | Native effect, Effect Options, and duration |
|
||||
| Sound | Optional cue played with the current slide's transition | `p:sndAc/p:stSnd/p:snd` with an embedded WAV relationship |
|
||||
| Advance | How the current slide leaves for the next slide | advClick and advTm |
|
||||
|
||||
Enter policy:
|
||||
|
||||
| Policy | Behavior |
|
||||
|---|---|
|
||||
| preserve | Keep the source visual transition, including unknown extensions |
|
||||
| replace | Write the requested supported effect |
|
||||
| none | Write no visual effect |
|
||||
|
||||
Advance mode:
|
||||
|
||||
| Mode | Behavior |
|
||||
|---|---|
|
||||
| preserve | Keep source advClick and advTm |
|
||||
| click | Click advance only |
|
||||
| after | Timed advance only |
|
||||
| both | Click or timed advance, whichever occurs first |
|
||||
| narration | Timed advance from narration lead-in, audio duration, and page-tail padding; click disabled |
|
||||
|
||||
**Hard rule**: enter=none may coexist with a sound and/or timed advance. The
|
||||
valid result is a non-visual `p:transition` with `p:sndAc`, advance attributes,
|
||||
or both, and no visual-effect child.
|
||||
|
||||
---
|
||||
|
||||
## 3. Compatibility Contract
|
||||
|
||||
The native registry covers the complete current PowerPoint transition gallery:
|
||||
12 Subtle effects, 29 Exciting effects, and 7 Dynamic Content effects. New
|
||||
selection, sidecars, plans, conversion traces, help, and writers use only these
|
||||
48 native keys.
|
||||
|
||||
Eight established low-level names remain valid at input boundaries. They
|
||||
normalize to one native effect plus native `effect_options`; they are not a
|
||||
second transition registry:
|
||||
|
||||
| Compatibility input | Native request |
|
||||
|---|---|
|
||||
| `strips` | `wipe` with `direction: right` |
|
||||
| `circle` | `shape` with `shape: circle` |
|
||||
| `diamond` | `shape` with `shape: diamond` |
|
||||
| `plus` | `shape` with `shape: plus` |
|
||||
| `newsflash` | `flash` |
|
||||
| `pull` | `uncover` |
|
||||
| `wedge` | `clock` with `style: wedge` |
|
||||
| `wheel` | `clock` with `style: clockwise` |
|
||||
|
||||
Standard PresentationML effects use a direct `p:transition` carrier:
|
||||
|
||||
| Effect | Required primary child and attributes |
|
||||
|---|---|
|
||||
| fade | p:fade |
|
||||
| push | p:push dir=r |
|
||||
| wipe | p:wipe dir=r |
|
||||
| split | p:split |
|
||||
| cut | p:cut |
|
||||
| random_bars | p:randomBar dir=vert |
|
||||
| shape | p:circle |
|
||||
| uncover | p:pull dir=r |
|
||||
| cover | p:cover dir=r |
|
||||
| dissolve | p:dissolve |
|
||||
| checkerboard | p:checker |
|
||||
| blinds | p:blinds dir=vert |
|
||||
| clock | p:wheel spokes=1 |
|
||||
| random | p:random |
|
||||
| box | p:zoom |
|
||||
| comb | p:comb |
|
||||
|
||||
Office 2010 effects use a `p14` Choice with a `p:fade` Fallback:
|
||||
|
||||
| Effect | Required primary child and attributes |
|
||||
|---|---|
|
||||
| reveal | p14:reveal dir=r |
|
||||
| flash | p14:flash |
|
||||
| ripple | p14:ripple |
|
||||
| honeycomb | p14:honeycomb |
|
||||
| glitter | p14:glitter |
|
||||
| vortex | p14:vortex dir=r |
|
||||
| shred | p14:shred dir=out |
|
||||
| switch | p14:switch dir=r |
|
||||
| flip | p14:flip dir=r |
|
||||
| gallery | p14:gallery dir=r |
|
||||
| cube | p14:prism dir=r |
|
||||
| doors | p14:doors dir=vert |
|
||||
| zoom | p14:warp dir=in |
|
||||
| pan | p14:pan dir=r |
|
||||
| ferris_wheel | p14:ferris dir=r |
|
||||
| conveyor | p14:conveyor dir=r |
|
||||
| rotate | p14:prism dir=r isContent=1 |
|
||||
| window | p14:window |
|
||||
| orbit | p14:prism dir=r isContent=1 isInverted=1 |
|
||||
| fly_through | p14:flythrough |
|
||||
|
||||
Office 2012 effects use a `p15` Choice with a `p:fade` Fallback:
|
||||
|
||||
| Effect | Required primary child and attributes |
|
||||
|---|---|
|
||||
| fall_over | p15:prstTrans prst=fallOver invX=1 |
|
||||
| drape | p15:prstTrans prst=drape invX=1 |
|
||||
| curtains | p15:prstTrans prst=curtains |
|
||||
| wind | p15:prstTrans prst=wind |
|
||||
| prestige | p15:prstTrans prst=prestige |
|
||||
| fracture | p15:prstTrans prst=fracture |
|
||||
| crush | p15:prstTrans prst=crush |
|
||||
| peel_off | p15:prstTrans prst=peelOff invX=1 |
|
||||
| page_curl | p15:prstTrans prst=pageCurlSingle invX=1 |
|
||||
| airplane | p15:prstTrans prst=airplane |
|
||||
| origami | p15:prstTrans prst=origami |
|
||||
|
||||
`morph` uses `p159:morph option=byObject` in an Office 2015 Choice with a
|
||||
`p:fade` Fallback. `none` is the explicit no-visual-effect input and therefore
|
||||
is not a registry entry.
|
||||
|
||||
### 3.1 Native Effect Options
|
||||
|
||||
Use `effect_options` only with an explicit native `effect`. Omitted options use
|
||||
the PowerPoint-authored `default` reported by `--describe-transition`:
|
||||
|
||||
| Effect | Supported options |
|
||||
|---|---|
|
||||
| `morph` | `morph_by`: `object`, `word`, `character` |
|
||||
| `fade` | `style`: `smoothly`, `through_black` |
|
||||
| `push`, `wipe`, `vortex`, `cube`, `pan`, `rotate`, `orbit` | `direction`: `left`, `right`, `up`, `down` |
|
||||
| `split` | `orientation`: `horizontal`, `vertical`; `direction`: `out`, `in` |
|
||||
| `reveal` | `direction`: `right`, `left`; `through_black`: boolean |
|
||||
| `cut` | `through_black`: boolean |
|
||||
| `random_bars`, `blinds`, `doors` | `orientation`: `vertical`, `horizontal` |
|
||||
| `checkerboard` | `direction`: `across`, `down` |
|
||||
| `comb`, `window` | `orientation`: `horizontal`, `vertical` |
|
||||
| `shape` | `shape`: `circle`, `diamond`, `plus` |
|
||||
| `uncover`, `cover` | `direction`: `left`, `right`, `up`, `down`, `up_left`, `up_right`, `down_left`, `down_right` |
|
||||
| `fall_over`, `drape`, `wind`, `peel_off`, `airplane`, `origami` | `direction`: `right`, `left` |
|
||||
| `page_curl` | `direction`: `right`, `left`; `pages`: `single`, `double` |
|
||||
| `clock` | `style`: `clockwise`, `counterclockwise`, `wedge` |
|
||||
| `ripple` | `origin`: `center`, `up_left`, `up_right`, `down_left`, `down_right` |
|
||||
| `glitter` | `shape`: `diamond`, `hexagon`; `direction`: `right`, `left`, `up`, `down` |
|
||||
| `shred` | `pattern`: `strips`, `rectangle`; `direction`: `out`, `in` |
|
||||
| `switch`, `flip`, `gallery`, `ferris_wheel`, `conveyor` | `direction`: `right`, `left` |
|
||||
| `box`, `zoom` | `direction`: `out`, `in` |
|
||||
| `fly_through` | `direction`: `in`, `out`; `bounce`: boolean |
|
||||
| All other native effects | No Effect Options |
|
||||
|
||||
Example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"transition": {
|
||||
"effect": "page_curl",
|
||||
"effect_options": {
|
||||
"direction": "left",
|
||||
"pages": "double"
|
||||
},
|
||||
"duration": 0.6,
|
||||
"sound": "sounds/bigsoundbank/<file>.wav"
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
`transition.sound` is optional and accepts a `.wav` path resolved by the
|
||||
generated-project adapter. A bundled-library choice is synced on demand only
|
||||
after the visual transition plan is complete, then referenced by its
|
||||
project-relative `sounds/<namespace>/<file>.wav` path. The adapter packages the
|
||||
file and passes the shared core an embedded relationship id/name; the core
|
||||
never reads `templates/sounds/` or resolves library ids.
|
||||
|
||||
Inspect the exact contract, including compatibility desugaring:
|
||||
|
||||
~~~bash
|
||||
python3 skills/ppt-master/scripts/pptx_animations.py --describe-transition page_curl
|
||||
python3 skills/ppt-master/scripts/pptx_animations.py --describe-transition diamond
|
||||
~~~
|
||||
|
||||
Read-back reports the canonical native effect, its complete effective options,
|
||||
the raw OOXML child, and raw attributes. This makes option loss a validation
|
||||
failure rather than a silent downgrade.
|
||||
|
||||
**Hard rule — no downgrade**:
|
||||
|
||||
- Never rename or remove an established effect.
|
||||
- Never omit its established direction or split attributes.
|
||||
- Reject an unknown requested effect; never substitute fade.
|
||||
- Preserve an unknown source effect when the route selects preserve.
|
||||
- An extension counts as successful only when the primary Choice contains the
|
||||
requested effect. A fallback alone is not success.
|
||||
|
||||
### 3.2 Deterministic Morph Identity
|
||||
|
||||
The generated route may add an explicit `slides.<destination>.morph` block to
|
||||
bind direct-root SVG groups across adjacent slides. The sidecar stable key is
|
||||
lowered to the same top-level `p:cNvPr@name="!!<key>"` on both final
|
||||
Slide-local objects. This does not create an Animation Pane row and does not
|
||||
change either object's numeric shape id.
|
||||
|
||||
The full plan is resolved before any SVG conversion so a source group named by
|
||||
the following slide remains a stable top-level target. Names are written only
|
||||
after flat/structured/preserve processing has finished; structured slide-shape
|
||||
roster expectations are then refreshed. Package read-back requires:
|
||||
|
||||
- the declared source to be the immediately preceding public slide;
|
||||
- exactly one `!!<key>` object on each side;
|
||||
- the same OOXML object container type on both sides;
|
||||
- Morph by object on the destination; and
|
||||
- no structural target, same-slide name collision, group/key conflict, or
|
||||
undeclared shared `!!` name on a Morph edge.
|
||||
|
||||
Morph without an explicit pair block retains PowerPoint's automatic matching
|
||||
behavior. Explicit pairing is generated-route authoring; direct-PPTX routes
|
||||
continue to preserve existing object names and transition XML.
|
||||
|
||||
---
|
||||
|
||||
## 4. Route Mapping
|
||||
|
||||
| Route | Default enter | Default advance | Compatibility note |
|
||||
|---|---|---|---|
|
||||
| Generated PPTX CLI | fade, 0.4s; no sound | click | auto-advance maps to both; an optional sidecar sound is project-local |
|
||||
| Recorded narration | Preserve resolved enter | narration | none remains visually none |
|
||||
| Template Fill | preserve source | preserve source | explicit effects replace; legacy advance_after maps to both |
|
||||
| Native Enhance | Confirmed global/per-slide plan effect | Confirmed timing module | With audio off, an enabled global transition or explicit global `none` applies to all pages; with audio on, the scope flag controls non-narrated pages |
|
||||
|
||||
Template Fill changes source transitions only when its CLI or per-slide plan
|
||||
selects a replacement, removal, or timed advance. Native Enhance uses its
|
||||
confirmed plan. The public `create_pptx_with_native_svg` Python API retains its
|
||||
legacy 0.5s default; the generated-deck CLI explicitly passes 0.4s.
|
||||
|
||||
---
|
||||
|
||||
## 5. OOXML Rules
|
||||
|
||||
**Slide child order**:
|
||||
|
||||
~~~text
|
||||
p:cSld
|
||||
p:clrMapOvr
|
||||
p:transition or transition mc:AlternateContent
|
||||
p:timing
|
||||
p:extLst
|
||||
~~~
|
||||
|
||||
One slide may contain at most one logical transition carrier:
|
||||
|
||||
- one direct p:transition; or
|
||||
- one root-level mc:AlternateContent whose Choice/Fallback branches contain
|
||||
p:transition.
|
||||
|
||||
Mutation rules:
|
||||
|
||||
| Operation | Direct transition | AlternateContent |
|
||||
|---|---|---|
|
||||
| preserve | Leave unchanged | Leave wrapper and branches unchanged |
|
||||
| advance-only | Patch direct attributes | Patch Choice and Fallback identically |
|
||||
| replace | Replace the direct carrier | Remove the whole wrapper, then write one carrier |
|
||||
| none | Remove visual effect; retain a non-visual carrier when sound or timing is needed | Remove the whole wrapper; write a non-visual carrier when sound or timing is needed |
|
||||
|
||||
**Sound placement**: for a direct transition, append `p:sndAc` inside
|
||||
`p:transition` after the visual-effect child, when present. For
|
||||
`mc:AlternateContent`, write the same sound action into both Choice and
|
||||
Fallback transition carriers so older Office consumers do not lose the cue.
|
||||
The slide relationship targets one packaged WAV part; replacing or removing a
|
||||
requested generated sound must not leave a dangling relationship.
|
||||
|
||||
**MCE prefix rule**: Requires and Ignorable values contain textual prefix
|
||||
names. Serialization must retain bindings for those exact names. Renaming an
|
||||
effect prefix without updating these attributes corrupts compatibility.
|
||||
|
||||
**Package timing rule**: when a route writes advTm, set
|
||||
ppt/presProps.xml p:presentationPr/p:showPr useTimings=1. Do not write showPr
|
||||
into ppt/presentation.xml.
|
||||
|
||||
---
|
||||
|
||||
## 6. Validation and Read-Back
|
||||
|
||||
Reject:
|
||||
|
||||
- unknown effect names;
|
||||
- options without an explicit native effect;
|
||||
- unknown option fields or values for the selected effect;
|
||||
- non-finite values, including NaN and Infinity;
|
||||
- duration less than or equal to zero;
|
||||
- a missing/non-file transition sound, a non-WAV transition sound, or an
|
||||
unresolved/dangling sound relationship;
|
||||
- negative advance or narration padding;
|
||||
- booleans passed as numeric API values;
|
||||
- multiple logical transition carriers;
|
||||
- unresolved MCE Requires or Ignorable prefixes.
|
||||
- invalid forced-Morph adjacency, identity uniqueness, object type, or
|
||||
destination effect.
|
||||
|
||||
Read-back must report the canonical native effect and complete effective
|
||||
options, while keeping the primary Choice child separate from the fallback. It
|
||||
must also report raw effect attributes, carrier type, duration, click mode, and
|
||||
automatic advance time, plus the transition sound relationship/name when
|
||||
present. Package validation must run after writing, not only before mutation.
|
||||
|
||||
Use inline smoke commands and gitignored projects/_smoke_* artifacts. Do not
|
||||
add a tests directory or test_*.py files.
|
||||
Reference in New Issue
Block a user