paper-cutout について
紙の切り絵によるストップモーションアニメを作る JavaScript エンジンです。ショット単位で制作するクリエイター向けに、時間駆動のフレーム、紙の質感、パペットの動き、トランジション、ヘッドレスレンダリングを備えています。
主な機能
- 01時間駆動の決定的なフレーム生成
- 02紙の形状、素材、影
- 03パペットのポーズと表情の制御
- 04ショットの切り替えと字幕トラック
- 05ヘッドレスプレビューとフレーム生成
活用シーン
- 01紙の切り絵風ストップモーションの制作
- 02ストーリーボードに沿ったショット単位の構築
- 03コンタクトシート、ストリップ、最終フレームのレンダリング
- 04キャラクターの表情や動きの確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ edenfunf/ reelmimic --skill paper-cutoutインストール後、Claude Code で/paper-cutoutを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
GUIDE.mdscripts/new_project.shtemplate/.gitignoreLICENSE-render.mjs.txtpackage-lock.jsonpackage.jsonrender.mjsstudio.htmltemplate/src/cast.jsconfig.jscutout.jskit.jstemplate/src/scenes/demo.js詳細
ペーパーカットアウト(ストップモーションペーパー)エンジン
すべてのフレームは、時刻 t の純粋関数です。studio.html は src/kit.js(共有の ReelMimic ランタイム:タイムライン、モーションヘルパー、カメラ、レンダリングフック)、src/cutout.js(この表現スタイル:素材、切り抜き・ちぎり紙のパーツ、影、セット装飾、小道具、トランジション、キャプション、写真のような仕上げ)、src/cast.js(パペット)と、ショットごとのシーンファイルを読み込みます。
render.mjs はヘッドレス Chrome を使って、コンタクトシート、ストリップ、クロップ、最終フレームを生成します。
ワークフロー
- ひな型を作成 —
bash .claude/skills/paper-cutout/scripts/new_project.sh <project-dir>(サンプルを残すには--keep-demoを追加します)。次に、このスキルフォルダー内のGUIDE.mdを最初から最後まで読み、docs/demo-sheet.jpg、docs/expressions.jpg(13種類の表情 × 両方のパペット)、docs/poses.jpgを確認します。 - ストーリーボードを作成 — 読み取り(視聴者が何をいつ理解する必要があるか)を含めます。これは、ペイントアニメーションの
ANIMATION_GUIDE.mdと同じ規律(タイミング、一度に一つの読み取り、予備動作 → 動作 → 後続動作、すべての継ぎ目でトランジション)に従います。 - 構築 —
src/scenes/にショットごとに IIFE ファイルを作成し、それぞれをshots([[t0, fn]])で終わらせます。cast.jsの後に、その<script>をstudio.htmlに追加します。src/config.jsでdurationを設定します。ショットは 1/12 秒の倍数から開始します。 - 見た目を確認 —
node render.mjs --sheet=... --cols=4 --w=480 --out=out/check/a.jpg、動きを確認するには--strip=a:b、顔や手を確認するには--crop=x,y,w,h/--crop-at=を使います。各画像を Read で開きます。修正して再レンダリングします。 - レンダリング —
node render.mjs --frames --workers=4 && node render.mjs --encode --out=out/video.mp4 [--audio=...]。
1画面で確認できる API(すべての角度は度、サイズは px、時間は sm(lt) で指定)
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
最も重要なルール
- すべて紙で作ります。
piece()/ ヘルパー経由でのみ描画します(シーン内でfillRect/arcを直接使わないでください)。オブジェクトごとに素材を選びます。風景やラベルにはちぎり紙の縁、キャラクターや小道具にはハサミで切った縁を使います。 - 奥行き = 影。 背景レイヤーの
depthは .3–.8、セットのパーツは約 1、パペットは 1–1.3、浮いているものや持ち上げられたものは 1.5–3 にします。layer(k)で視差を付けます。3D を偽装しないでください。 - ストップモーションのタイミング。 すべてのパペットや小道具のポーズを
sm(lt)(1 秒あたり 12 ステップ)で制御します。パペットは各ステップでごくわずかに自動で揺れます。セットのパーツは動かないように固定します(jit: 0)。カメラ移動は滑らかにする(モーションコントロール)か、steppedにできます。 - 差し替え式の顔。
faceをフレームごとに切り替えるのではなく、moods()で表情を変えます(まばたきで切り替えを隠します)。 - 4種類のキットからトランジションを選択(本のような折り畳み、ちぎり紙での切り替え、フリップカード、紙のスライド)し、すべての継ぎ目に適用します。次のショットでいずれかを使う場合、前のショットでは独自のアウトトランジションを描画してはいけません(前のショットはトランジション中にリアルタイムで再レンダリングされます)。
- スマートフォンの画面でも判読できるようにします。 パペットを大きくします(ミディアムショットで pom の u ≥ 55、lulu の u ≥ 36)。キャプションは ≥ 70 px にします。
- キャプションは
captionTrack経由でのみ表示します(オーバーレイ、CJK フォントは「Chiron GoRound TC」→「Zen Maru Gothic」→「Noto Sans TC」の順)。
エンジン使用時の注意点
tの純粋関数にします。Math.random()やフレーム間の状態保持は使わないでください。hash/rnd/sway(key)を使います。piece()は、形状キーとseedに基づいて切り抜き線をキャッシュします。異なる各パーツにはそれぞれ固有のseedを指定してください。そうしないと、同じ形状のパーツは同一の揺れ方になります(紙吹雪には適していますが、2本の木には不自然です)。- 切り抜き線は形状のサイズに依存するため、サイズをアニメーションさせると毎フレーム切り抜き直され、縁がちらつきます。形状の寸法をアニメーションさせるのではなく、
sx/syまたはカメラで拡大縮小します。 prevFrame()は現在の時刻で前のショットをレンダリングし(トランジション中も動き続けます)、Gを入れ替えます。シーンではキャプチャ済みのコンテキストではなく、Gを使う必要があります。- 裏返したパペットが持つ小道具は自動的に左右反転が解除されるため、文字や左右非対称の小道具も読みやすいままです。
- 速度:1 フレームあたりの描画は約 5–30 ms、1920×1080 で JPEG エンコードを含め、4 ワーカー使用時の実効速度は約 130 ms/フレームです。
コメント
Markdown 対応