AnimationSpec v2 仕様書 — 自作の「文字の動き」
この文書は movlyric の文字の動き(歌詞アニメーション)の定義「AnimationSpec v2」の完全仕様です。 アプリの「スタイルエディタ →「動き」タブ → 文字の動き →「カスタム」→ AIで作る…」から使います(背景に図形を描く「背景エフェクト」は別物で、 そちらは GRAPHIC_SPEC(背景エフェクト) が仕様です)。 v1(モーションのみ)で書かれた JSON はそのまま v2 として有効です。v2 で色・縁取り・発光・軸別の伸縮が追加されました。 この文書だけを読んだ AI(または人間)が、アプリにそのまま貼って通る JSON を書けることを目的とします。 文書末尾に AI へ渡すプロンプトテンプレートがあります。この文書全体をプロンプトの一部として貼り付けても機能します。
1. 概要
movlyric は歌詞(フレーズ)を時間に合わせて画面に表示する動画エンジンです。 1つのフレーズは次の3段階で動きます。
- 入場(in): フレーズ表示窓の先頭(フレーズ発声開始の約1秒前)から、文字/単語が現れる動き
- 表示中(定常): 入場が終わった状態で静止。任意で activePulse(sin 波の脈動)を掛けられる
- 退場(out): 表示窓の末尾(フレーズ発声終了の約1秒後)に向けて消える動き
AnimationSpec はこの in / out / activePulse を keyframe ベースの宣言的 JSON で記述します。 コードや式は書けません。書けるのは以下の仕様にあるフィールドだけです。
2. JSON 形式の完全仕様
2.1 ルート: AnimationSpec
{ "in": <Phase>, "out": <Phase>, "activePulse": <Pulse> }
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
in |
Phase | 必須 | 入場フェーズ |
out |
Phase | 必須 | 退場フェーズ(退場演出が不要でも省略不可。無変化にしたい場合は §2.7 参照) |
activePulse |
Pulse | 任意 | 表示中の脈動。不要ならキーごと省略する(null は不可) |
ルート直下に書けるキーはこの3つだけです。
2.2 Phase(in / out 共通)
| フィールド | 型 | 必須 | 値域 | 説明 |
|---|---|---|---|---|
durationMs |
整数 | 必須 | 50〜4000 | 1ユニット(文字/単語)のフェーズ所要時間(ミリ秒)。小数不可 |
easing |
文字列 | 必須 | §3 の31種のいずれか | フェーズ全体に1回適用されるイージング(keyframe 区間ごとには指定できない) |
stagger |
Stagger | 必須 | — | ユニット間の時間差。時間差なしでも {"unit":"none","delayMs":0,"from":"start"} のように3フィールドすべて必須 |
keyframes |
Keyframe[] | 必須 | 2〜8個 | 動きの列。t は 0..1 の狭義昇順(同値も不可)、先頭は必ず t=0、末尾は必ず t=1 |
2.3 Keyframe
| フィールド | 型 | 必須 | 値域 | 意味・単位 |
|---|---|---|---|---|
t |
数値 | 必須 | 0〜1 | フェーズ内の正規化時刻(0=開始、1=終了) |
alpha |
数値 | 任意 | 0〜1 | 不透明度(0=透明、1=不透明) |
scale |
数値 | 任意 | 0.1〜3 | 拡大率(1=等倍) |
dx |
数値 | 任意 | -2〜2 | 横オフセット。単位は文字サイズ(fontSize)比(1.0=文字1つ分)。正=右 |
dy |
数値 | 任意 | -2〜2 | 縦オフセット。単位は文字サイズ比。正=下(例: 下から入場は正→0) |
rotate |
数値 | 任意 | -360〜360 | 回転。単位は度。正=時計回り |
scaleX |
数値 | 任意 | 0.1〜3 | 横だけの拡大率。scale と掛け合わされる |
scaleY |
数値 | 任意 | 0.1〜3 | 縦だけの拡大率。scale と掛け合わされる |
tint |
整数 | 任意 | 0〜16777215 | 文字色(0xRRGGBB の10進または16進表記) |
strokeWidth |
数値 | 任意 | 0〜20 | 縁取りの太さ(px)。0 で縁取りなし |
strokeColor |
整数 | 任意 | 0〜16777215 | 縁取りの色 |
glow |
数値 | 任意 | 0〜40 | 発光の強さ(ぼかし半径 px)。0 で発光なし |
glowColor |
整数 | 任意 | 0〜16777215 | 発光の色。省略すると文字色で光る(自己発光) |
書けるプロパティは上の13個だけです。他の名前(x, y, opacity, color, blur, shadow など)は存在しません。
単位(dx/dy=文字サイズ比、rotate=度)はアプリ内のアニメーションエディタの表示単位(横/縦=文字サイズ比、回転=度)と同一です。
「未指定」の意味はプロパティごとに違います。 ここを取り違えると意図しない見た目になります。
| プロパティ | 未指定のとき |
|---|---|
alpha / scale / scaleX / scaleY |
1(変化なし) |
dx / dy / rotate |
0(変化なし) |
tint |
文字色を変えない(スタイルのカラオケ発声色がそのまま効く) |
strokeWidth / strokeColor |
スタイルの縁取りをそのまま使う(0 にはならない) |
glow / glowColor |
発光なし |
つまり色や縁取りを変えたくないなら、そのプロパティを書かないでください。tint を書くと、その文字は歌唱に合わせた色替え(未発声→発声済み)をしなくなり、指定した色で固定されます。
scaleX と scaleY を別々に動かすと、潰れて伸びる動き(squash & stretch)が作れます。弾む・着地する表現では、これがあると動きが柔らかくなります。
2.4 Stagger(時間差)
| フィールド | 型 | 必須 | 値域 | 説明 |
|---|---|---|---|---|
unit |
文字列 | 必須 | "none" / "char" / "word" |
時間差の単位。none=フレーズ全体が一斉、char=文字ごと、word=単語ごと |
delayMs |
整数 | 必須 | 0〜500 | ユニット1つ分の遅延(ミリ秒)。小数不可。unit が none でも 0 を明記する |
from |
文字列 | 必須 | "start" / "end" / "center" |
起点。start=先頭から、end=末尾から、center=中央から外へ(偶数個は中央2つが同時に最初) |
n 番目に動くユニットの遅延は 順序×delayMs。ルビ(ふりがな)は常に親単語と同じ位相で動きます。
in と out で別々の stagger を指定できます(例: 入場は先頭から、退場は末尾から)。
2.5 Pulse(activePulse、任意)
| フィールド | 型 | 必須 | 値域 | 説明 |
|---|---|---|---|---|
property |
文字列 | 必須 | "scale" / "alpha" |
揺らす対象 |
amplitude |
数値 | 必須 | 0〜0.5 | 揺れ幅 |
periodMs |
整数 | 必須 | 200〜4000 | 周期(ミリ秒)。小数不可 |
動作: 各ユニットの入場完了後〜退場開始前だけ、1 + amplitude × sin(2π × nowMs / periodMs) を property に乗算します。
nowMs は動画の絶対時刻なので、脈動の位相はフレーズをまたいで連続します(決定論的 = プレビューと書き出しが一致)。
注意: property:"alpha" で定常 alpha が 1 のとき、1 を超える半周期はクランプされるため「暗くなる方向だけ」が見えます(明滅表現としてはそれで自然です)。
2.6 補間の意味論(疎 keyframe)
- プロパティごとに独立して補間します。あるプロパティは「そのプロパティを持つ keyframe」だけを結んで線形補間します。
- 例:
alphaは t=0 と t=1 だけに書き、scaleは t=0 / 0.5 / 1 に書く、というように疎に書けます。
- 例:
- そのプロパティを持つ最初の keyframe より手前は先頭の値、最後の keyframe より後は末尾の値を保持します(最近傍。補外はしません)。
- どの keyframe にも書かれていないプロパティの扱いは §2.3 の「未指定のとき」の表に従います。モーション系は恒等値(alpha=1, scale=1, scaleX=1, scaleY=1, dx=0, dy=0, rotate=0)ですが、色・縁取りは「上書きしない」(スタイルの値がそのまま残る)点が違います。
- easing は「フェーズの進行 0→1」に1回だけ適用され、その eased 値で全プロパティを補間します。
2.7 in と out の合成・定常状態
in と out は常に同時評価され、alpha と scale は乗算、dx / dy / rotate は加算で合成されます。したがって:
- in の t=1 = 表示中の定常状態。通常は恒等値(alpha 1, scale 1, dx 0, dy 0, rotate 0)にします。
- out の t=0 は必ず恒等値にしてください。そうしないと表示中の見た目が out の値でずれ続けます。
- 退場演出を無くしたい場合は out を「無変化」にします:
keyframesを[{"t":0,"alpha":1},{"t":1,"alpha":1}]のように同じ値で書けば動きません(t は昇順を守ること)。
合成後の alpha は最終的に 0..1 にクランプされます。
2.8 タイムラインと短いフレーズでの圧縮
- 表示窓はフレーズ発声区間の前後にそれぞれ約1000msの余白を持ちます。in は窓の先頭から始まり、out は「最後のユニットの t=1 がちょうど窓の末尾」になるよう逆算して配置されます。
- フェーズ全体の所要時間は
durationMs + 最大stagger遅延(順序最大×delayMs)です。これが表示窓より長い場合、タイムライン全体が等倍圧縮されます(窓が短くても文字が出ないままにならない)。文字数が多い歌詞でcharstagger に大きい delayMs を使うと圧縮されやすいので、durationMs + 文字数×delayMsが 2000ms 程度に収まる値を推奨します。
3. イージング一覧(31種)
easing に書ける名前は以下の31種のみです(大文字小文字も厳密一致。ease-in や easeOutBack のような別表記は不可)。
| 名前 | 説明 |
|---|---|
linear |
等速 |
inQuad / outQuad / inOutQuad |
2次。ゆるやかな加速/減速/両方 |
inCubic / outCubic / inOutCubic |
3次。標準的な加速/減速/両方 |
inQuart / outQuart / inOutQuart |
4次。強めの加速/減速/両方 |
inQuint / outQuint / inOutQuint |
5次。かなり強い加速/減速/両方 |
inSine / outSine / inOutSine |
sin 波。最も柔らかい加速/減速/両方 |
inExpo / outExpo / inOutExpo |
指数。急激な加速/減速/両方 |
inCirc / outCirc / inOutCirc |
円弧。終端で急な加速/減速/両方 |
inBack / outBack / inOutBack |
行き過ぎて戻る(反動) |
inElastic / outElastic / inOutElastic |
バネのような振動 |
inBounce / outBounce / inOutBounce |
ボールが弾むようなバウンド |
重要(エンジンの実挙動): back / elastic 系は途中で進行が 0..1 の範囲外に出ますが、補間は最近傍クランプのため出力は端点 keyframe の値で留まります(t=1 の値を超えて飛び出すことはありません)。
「行き過ぎてから戻る」見た目を確実に出したい場合は、中間 keyframe で明示的に書いてください(例: scale を 0 → 1.15 → 1)。
4. よくある間違い(禁止事項)
以下は検証エラーまたは意図しない見た目になります。必ず避けてください。
- 値域違反:
scale: 0や3.5、alpha: 1.2、dx: 2.5、durationMs: 30や5000、delayMs: 600、amplitude: 0.8、periodMs: 100などはすべて不可。§2 の値域表に厳密に従う - 存在しないプロパティ: keyframe に書けるのは §2.3 の13個だけ(
t, alpha, scale, scaleX, scaleY, dx, dy, rotate, tint, strokeWidth, strokeColor, glow, glowColor)。x,y,opacity,color,blur,skew,shadowなどは不可。keyframe ごとの easing 指定も不可 - 色を整数以外で書く:
"#ff0066"や"red"は不可。0xRRGGBBを整数で書く(16進リテラル0xff0066または10進16711782) - 変えたくないプロパティを 0 で書く:
strokeWidth: 0は「縁取りを消す」指定。スタイルの縁取りを残したいなら書かない - t の順序違反: t の降順・同値の重複は不可(狭義昇順)。先頭 t=0 と末尾 t=1 を忘れない
- keyframes の個数: 1個以下・9個以上は不可(2〜8個)
- 小数の禁止箇所:
durationMs/delayMs/periodMsは整数のみ - easing 名の表記揺れ: §3 の31種と厳密一致で書く
- in / out の省略: 両方必須。stagger の3フィールド(unit / delayMs / from)も常に必須
- out の t=0 を恒等値以外にする: 表示中の見た目がずれる(§2.7)
- JSON 以外の混入: コメント、末尾カンマ、式(
"dy": "0.5 * 2"など)は不可。値はすべて数値リテラルか許可された文字列
5. 作例
3つともこのままアプリに貼って通る完全な JSON です。
5.1 ふわっと浮かび上がる
文字が少し下から柔らかくフェードインし、退場は上に抜けながらフェードアウト。
{
"in": {
"durationMs": 700,
"easing": "outSine",
"stagger": { "unit": "char", "delayMs": 40, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 0, "dy": 0.4 },
{ "t": 1, "alpha": 1, "dy": 0 }
]
},
"out": {
"durationMs": 600,
"easing": "inSine",
"stagger": { "unit": "char", "delayMs": 30, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 1, "dy": 0 },
{ "t": 1, "alpha": 0, "dy": -0.3 }
]
}
}
5.2 文字が回転しながら弾んで登場
小さく回転した状態から、行き過ぎ(scale 1.15)を中間 keyframe で明示して弾む入場。退場は末尾の文字から逆回転で縮む。
alpha は疎指定の例: in では t=0.6 までに 1 に達し、以降は末尾値 1 を保持します。
{
"in": {
"durationMs": 800,
"easing": "outBack",
"stagger": { "unit": "char", "delayMs": 60, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 0, "scale": 0.3, "rotate": -180 },
{ "t": 0.6, "alpha": 1, "scale": 1.15, "rotate": 20 },
{ "t": 1, "scale": 1, "rotate": 0 }
]
},
"out": {
"durationMs": 500,
"easing": "inBack",
"stagger": { "unit": "char", "delayMs": 40, "from": "end" },
"keyframes": [
{ "t": 0, "alpha": 1, "scale": 1, "rotate": 0 },
{ "t": 1, "alpha": 0, "scale": 0.3, "rotate": 180 }
]
}
}
5.3 単語ごとに下からスライドイン + 表示中ゆっくり明滅
単語単位の stagger で下から順に現れ、表示中は activePulse でゆっくり明滅。退場はフレーズ全体が一斉にフェードアウト。
{
"in": {
"durationMs": 600,
"easing": "outCubic",
"stagger": { "unit": "word", "delayMs": 120, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 0, "dy": 0.8 },
{ "t": 1, "alpha": 1, "dy": 0 }
]
},
"out": {
"durationMs": 400,
"easing": "inQuad",
"stagger": { "unit": "none", "delayMs": 0, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 1 },
{ "t": 1, "alpha": 0 }
]
},
"activePulse": { "property": "alpha", "amplitude": 0.25, "periodMs": 1600 }
}
5.4 ネオンのように光りながら登場
glow で発光させ、glowColor で光の色を指定。退場では発光を 0 へ収束させる。tint を書いていないので、文字色は歌唱に合わせた色替えがそのまま効く。
{
"in": {
"durationMs": 500,
"easing": "outCubic",
"stagger": { "unit": "char", "delayMs": 40, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 0, "glow": 0, "glowColor": 65535 },
{ "t": 0.6, "alpha": 1, "glow": 34, "glowColor": 65535 },
{ "t": 1, "alpha": 1, "glow": 20, "glowColor": 65535 }
]
},
"out": {
"durationMs": 400,
"easing": "inQuad",
"stagger": { "unit": "none", "delayMs": 0, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 1, "glow": 20, "glowColor": 65535 },
{ "t": 1, "alpha": 0, "glow": 0, "glowColor": 65535 }
]
}
}
5.5 色が変わりながら現れる
tint を動かすと文字色が補間される。tint を書いたフレーズは歌唱に合わせた色替えをしなくなるので、色は全部この spec で決める。
{
"in": {
"durationMs": 700,
"easing": "outQuad",
"stagger": { "unit": "char", "delayMs": 30, "from": "center" },
"keyframes": [
{ "t": 0, "alpha": 0, "tint": 16711808 },
{ "t": 1, "alpha": 1, "tint": 16777215 }
]
},
"out": {
"durationMs": 400,
"easing": "inQuad",
"stagger": { "unit": "none", "delayMs": 0, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 1 },
{ "t": 1, "alpha": 0 }
]
}
}
5.6 潰れて伸びながら着地(squash & stretch)
scaleX と scaleY を逆方向に動かす。落ちてくる間は縦長、着地の瞬間に横へ潰れ、そこから等倍へ戻す。
{
"in": {
"durationMs": 550,
"easing": "outBack",
"stagger": { "unit": "char", "delayMs": 45, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 0, "dy": -1.2, "scaleX": 0.75, "scaleY": 1.35 },
{ "t": 0.7, "alpha": 1, "dy": 0, "scaleX": 1.3, "scaleY": 0.7 },
{ "t": 1, "alpha": 1, "dy": 0, "scaleX": 1, "scaleY": 1 }
]
},
"out": {
"durationMs": 350,
"easing": "inQuad",
"stagger": { "unit": "none", "delayMs": 0, "from": "start" },
"keyframes": [
{ "t": 0, "alpha": 1 },
{ "t": 1, "alpha": 0, "scaleY": 0.6 }
]
}
}
6. AI 用プロンプトテンプレート
以下の枠内をコピーして AI に渡してください。この仕様書全体を先に貼り付け、その直後にテンプレートを続ける使い方を推奨します(仕様書なしでテンプレート単体を渡すと AI が値域や easing 名を誤ります)。
ここからコピー
あなたは movlyric の歌詞アニメーション設計者です。上に貼り付けた「AnimationSpec v2 仕様書」に厳密に従い、AnimationSpec の JSON を1つ作成してください。
出力規則:
- JSON のみを出力する(説明文・前置き・後書きは書かない。JSON をコードフェンスで囲むのは可)
- ルートは {"in": ..., "out": ...} で、必要な場合のみ "activePulse" を加える
- keyframes は 2〜8個、t は 0..1 の狭義昇順で、先頭は必ず t=0、末尾は必ず t=1
- keyframe に書けるのは t, alpha(0..1), scale(0.1..3), scaleX(0.1..3), scaleY(0.1..3), dx(-2..2), dy(-2..2), rotate(-360..360), tint(0..16777215), strokeWidth(0..20), strokeColor(0..16777215), glow(0..40), glowColor(0..16777215) のみ。単位: dx/dy は文字サイズ比(正=右/下)、rotate は度、strokeWidth/glow は px、色は 0xRRGGBB の整数
- **変えたくないプロパティは書かない**。tint を書くと歌唱に合わせた色替えが止まり指定色で固定される。strokeWidth/strokeColor を書かなければスタイルの縁取りがそのまま残る(書かない = 0 ではない)
- 光らせたいときは glow(オフセットのない発光)を使う。glowColor を省くと文字色で光る
- 潰して伸ばす動き(squash & stretch)は scaleX と scaleY を逆方向に動かして作る
- durationMs(整数 50..4000) / stagger.delayMs(整数 0..500) / activePulse.periodMs(整数 200..4000) を守る。stagger は unit("none"/"char"/"word")・delayMs・from("start"/"end"/"center") の3つすべて必須
- easing は仕様書のイージング一覧にある31種の名前のみ(厳密一致)
- out の t=0 の keyframe は恒等値(alpha 1, scale 1, dx 0, dy 0, rotate 0 に相当)にする
- 存在しないプロパティ・コメント・末尾カンマ・式を書かない
作りたい動き:
{ここに作りたい動きを書く}
(既存のアニメーションを修正したい場合のみ、以下に現在の JSON を貼ってください。新規作成の場合はこの節ごと削除してください)
現在の JSON:
{現在の JSON}
ここまでコピー