paper-cutout
edenfunf/reelmimic/.claude/skills/paper-cutout/SKILL.md
Make paper cut-out / stop-motion style animated videos (MP4) with code — handmade construction paper, cardstock, kraft, felt and tissue pieces with scissor-cut or torn edges and soft drop shadows, photographed on a table under a warm lamp; jointed paper puppets with brass split-pin joints, moving in 12 fps steps. Canvas 2D rendered frame by frame in headless Chrome, encoded with ffmpeg. Use when a reference video or brief calls for paper craft, cut-paper, papercraft, stop-motion paper, kids' storybook collage, 剪紙 / 紙片 / 紙偶 / 定格動畫 looks, or when the video-clone router picks the paper-cutout style.
What's in it
- Paper cut-out (stop-motion paper) engine
- Workflow
- API in one screen (all angles in DEGREES, sizes in px, time via sm(lt))
- Rules that matter most
- Engine gotchas
---
name: paper-cutout
description: Make paper cut-out / stop-motion style animated videos (MP4) with code — handmade construction paper, cardstock, kraft, felt and tissue pieces with scissor-cut or torn edges and soft drop shadows, photographed on a table under a warm lamp; jointed paper puppets with brass split-pin joints, moving in 12 fps steps. Canvas 2D rendered frame by frame in headless Chrome, encoded with ffmpeg. Use when a reference video or brief calls for paper craft, cut-paper, papercraft, stop-motion paper, kids' storybook collage, 剪紙 / 紙片 / 紙偶 / 定格動畫 looks, or when the video-clone router picks the paper-cutout style.
---
# Paper cut-out (stop-motion paper) engine
Every frame is a pure function of time `t`. `studio.html` loads `src/kit.js` (shared ReelMimic runtime: timeline,
motion helpers, camera, render hooks), `src/cutout.js` (this look: materials, cut/torn pieces, shadows, set dressing,
props, transitions, captions, the photographed finish), `src/cast.js` (the puppets) and one scene file per shot.
`render.mjs` drives headless Chrome for contact sheets, strips, crops and the final frames.
## Workflow
1. **Scaffold** — `bash .claude/skills/paper-cutout/scripts/new_project.sh <project-dir>` (add `--keep-demo` to keep
the example). Then read **`GUIDE.md`** (in this skill folder) in full, and look at `docs/demo-sheet.jpg`,
`docs/expressions.jpg` (13 expressions × both puppets) and `docs/poses.jpg`.
2. **Storyboard** with reads (what the viewer must understand, when) — the same discipline as painted-animation's
`ANIMATION_GUIDE.md` (timing, one read at a time, anticipation → action → follow-through, transitions at every seam).
3. **Build** one IIFE file per shot in `src/scenes/`, each ending with `shots([[t0, fn]])`; add its `<script>` to
`studio.html` after `cast.js`. Set `duration` in `src/config.js`. Start shots on multiples of 1/12 s.
4. **Look** — `node render.mjs --sheet=... --cols=4 --w=480 --out=out/check/a.jpg`, `--strip=a:b` for motion,
`--crop=x,y,w,h` / `--crop-at=` for faces and hands. Open every image with Read. Fix, re-render.
5. **Render** — `node render.mjs --frames --workers=4 && node render.mjs --encode --out=out/video.mp4 [--audio=...]`.
## API in one screen (all angles in DEGREES, sizes in px, time via `sm(lt)`)
```js
paperCam(lt, [[0,[cx,cy,zoom]], [2,[cx,cy,zoom]]], { stepped }) // camBegin with a (smooth | stepped) move
backdrop(PC.sky, { to }) layer(.5, () => ...) // screen-fixed sheet; parallax depth plane
hills(x,y,w,h,col,{seed,torn}) grass(x,y,w,h,col,seed) tree(x,y,s,{fruit,sway}) → {fruit:[[x,y]..]} bush flower
cloud(x,y,w,{hang:'string'|'stick'}) sun(x,y,r) house(x,y,s) bunting(x0,y0,x1,y1,n,cols) stripes confetti(lt,x,y,{t0})
piece(SH.xxx(...), { x,y,rot,sx,sy, col, mat, depth, torn, seed, alpha, jit }) // ONE cut-out; the base of everything
SH.ellipse/circle/rect/round/poly/smooth/capsule/blob/cloud/leaf/heart/star/drop/tri/band/zig/hills ; clipHalf ; xform
mat: 'paper' | 'card' | 'kraft' | 'felt' | 'tissue' | 'corr' | 'wood' brad(x,y,r) thread(pts) popUp(k,x,y,fn)
PROPS.apple|balloon|flower|star|gift|letter(x, y, ang, s)
// transitions — call AFTER camEnd(), in the INCOMING shot, k = 0→1 on stepped time:
trBook(t,k) trTear(t,k) trFlip(t,k) trSlide(t,k,{dir}) sheetIn(k) sheetOut(k)
captionTrack([[t0, t1, '文字', { style: 'label' | 'letters', y, size }]])
// puppets (cast.js) — (x, y) = ground point, u = size unit
pom(x, y, u, opts) lulu(x, y, u, opts) → joints { hand:[L,R], elbow, shoulder, foot, head, top, mouth }
opts: face, view:'front'|'3q', flip, look, blink, armL/armR:[shoulder,elbow], footL/footR:[dx,dy], sq, dy, lean, tilt,
holdL/holdR:'apple'|{prop,s,dy}|fn, jit, dry (measure only)
moods(lt, [[0,'sad'],[2,'surprised']]) walkCycle(lt,{stride,rate}) + walkSpeed() jumpPose(lt,t0,t1,h) emote(kind,x,y,s,age)
EXPR: neutral happy laugh sad cry angry surprised scared love sleepy wink determined shy
```
## Rules that matter most
1. **Everything is paper.** Draw only through `piece()` / the helpers (never raw `fillRect`/`arc` in scenes). Pick a
material per object; torn edges for landscapes and labels, scissor edges for characters and props.
2. **Depth = shadow.** Background layers `depth` .3–.8, set pieces ~1, puppets 1–1.3, things floating/held up 1.5–3.
Parallax with `layer(k)`. Never fake 3D.
3. **Stop-motion timing.** Drive every puppet/prop pose with `sm(lt)` (12 steps/s). Puppets jitter a hair per step by
themselves; set pieces stay glued (`jit: 0`). Camera moves may be smooth (motion control) or `stepped`.
4. **Replacement faces.** Change expressions with `moods()` (blink hides the swap), not by flipping `face` per frame.
5. **Transitions from the kit of four** (book fold, torn reveal, flip card, sheet slide) at every seam; the previous
shot must NOT draw its own out-transition when the next shot uses one of them (they re-render it live).
6. **Legible at phone size:** puppets big (pom u ≥ 55, lulu u ≥ 36 in a medium shot), captions ≥ 70 px.
7. Captions only via `captionTrack` (overlay, CJK font "Chiron GoRound TC" → "Zen Maru Gothic" → "Noto Sans TC").
## Engine gotchas
- Pure function of `t`: no `Math.random()`, no state between frames. Use `hash`/`rnd`/`sway(key)`.
- `piece()` caches the cut outline by shape key + `seed`. Give each distinct piece its own `seed`, or two identical
shapes get identical wobble (fine for confetti, odd for a pair of trees).
- The cut outline depends on the shape's size, so an animated size re-cuts every frame (edges shimmer). Scale with
`sx/sy` or the camera instead of animating the shape's dimensions.
- `prevFrame()` renders the previous shot at the CURRENT time (it keeps moving under a transition) and swaps `G`;
scenes must use `G`, not a captured context.
- Props held by a flipped puppet are un-mirrored automatically (text/asymmetric props stay readable).
- Speed: ~5–30 ms draw per frame, ~130 ms/frame effective with 4 workers incl. JPEG encode at 1920×1080.
More agent context in edenfunf/reelmimic
37 other files this repository gives its agents.
AGENTS.md
CLAUDE.md
Skill
- anime-cel.claude/skills/anime-cel/SKILL.md
- blender-product-film.claude/skills/blender-product-film/SKILL.md
- captions-overlay.claude/skills/captions-overlay/SKILL.md
- crayon-storybook.claude/skills/crayon-storybook/SKILL.md
- cut-the-curve.claude/skills/cut-the-curve/SKILL.md
- embedded-captions.claude/skills/embedded-captions/SKILL.md
- faceless-explainer.claude/skills/faceless-explainer/SKILL.md
- ffmpeg.claude/skills/ffmpeg/SKILL.md
- figma.claude/skills/figma/SKILL.md
- frontend-design.claude/skills/frontend-design/SKILL.md
- general-video.claude/skills/general-video/SKILL.md
- hyperframes-animation.claude/skills/hyperframes-animation/SKILL.md
- hyperframes-audio.claude/skills/hyperframes-audio/SKILL.md
- hyperframes-cli.claude/skills/hyperframes-cli/SKILL.md
- hyperframes-core.claude/skills/hyperframes-core/SKILL.md
- hyperframes-creative.claude/skills/hyperframes-creative/SKILL.md
- hyperframes-keyframes.claude/skills/hyperframes-keyframes/SKILL.md
- hyperframes-registry.claude/skills/hyperframes-registry/SKILL.md
- hyperframes.claude/skills/hyperframes/SKILL.md
- hyperframes-studio.claude/skills/hyperframes-studio/SKILL.md
- media-use.claude/skills/media-use/SKILL.md
- motion-doctrine.claude/skills/motion-doctrine/SKILL.md
- motion-graphics.claude/skills/motion-graphics/SKILL.md
- music-to-video.claude/skills/music-to-video/SKILL.md
- oversized-cursor.claude/skills/oversized-cursor/SKILL.md
- painted-animation.claude/skills/painted-animation/SKILL.md
- pixel-art.claude/skills/pixel-art/SKILL.md
- product-launch-video.claude/skills/product-launch-video/SKILL.md
- pr-to-video.claude/skills/pr-to-video/SKILL.md
- remotion-to-hyperframes.claude/skills/remotion-to-hyperframes/SKILL.md
- seam-craft.claude/skills/seam-craft/SKILL.md
- slideshow.claude/skills/slideshow/SKILL.md
- talking-head-recut.claude/skills/talking-head-recut/SKILL.md
- video-clone.claude/skills/video-clone/SKILL.md
- whiteboard.claude/skills/whiteboard/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

