with one click
morph-ppt
Generate Morph-animated PPTs with officecli
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Generate Morph-animated PPTs with officecli
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
MUST USE for cli-jaw PABCD orchestration workflows — orchestrate, phase, attest/attestation, interview mode, goal mode, checkpoints, and multi-phase development. Triggers: orchestrate, phase, attest, attestation, interview, goal mode, checkpoint, PABCD, 요구사항 정리, 인터뷰, 스펙 정리. Operate state transitions only when the user explicitly requests orchestration or an active PABCD phase is injected — do not transition state merely because a document mentions phases, goals, or checkpoints.
MUST USE for every coding task — classifies work depth (C0-C5), task_tags overlays, modular limits, pre-write search, verification-before-completion, and safety rules. Triggers: develop, implement, refactor, feature, bug fix, test, review, code quality, scaffolding.
Use only on the Codex CLI for native image generation or image editing without an API key. Save final PNG files under ~/.cli-jaw/uploads, report web-ready absolute-path markdown, and send to Telegram or Discord only when explicitly requested.
MUST USE for any real runtime debugging in any language — crashes, silent failures, wrong output, build/test failures, flaky tests, performance regressions, and integration bugs. A 5-phase root-cause method: architecture check → investigate → analyze → hypothesize → implement. Triggers: debug this, why is X failing, flaky test, fix the crash, root cause, error, stack trace, regression, 왜 안 돼, 디버깅, 원인 분석.
MUST USE for code review and review-readiness — review process, quality thresholds, antipattern detection, review verdicts, and giving/receiving feedback. Triggers: review this, code review, PR review, check my diff, before merge, antipattern, review-readiness, 리뷰, 코드 리뷰, 머지 전에 확인.
MUST USE for any frontend, web UI, or visual implementation work — building, styling, or redesigning pages/components, responsive layouts, motion, component architecture, and production-surface polish. Triggers: frontend, UI, component, CSS, responsive, animation, React, Vue, Svelte, Tailwind, layout, styling, redesign, mockup, anti-slop, 프론트엔드, UI 작업, 반응형, 디자인 수정.
| name | morph-ppt |
| description | Generate Morph-animated PPTs with officecli |
Generate visually compelling PPTs with smooth Morph animations.
Philosophy: Trust yourself to learn through practice. This skill provides workflow and references — you bring creativity and judgment.
.pptxPowerPoint's Morph transition creates smooth animations by matching shapes with identical names across adjacent slides.
Slide 1: shape name="!!circle" x=5cm width=8cm
Slide 2: shape name="!!circle" x=20cm width=12cm
↓
Result: Circle smoothly moves and grows
Three core concepts:
!! prefix that evolve across slidesx=36cm (off-screen) instead of deletingFor details: reference/pptx-design.md
Ask only when topic is unclear, otherwise proceed directly.
⚠️ CRITICAL KNOWN ISSUE: Name-based path selectors break after
transition=morphis set After callingofficecli set '/slide[N]' --prop transition=morph, paths like/slide[N]/!!my-shapereturn 'Element not found'. The CLI auto-prepends!!to shape names when morph is applied, which invalidates name-based lookups.Workaround: Always use shape INDEX paths instead of name paths when accessing shapes on morph slides:
# WRONG (after transition=morph set): officecli get deck.pptx '/slide[3]/!!my-circle' --depth 1 # CORRECT: officecli get deck.pptx '/slide[3]' --depth 1 # first list all shapes to find index officecli get deck.pptx '/slide[3]/shape[2]' --depth 1The build.py template should use
inspect()+ index-based access throughout.
FIRST: Read the thinking framework
→ Open and read reference/decision-rules.md — it provides the structured approach for planning compelling presentations (Pyramid Principle, SCQA, page types).
Then create brief.md with:
Morph Pair Scene Planning (REQUIRED before building)
For every morph transition, plan the slide pair BEFORE writing any code. Use a table like this in brief.md:
| Pair | Slide A (start) | Slide B (end) | Visual narrative purpose |
|---|---|---|---|
| 1→2 | Ring centered, title appears | Ring shifts right, subtitle revealed | Attention → context |
| 2→3 | Feature box large | Feature box small, metric card grows | Zoom out → detail |
| 3→4 | Metric card exits (ghost), new actor enters | Actor repositions | Section transition |
Rules for the planning table:
!! shape names during planning — the same name must be used identically across the slide pair!! shape, decide its role: !!scene-{desc} (background/decoration) or !!actor-{desc} (content/foreground)Before generation starts, always remind the user:
FIRST: Install officecli if needed
Follow the install section in reference/officecli-pptx-min.md section 0.
IMPORTANT: Use morph-helpers for reliable workflow
Generate a Python script that uses reference/morph-helpers.py — this provides helper functions with built-in verification. Python works cross-platform (Mac / Windows / Linux).
Shape naming rules (for best results):
Use these naming patterns for clear code and reliable verification:
Namespace prefixes for !! shapes — prevent scene collision:
All persistent !! shapes MUST use one of these two prefixes to avoid morph engine confusion when multiple morph pairs share similar shape names:
!!scene-{desc} — Background / decoration shapes (e.g., !!scene-ring, !!scene-bg-gradient, !!scene-grid-line)
!!actor-{desc} — Content / foreground shapes (e.g., !!actor-feature-box, !!actor-metric, !!actor-label)
Rule: !!scene-* and !!actor-* names must NEVER be identical.
Bad: !!scene-card and !!actor-card in the same deck — morph engine will confuse them.
Good: !!scene-card-bg and !!actor-card-content — unambiguous.
Scene actors (persistent across slides):
name=!!scene-{desc} or name=!!actor-{desc}name=!!scene-ring, name=!!scene-dot, name=!!actor-feature-boxx=36cm.
Morph will smoothly slide it out of view.
Example: officecli set deck.pptx '/slide[N]/!!FeatureBox' --prop x=36cm --prop y=14cm
To bring it back on a later slide, simply move it back to a visible position.!! content shapes from the previous
section must also be ghosted to x=36cm. Only decoration actors that persist
throughout the entire deck (e.g., a background ring) should remain visible.
# Entering new section: ghost all previous section's !! content shapes
# First, check what !! shapes are on the current slide
officecli get deck.pptx '/slide[N]' --depth 1
# Then ghost each one
officecli set deck.pptx '/slide[N]/!!FeatureBox' --prop x=36cm
officecli set deck.pptx '/slide[N]/!!MetricCard' --prop x=36cm
officecli set deck.pptx '/slide[N]/!!ChannelLabel' --prop x=36cm
Rule: Each new section's first slide should be clean — only current-section
actors visible; no leftover shapes from the previous section.Content shapes (unique per slide):
name=#sN-description# + s + slide_number + - + descriptionname=#s1-title, name=#s2-card1, name=#s3-statsGhost accumulation — critical behavior to understand:
Once a
!!-prefixed shape appears on any slide, it persists and remains visible on every subsequent morph slide unless explicitly moved off-screen.
This means:
!!actor-feature-box introduced on slide 3 will still be visible on slides 4, 5, 6, 7 ... unless you ghost itmorph_final_check tool does NOT catch !! shapes that linger in the visible area; only screenshot verification can detect thisGhost cleanup pattern — when a !!actor-* shape is no longer needed, exit it explicitly:
# Pattern: after the last slide where !!actor-feature-box is needed,
# on the NEXT slide's setup, move it off-screen BEFORE adding new content
officecli set deck.pptx '/slide[N]/shape[X]' --prop x=36cm --prop y=10cm
# If the shape served a 2-slide story arc (slides 3→4), ghost it on slide 5:
helper("ghost", OUTPUT, 5, <shape_index_of_actor_feature_box>)
Rule: For every !!actor-* shape, its "ghost slide" (where it exits) must be planned in the Phase 2 morph pair table. Do not leave any !!actor-* shape without a planned exit.
Why this naming matters:
#sN- pattern matching) is fastest and most accurate#s1-title is slide 1's titlegrep "#s1-" finds all slide 1 content quickly# prefix, duplicate text detection will catch most issues (but has edge cases)Bottom line: Follow these patterns in your code examples, and verification will work smoothly.
Then proceed with pattern:
#!/usr/bin/env python3
import subprocess, sys, os
def run(*args):
result = subprocess.run(list(args))
if result.returncode != 0:
sys.exit(result.returncode)
# Load helper functions (provides morph_clone_slide, morph_ghost_content, morph_verify_slide)
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
def helper(*args):
run(sys.executable, os.path.join(SCRIPT_DIR, "reference", "morph-helpers.py"), *[str(a) for a in args])
OUTPUT = "deck.pptx"
run("officecli", "create", OUTPUT)
run("officecli", "open", OUTPUT) # Resident mode — all commands run in memory
# ============ SLIDE 1 ============
print("Building Slide 1...")
run("officecli", "add", OUTPUT, "/", "--type", "slide")
run("officecli", "set", OUTPUT, "/slide[1]", "--prop", "background=1A1A2E")
# Scene actors (!!scene-* prefix = decoration, persists entire deck)
run("officecli", "add", OUTPUT, "/slide[1]", "--type", "shape",
"--prop", "name=!!scene-ring", "--prop", "geometry=ellipse", "--prop", "fill=E94560",
"--prop", "opacity=0.3", "--prop", "x=5cm", "--prop", "y=3cm", "--prop", "width=8cm", "--prop", "height=8cm")
run("officecli", "add", OUTPUT, "/slide[1]", "--type", "shape",
"--prop", "name=!!scene-dot", "--prop", "geometry=ellipse", "--prop", "fill=0F3460",
"--prop", "x=28cm", "--prop", "y=15cm", "--prop", "width=1cm", "--prop", "height=1cm")
# Content shapes (#s1- prefix, will be ghosted on next slide)
# Use generous width (25-30cm for titles) to avoid text wrapping!
run("officecli", "add", OUTPUT, "/slide[1]", "--type", "shape",
"--prop", "name=#s1-title", "--prop", "text=Main Title",
"--prop", "font=Arial Black", "--prop", "size=64", "--prop", "bold=true",
"--prop", "color=FFFFFF", "--prop", "x=10cm", "--prop", "y=8cm",
"--prop", "width=28cm", "--prop", "height=3cm", "--prop", "fill=none")
# ============ SLIDE 2 ============
print("Building Slide 2...")
# Use helper: automatically clone + set transition + list shapes + verify
helper("clone", OUTPUT, 1, 2)
# Use helper: ghost all content from slide 1 (shape index 3 = #s1-title)
helper("ghost", OUTPUT, 2, 3)
# Add new content for slide 2
run("officecli", "add", OUTPUT, "/slide[2]", "--type", "shape",
"--prop", "name=#s2-title", "--prop", "text=Second Slide",
"--prop", "font=Arial Black", "--prop", "size=64", "--prop", "bold=true",
"--prop", "color=FFFFFF", "--prop", "x=10cm", "--prop", "y=8cm",
"--prop", "width=28cm", "--prop", "height=3cm", "--prop", "fill=none")
# Adjust scene actors to create motion
# SPATIAL RULE: scene actors must stay in safe zones (see Shape naming rules above)
run("officecli", "set", OUTPUT, "/slide[2]/shape[1]", "--prop", "x=15cm", "--prop", "y=5cm") # !!scene-ring moves
run("officecli", "set", OUTPUT, "/slide[2]/shape[2]", "--prop", "x=5cm", "--prop", "y=10cm") # !!scene-dot moves
# Use helper: verify slide is correct (transition + ghosting)
helper("verify", OUTPUT, 2)
# ============ SLIDE 3 ============
print("Building Slide 3...")
# ============ SECTION TRANSITION: Ghost ALL !! content shapes from previous section ============
# Before adding new section content, ghost every !! shape that belongs to the previous section.
# Run: officecli get deck.pptx '/slide[N]' --depth 1 to list all shapes and confirm indices.
# Then ghost each previous-section actor:
# helper("ghost", OUTPUT, N, shape_index_1)
# helper("ghost", OUTPUT, N, shape_index_2)
# ... repeat for ALL !! shapes that were part of the previous section
# VERIFY: After building, open screenshot of this slide and confirm zero overlap with previous section content.
helper("clone", OUTPUT, 2, 3)
helper("ghost", OUTPUT, 3, 4) # Ghost #s2-title (now at index 4)
run("officecli", "add", OUTPUT, "/slide[3]", "--type", "shape",
"--prop", "name=#s3-title", "--prop", "text=Third Slide",
"--prop", "font=Arial Black", "--prop", "size=64", "--prop", "bold=true",
"--prop", "color=FFFFFF", "--prop", "x=10cm", "--prop", "y=8cm",
"--prop", "width=28cm", "--prop", "height=3cm", "--prop", "fill=none")
run("officecli", "set", OUTPUT, "/slide[3]/shape[1]", "--prop", "x=25cm", "--prop", "y=8cm")
run("officecli", "set", OUTPUT, "/slide[3]/shape[2]", "--prop", "x=10cm", "--prop", "y=5cm")
helper("verify", OUTPUT, 3)
# ============ FINAL VERIFICATION ============
run("officecli", "close", OUTPUT) # Save from memory to disk
print()
print("=========================================")
helper("final-check", OUTPUT)
print()
print("Build complete! Open", OUTPUT, "in PowerPoint to see morph animations.")
Key advantages of using helpers:
morph_clone_slide = clone + transition + list + verify (4 steps → 1 function)# prefix, duplicate detection will still catch the problem!Scene Actor Spatial Rule (CRITICAL):
Scene actors must stay in safe zones at all times — corners and edges only.
DO NOT let scene actors pass through or rest in the content area (x=2~28cm, y=3~16cm).
Safe zones:
Top-right corner: x ≥ 24cm, y ≤ 6cm
Bottom-right: x ≥ 24cm, y ≥ 12cm
Bottom-left: x ≤ 2cm, y ≥ 12cm
Off-screen (right): x ≥ 32cm (fully out of view — use for ghost position)
Before planning any scene actor path, inspect existing shape coordinates:
# List all shapes on a slide (check for coordinate conflicts before placing actors)
officecli get deck.pptx '/slide[N]' --depth 1 --json
Confirm the actor's target position does not overlap any content shape's bounding box
(x to x+width, y to y+height).
Essential rules:
!! prefix, content uses #sN- prefix (best practice for verification and readability)transition=morph (without this, no animation!)x=36cm (don't delete)!!-*) positions between slides for animationreference/pptx-design.md for detailsChoreography — timing and motion principles:
Understanding how morph animates multiple shapes helps you plan intentional motion:
| Animation type | How to achieve it |
|---|---|
| Simple move | Same shape on slide A and B, same size, different x/y — morph interpolates position |
| Scale transform | Same shape on slide A and B, different width/height — morph interpolates size and position |
| Move + scale | Different x, y, width, height simultaneously — morph handles all dimensions at once |
| Color shift | Same shape, different fill color — morph cross-fades the fill |
| Enter (fade in) | Shape exists only on slide B (no counterpart on slide A) — morph fades it in |
| Exit (fade out) | Shape only on slide A (no counterpart on slide B) — morph fades it out |
Multi-shape timing rule:
!! shapes in the same morph pair animate simultaneously — there is no way to stagger their start times within a single pairStaggered timing pattern (two shapes, offset timing):
Slide 2 → Slide 3: !!actor-A moves (!!actor-B stays put)
Slide 3 → Slide 4: !!actor-B moves (!!actor-A stays put or has already exited)
This requires slide 3 as an explicit intermediate keyframe — never try to fake staggering within a single morph pair.
Known CLI behaviors:
!! prefix auto-added after transition=morph: After running set --prop transition=morph
on a slide, the CLI automatically prepends !! to all shape names on that slide
(e.g., #s1-title → !!#s1-title). This is expected behavior.
morph-helpers.py handles this correctly — its verification logic uses substring matching
and is not affected.
⚠️ CRITICAL: Name-based path selectors break after
transition=morphis set After callingofficecli set '/slide[N]' --prop transition=morph, paths like/slide[N]/!!my-shapereturn 'Element not found'. The CLI auto-prepends!!to shape names when morph is applied, which invalidates name-based lookups.Workaround: Always use shape INDEX paths instead of name paths when accessing shapes on morph slides:
# WRONG (after transition=morph set): officecli get deck.pptx '/slide[3]/!!my-circle' --depth 1 # CORRECT: officecli get deck.pptx '/slide[3]' --depth 1 # first list all shapes to find index officecli get deck.pptx '/slide[3]/shape[2]' --depth 1The build.py template should use
inspect()+ index-based access throughout.Pattern recommendation: Pre-plan all shape indices in a comment block at the top of your build script before setting morph. This prevents index tracking errors as the slide's shape count grows.
Shape index tracking: After each batch of shape additions, run
officecli get deck.pptx '/slide[N]' --depth 1 to confirm the current slide's
shape list and indices. This prevents off-by-one errors when manually computing
index values for subsequent ghost/set operations.
Design resources:
reference/pptx-design.md — Design principles (Canvas, Fonts, Colors, Scene Actors, Page Types, Style References)reference/officecli-pptx-min.md — Command syntaxreference/styles/<name>/ — Visual style examples (optional inspiration, browse by use case in styles/INDEX.md)If you used morph-helpers.py, the build script calls helper("verify", ...) and helper("final-check", ...) automatically. Also validate the final structure:
officecli validate <file>.pptx
officecli view <file>.pptx outline
final-check 通过不等于视觉正确。 morph_final_check 只验证 #sN- 前缀 shapes 的 ghost 状态(x=36cm 检查),它无法检测:
!! shapes 在场景切换后仍停留在可视区域(x < 33.87cm)——这类问题会通过 final-check 但产生视觉叠加必须对每张 slide 截图验证:
# 方案1: officecli view(pptx 有 SVG 预览)
officecli view deck.pptx svg --output-dir screenshots/
# 方案2: LibreOffice PDF → Chrome PNG(更准确)
libreoffice --headless --convert-to pdf deck.pptx
# 然后用 Chrome DevTools MCP 截图每页
逐 slide 检查清单:
!! content shapes 均不可见(x >= 33.87cm 已移出视野)!! shapes 已 ghost!! shapes(背景圆、角标等)在正确位置If verification fails, see Troubleshooting section below.
Outputs (3 files):
<topic>.pptxbrief.md — MUST be a standalone file (not embedded inside test-report.md or any other file).
Content: slide-by-slide plan, content per slide, morph design decisions, ghost strategy per transition.Final delivery message requirements:
If morph_verify_slide or morph_final_check reports issues:
Missing transition:
# Check which slides are missing transition
officecli get <file>.pptx '/slide[2]' --json | grep transition
officecli get <file>.pptx '/slide[3]' --json | grep transition
# Expected: "transition": "morph"
# Fix:
officecli set <file>.pptx '/slide[2]' --prop transition=morph
Unghosted content:
# Find unghosted shapes manually
import subprocess
for slide in range(2, 7):
print(f"Slide {slide}:")
subprocess.run(["officecli", "get", "<file>.pptx", f"/slide[{slide}]", "--depth", "1"])
# If you see shapes like "#s1-title" on slide 2 (not at x=36cm), they should be ghosted
# Fix (run in terminal):
# officecli set <file>.pptx /slide[N]/shape[X] --prop x=36cm
Visual issues:
# Open HTML preview to debug layout
officecli view <file>.pptx html
Note: !!scene-* shapes (decoration/background actors) should appear on all slides — that's normal and expected. However, !!actor-* shapes (content actors) MUST be ghosted at section boundaries to prevent ghost accumulation. Only #sN- prefix shapes are checked by morph_final_check; !!actor-* shapes require screenshot verification to confirm they are off-screen after their section ends.
Ask user for feedback, support quick adjustments.
reference/decision-rules.md — Planning logic, Pyramid Principlereference/pptx-design.md — Design principles (Canvas, Fonts, Colors, Scene Actors, Page Types)reference/officecli-pptx-min.md — Tool syntaxreference/styles/INDEX.md — Visual style examples organized by use caseWhen the user requests changes after the deck is built:
| Request | Command |
|---|---|
| Swap two slides | officecli swap deck.pptx '/slide[2]' '/slide[4]' |
| Move a slide after another | officecli move deck.pptx '/slide[5]' --after '/slide[2]' |
| Edit shape text | officecli set deck.pptx '/slide[N]/shape[@name=!! ShapeName]' --prop text="..." |
| Change color / style | officecli set deck.pptx '/slide[N]/shape[@name=!! ShapeName]' --prop fill=FF0000 |
| Remove an element | officecli remove deck.pptx '/slide[N]/shape[@name=!! ShapeName]' |
| Find & replace text | officecli set deck.pptx / --prop find=OldText --prop replace=NewText |
Morph caution: Morph transitions rely on matching
!!-prefixed shape names across consecutive slides. After swapping or moving slides, verify that morph pairs (same!!name on adjacent slides) are still correctly aligned. Useofficecli get deck.pptx '/slide[N]' --depth 1to check shape names.
First time? Read "Understanding Morph" above, skim one style reference for inspiration, then generate. Always use morph-helpers.py workflow. You'll learn by doing.
Trust yourself. You have vision, design sense, and the ability to iterate. These tools enable you — your creativity makes it excellent.