GraphicSpec 仕様書 — 自作の「背景エフェクト」
この文書は movlyric の背景エフェクト(歌詞の背後に図形・線を描く)の定義「GraphicSpec」の完全仕様です。 アプリの「スタイルエディタ →「背景」タブ → 背景エフェクト →「カスタム」→ AIで作る…」から使います(歌詞の文字そのものを動かす「文字の動き」は別物で、 そちらは ANIMATION_SPEC(文字の動き) が仕様です)。 この文書だけを読んだ AI(または人間)が、アプリにそのまま貼って通る JSON を書けることを目的とします。 文書末尾に AI へ渡すプロンプトテンプレートがあります。この文書全体をプロンプトの一部として貼り付けても機能します。
1. 概要
背景エフェクトは、歌詞の背後で動くモーショングラフィックです(歌詞そのものの動きは別仕様の AnimationSpec が扱います)。
GraphicSpec は「同じ形の図形を N 個並べて動かす」という形で書きます。図形は円・長方形・線・多角形の4種類です。
各図形の位置・大きさ・色・不透明度は、2通りの書き方で決められます。
- 定型の合成(
基準値 + 乱数 + 正弦波 + 流れ + 音)— 短く書ける - 数式 —
0.5 + sin(t * 2 + i) * 0.2のように自由に計算できる。条件分岐や、直前の図形の位置を参照した連鎖配置も書ける
数式は JavaScript ではありません。代入・ループ・関数定義は書けず、1つの式が1つの数値を返すだけです(表計算の数式と同じ考え方)。使える名前は §2.6 の一覧に限られます。
2. JSON 形式の完全仕様
2.1 ルート: GraphicSpec
{ "layers": [ <Layer>, ... ] }
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
layers |
Layer[] | 必須 | 1〜4個。先に書いたレイヤが奥、後が手前に描かれる |
ルート直下に書けるキーはこれだけです。
2.2 Layer
| フィールド | 型 | 必須 | 値域 | 説明 |
|---|---|---|---|---|
shape |
文字列 | 必須 | "circle" / "rect" / "line" / "polygon" |
図形の種類 |
count |
整数 | 必須 | 1〜200 | 図形の個数 |
sides |
整数 | 任意 | 3〜24 | polygon の頂点数(省略時 5)。他の shape では無視 |
star |
数値 | 任意 | 0〜1 | polygon の星形度。0=正多角形、0.5 で標準的な星。他の shape では無視 |
when |
文字列 | 任意 | 数式 | 描画条件。0 と評価されたインスタンスは描かない(§2.6) |
spread |
文字列 | 任意 | §2.4 | 個数ぶんの初期配置。省略すると全部同じ位置に重なる |
x |
Value | 必須 | — | 横位置。画面幅に対する比(0=左端、0.5=中央、1=右端) |
y |
Value | 必須 | — | 縦位置。画面高さに対する比(0=上端、1=下端) |
size |
Value | 必須 | — | 大きさ。画面高さに対する比。circle=半径 / rect=高さ / line=長さ |
aspect |
数値 | 任意 | 0.01〜100 | rect の横幅 = size × aspect。line では太さに効く。circle では無視 |
rotation |
Value | 任意 | — | 回転(度)。circle では無視 |
color |
文字列 or 整数 | 必須 | §2.5 | 色 |
alpha |
Value | 必須 | — | 不透明度。0〜1 にクランプされる |
wrap |
真偽 | 任意 | — | true で画面外へ出た図形が反対側から現れる(流れ続ける表現) |
2.3 Value(値の決め方)
書き方は3通りあります。
| 書き方 | 例 | 用途 |
|---|---|---|
| 数値 | "x": 0.5 |
定数 |
| 数式(文字列) | "x": "0.5 + sin(t) * 0.2" |
自由な計算・条件分岐・前の図形への依存(§2.6) |
| オブジェクト | 下記 | 「基準値+乱数+波+流れ+音」の定型合成 |
迷ったら数式が書きやすいです。 オブジェクト形式は定型の組み合わせを短く書くための形です。
数値をそのまま書けば定数です("x": 0.5)。オブジェクト形式は次のとおりです。
{
"base": 0.5,
"random": [-0.2, 0.2],
"wave": { "amplitude": 0.05, "periodMs": 3000, "phaseByIndex": 0.7 },
"drift": -0.1,
"audio": { "band": 2, "scale": 0.3 }
}
| フィールド | 型 | 必須 | 値域 | 説明 |
|---|---|---|---|---|
base |
数値 | 必須 | — | 基準値 |
random |
[数値, 数値] | 任意 | — | この範囲の乱数を base に足す。図形ごとに違う値になる(毎回同じ絵になる決定論的な乱数) |
wave |
オブジェクト | 任意 | — | 正弦波で揺らす(下記) |
drift |
数値 | 任意 | — | 時間で線形に動く量(1秒あたり)。負で逆方向 |
audio |
オブジェクト | 任意 | — | 音に反応させる(下記) |
wave
| フィールド | 型 | 必須 | 値域 | 説明 |
|---|---|---|---|---|
amplitude |
数値 | 必須 | — | 揺れ幅 |
periodMs |
整数 | 必須 | 50〜60000 | 1往復にかかる時間(ミリ秒)。小数不可 |
phaseByIndex |
数値 | 任意 | — | 図形ごとに位相をずらす量。省略すると全部が一斉に同じ動きをするので、ばらけさせたいときは 0.3〜1.0 程度を入れる |
audio
| フィールド | 型 | 必須 | 値域 | 説明 |
|---|---|---|---|---|
band |
整数 | 必須 | 0〜63 | 周波数バンド。0 が最低音(キック)、数字が大きいほど高音 |
scale |
数値 | 必須 | — | バンドのレベル(0〜1)に掛けて base に足す量 |
低音に反応させるなら band は 0〜3、中音は 8〜16、高音は 24 以上が目安です。
2.4 spread(初期配置)
x/y の値に加算されます。
| 値 | 配置 |
|---|---|
"none"(省略時) |
全部同じ位置。random で散らす前提のときに使う |
"random" |
画面全体にランダムに散らす(毎回同じ配置になる決定論的な乱数) |
"row" |
横一列に等間隔 |
"column" |
縦一列に等間隔 |
"ring" |
円周上に等間隔 |
"spiral" |
中心から外へ渦を描く(黄金角刻みで重なりにくい) |
"grid" |
正方に近い格子 |
2.5 color(色)
パレット参照を推奨します。 ユーザーが配色を変えたときエフェクトも一緒に変わります。
| 値 | 意味 |
|---|---|
"text" |
文字色 |
"accent" |
強調色(サビの色) |
"stroke" |
縁取り色 |
| 整数 | 0xRRGGBB の直値(例: 赤 = 16711680)。文字列の "#ff0000" は不可 |
2.6 数式
値のところに文字列を書くと数式になります。200文字までです。
{ "x": "0.5 + sin(t * 2 + i * 0.5) * 0.2" }
使える変数
| 名前 | 意味 |
|---|---|
t |
経過秒 |
at |
音の経過秒(音に反応させるときはこちら) |
i |
この図形の番号(0 から) |
n |
図形の総数 |
p |
i/(n-1)(0〜1 に正規化した位置。n=1 では 0) |
beat |
拍の進行 0〜1(0 が拍の頭) |
energy |
セクションのエネルギー 0〜1 |
chorus |
サビ中なら 1、そうでなければ 0 |
aspect |
画面の縦横比(幅/高さ) |
px py psize prot |
直前の図形の位置・大きさ・回転(§2.7) |
PI TAU |
円周率、その2倍 |
使える関数
sin cos tan asin acos atan atan2 abs sqrt exp log sign floor ceil round min max pow hypot mod clamp lerp step smoothstep rand band
mod(a, b)— 常に正の剰余(mod(-1, 3)= 2)clamp(v, min, max)/lerp(a, b, t)/step(edge, v)/smoothstep(e0, e1, v)rand(k)— この図形固有の乱数 0〜1(kを変えると別の系列。毎回同じ値になる決定論的な乱数)band(k)— 周波数バンドkのレベル 0〜1(0 が最低音)
演算子
+ - * / % ^(べき乗)、比較 < <= > >= == !=、論理 && || !、そして三項演算子 条件 ? A : B。
条件分岐は三項演算子で書きます。
{ "size": "chorus ? 0.15 : 0.05" }
書けないもの
変数への代入、ループ、関数定義、文字列は書けません。1つの式で1つの数値を出すだけです。上の表に無い名前(Math、Date、random など)を書くとエラーになります。
2.7 前の図形に依存する計算
px / py / psize / prot は、直前の図形(i-1)の確定値です。これで連鎖・積み上げが書けます。値は画面比のまま渡ります。
{ "x": "px + 0.15", "y": "py + sin(i) * 0.05" }
先頭(i = 0)では 0 から始まります。「1個目だけ別扱い」にしたいときは i で分岐してください。
{ "size": "i == 0 ? 0.1 : psize * 0.8" }
3. よくある間違い(禁止事項)
- 値域違反:
count: 0や300、periodMs: 10や100000、band: 64、layersが 5個以上はすべて不可 - 存在しないプロパティ: Layer に書けるのは §2.2 のもの、Value のオブジェクト形式に書けるのは §2.3 の5個だけ。
speed,opacity,radius,pointsなどは存在しません - 数式に無い名前を書く:
Math.sin(t)は不可(sin(t)と書く)。Date,random,windowなどは使えません - 数式にループや代入を書く:
for,=,letは書けません。1つの式で1つの数値です - 色を文字列で書く:
"#ff0066"や"red"は不可。パレット名か整数 - 小数の禁止箇所:
count/periodMs/bandは整数のみ - 単位の取り違え: x/y/size はピクセルではなく画面比。
"size": 40は「画面高さの40倍」になり画面を埋め尽くします。大きさは 0.01〜0.2 程度が普通です phaseByIndexの付け忘れ: 付けないと全図形が一斉に同じ動きをして、機械的で不自然に見えます- JSON 以外の混入: コメント、末尾カンマは不可(数式は文字列として書けます — §2.6)
4. 作例
いずれもこのままアプリに貼って通る完全な JSON です。
4.1 ふわふわ漂う光の粒
ランダムに散らばった円がゆっくり上へ流れ、横に揺れながら明滅します。画面上端を抜けたら下から再登場します。
{
"layers": [
{
"shape": "circle",
"count": 24,
"spread": "random",
"x": { "base": 0, "wave": { "amplitude": 0.02, "periodMs": 7000, "phaseByIndex": 0.9 } },
"y": { "base": 0, "drift": -0.05 },
"size": { "base": 0.03, "random": [0, 0.03] },
"color": "accent",
"alpha": { "base": 0.18, "wave": { "amplitude": 0.1, "periodMs": 4000, "phaseByIndex": 0.6 } },
"wrap": true
}
]
}
4.2 音に反応するイコライザー
画面下部に並んだ縦棒が、低音から高音まで各バンドのレベルで伸び縮みします。
{
"layers": [
{
"shape": "rect",
"count": 32,
"spread": "row",
"x": 0.5,
"y": 0.95,
"size": { "base": 0.02, "audio": { "band": 4, "scale": 0.5 } },
"aspect": 0.4,
"color": "accent",
"alpha": 0.75
}
]
}
4.3 斜めに流れる線
背景を斜めの線がゆっくり横切り続けます。奥に薄い層、手前に濃い層を重ねて奥行きを出しています。
{
"layers": [
{
"shape": "line",
"count": 14,
"spread": "random",
"x": { "base": 0, "drift": 0.06 },
"y": 0,
"size": { "base": 0.5, "random": [0, 0.4] },
"aspect": 0.03,
"rotation": -24,
"color": "text",
"alpha": 0.06,
"wrap": true
},
{
"shape": "line",
"count": 5,
"spread": "random",
"x": { "base": 0, "drift": 0.11 },
"y": 0,
"size": { "base": 0.7, "random": [0, 0.3] },
"aspect": 0.05,
"rotation": -24,
"color": "accent",
"alpha": 0.14,
"wrap": true
}
]
}
4.4 キックで脈打つ輪
円周上に並んだ点が、低音(キック)に合わせて外側へ広がります。
{
"layers": [
{
"shape": "circle",
"count": 24,
"spread": "ring",
"x": { "base": 0.5, "audio": { "band": 0, "scale": 0.06 } },
"y": { "base": 0.5, "audio": { "band": 0, "scale": 0.06 } },
"size": { "base": 0.012, "audio": { "band": 0, "scale": 0.02 } },
"color": "accent",
"alpha": 0.5
}
]
}
4.5 サビだけ舞う星(条件分岐 + 多角形)
サビの間だけ星形が現れて回ります。when でレイヤごと出し入れし、大きさは拍で脈打ちます。
{
"layers": [
{
"shape": "polygon",
"sides": 5,
"star": 0.55,
"count": 18,
"spread": "random",
"when": "chorus",
"x": 0,
"y": { "base": 0, "drift": -0.03 },
"size": "0.02 + (1 - beat) * 0.015 + rand(0) * 0.02",
"rotation": "t * 40 + i * 20",
"color": "accent",
"alpha": 0.5,
"wrap": true
}
]
}
4.6 連なって伸びる線(前の図形に依存)
1本目から順に、直前の線の終点あたりへ次の線を置いて連鎖させます。px / py を使った例です。
{
"layers": [
{
"shape": "line",
"count": 40,
"x": "i == 0 ? 0.05 : px + 0.022",
"y": "i == 0 ? 0.5 : py + sin(t + i * 0.4) * 0.012",
"size": 0.04,
"aspect": 0.06,
"rotation": "sin(t + i * 0.4) * 40",
"color": "accent",
"alpha": "0.15 + p * 0.5"
}
]
}
5. AI 用プロンプトテンプレート
以下の枠内をコピーして AI に渡してください。この仕様書全体を先に貼り付け、その直後にテンプレートを続ける使い方を推奨します(仕様書なしでテンプレート単体を渡すと AI が値域や単位を誤ります)。
ここからコピー
あなたは movlyric の背景エフェクト設計者です。上に貼り付けた「GraphicSpec 仕様書」に厳密に従い、GraphicSpec の JSON を1つ作成してください。
出力規則:
- JSON のみを出力する(説明文・前置き・後書きは書かない。JSON をコードフェンスで囲むのは可)
- ルートは {"layers": [...]} で、layers は 1〜4 個
- Layer に書けるのは shape, count, sides, star, when, spread, x, y, size, aspect, rotation, color, alpha, wrap のみ
- shape は "circle" / "rect" / "line" / "polygon" のいずれか。polygon は sides(3..24) と star(0..1) を持てる
- count は 1〜200 の整数
- x, y, size, alpha は必須。次の3通りで書ける:
(a) 数値そのまま(定数)
(b) **数式の文字列**(200文字まで)
(c) {"base":..., "random":[min,max], "wave":{"amplitude":...,"periodMs":整数50..60000,"phaseByIndex":...}, "drift":..., "audio":{"band":整数0..63,"scale":...}}
- 数式で使える変数は t, at, i, n, p, beat, energy, chorus, aspect, px, py, psize, prot, PI, TAU のみ
- 数式で使える関数は sin cos tan asin acos atan atan2 abs sqrt exp log sign floor ceil round min max pow hypot mod clamp lerp step smoothstep rand(k) band(k) のみ
- 数式では代入・ループ・関数定義・文字列は書けない。条件分岐は三項演算子 `条件 ? A : B` で書く
- **Math.sin(t) のような書き方は不可**(sin(t) と書く)。Date / random / window などの名前は使えない
- 直前の図形に依存させたいときは px / py / psize / prot を使う(画面比のまま渡る。i=0 では 0)
- レイヤごと出し入れしたいときは when に数式を書く(0 と評価されたら描かれない)
- **x/y/size は画面に対する比**(ピクセルではない)。size は 0.01〜0.2 程度が普通。x/y は 0〜1 が画面内
- color は "text" / "accent" / "stroke" のいずれか、または 0xRRGGBB の整数。文字列の色コードは不可
- 複数の図形を動かすときは wave に phaseByIndex を入れて位相をずらす(付けないと全部が一斉に動いて不自然になる)
- 音に反応させるときは audio を使う。band 0 が最低音(キック)、数字が大きいほど高音
- 画面外へ流し続けるときは drift と wrap:true を組み合わせる
- 存在しないプロパティ・コメント・末尾カンマ・式を書かない
作りたいエフェクト:
{ここに作りたい動きを書く}
(既存のエフェクトを修正したい場合のみ、以下に現在の JSON を貼ってください。新規作成の場合はこの節ごと削除してください)
現在の JSON:
{現在の JSON}
ここまでコピー