LayoutSpec 仕様書 — 自作の「歌詞の置き方」

この文書は movlyric の歌詞の置き方(レイアウト)の定義「LayoutSpec」の完全仕様です。 アプリの「スタイルエディタ →「配置」タブ → 配置プリセット →「カスタム」→ AIで作る…」から使います。

似た名前の別物が2つあります。取り違えないでください。

何を決めるか 仕様書
歌詞を画面のどこに置くか(この文書) LAYOUT_SPEC(歌詞の置き方)
歌詞の文字がどう動くか(登場・退場・明滅) ANIMATION_SPEC(文字の動き)
歌詞の背後に描く図形・線 GRAPHIC_SPEC(背景エフェクト)

この文書だけを読んだ AI(または人間)が、アプリにそのまま貼って通る JSON を書けることを目的とします。 文書末尾に AI へ渡すプロンプトテンプレートがあります。この文書全体をプロンプトの一部として貼り付けても機能します。


1. 概要

LayoutSpec は「1フレーズぶんの歌詞を画面のどこに、どう並べるか」だけを決めます。 時間で変化する要素は一切ありません(動きは AnimationSpec の担当)。

決まるのは次の3つです。

  1. 場所 — 画面のどの点を基準に置くか(anchors / placement
  2. 組み方 — 横書きか縦書きか、何行まで折り返すか(writing / maxLines / lineGap / scaleMode
  3. くずし — まっすぐ並べずに崩すか(scatter / baselineRotateDeg / path / charScaleRange / focusWord

乱数を使う項目はすべて曲ごとに固定です。 同じ曲・同じスタイルなら毎回同じ結果になり、 プレビューと書き出しも一致します(placement: "random" / scatter / charScaleRange / focusWord.pick: "random" はすべてスタイルの seed から決まります)。


2. JSON 形式の完全仕様

2.1 ルート: LayoutSpec

{
  "writing": "horizontal",
  "anchors": [{ "x": 0.5, "y": 0.5, "align": "center" }],
  "placement": "fixed"
}
キー 必須 意味
writing "horizontal" | "vertical" 横書き / 縦書き(上→下・列は右→左)
anchors Anchor の配列(1個以上) 配置候補
placement "fixed" | "cycle" | "random" フレーズを候補へどう割り当てるか
maxLines 整数 1以上 折返し行数(縦書きは列数)。既定 1 = 折り返さない
lineGap 数値 0以上 行間(列間)。文字サイズに対する比。既定 0.15
scaleMode "fixed" | "fill" fill = 画面幅(縦書きは高さ)いっぱいの大組み。既定 fixed
scatter Scatter 文字ごとの散らし
baselineRotateDeg 数値 フレーズ全体の傾き(度)。既定 0
path Path 直線でない並べ方(横書きのみ
charScaleRange [最小, 最大] 文字ごとの大きさの揺らぎ(横書きのみ
focusWord FocusWord 1単語だけ拡大(横書きのみ

既定値と同じ値のキーは書かないでください。 例えば maxLines: 1scaleMode: "fixed" は 書かずに省略します(省略と同じ意味で、書くと保存内容が無駄に増えます)。

2.2 Anchor(配置候補)

{ "x": 0.5, "y": 0.88, "align": "center" }
キー 必須 意味
x 0..1 画面の左端 0 ~ 右端 1
y 0..1 画面の上端 0 ~ 下端 1
align "start" | "center" | "end" アンカーに対して歌詞をどちら側へ伸ばすか

align は横書きなら左揃え / 中央揃え / 右揃え、縦書きなら上揃え / 中央揃え / 下揃えです。

画面端に置くときは align を合わせてください。 例えば x: 0.08align: "center" を 指定すると、長いフレーズが画面の左へはみ出します。左端に寄せたいなら align: "start" です。

2.3 placement(フレーズごとの割り当て)

意味
"fixed" 常に1個目の候補を使う(候補が1個ならこれ)
"cycle" フレーズ順に候補を巡回する
"random" 候補からランダムに選ぶ(曲ごとに固定)

候補が1個のときは3つとも同じ結果になります。 候補を2個以上書いたときだけ意味を持ちます。

2.4 Scatter(文字ごとの散らし)

{ "offsetRatio": 0.25, "rotateDeg": 8 }
キー 必須 意味
offsetRatio 数値 0以上 位置のずれ幅。文字サイズに対する比
rotateDeg 数値 0以上 回転の振れ幅(度)

どちらも曲ごとに固定です。0.3 / 12 くらいでかなり崩れた印象になります。

2.5 Path(直線でない並べ方・横書きのみ)

{ "kind": "wave", "amplitude": 0.3, "period": 8 }
キー 必須 意味
kind "wave" | "arc" | "steps" 波 / 弧 / 階段
amplitude 数値 振れ幅。文字サイズに対する比
period 数値 0より大 何文字で1周するか。省略時は wave 8 / steps 3

wavearc文字の回転が曲線の接線に追随します(並びに沿って傾く)。 arcperiod を使いません(フレーズ全体で1つの弧を描く)。 複数行のときは各行で独立に適用されます。

2.6 charScaleRange(文字の大きさの揺らぎ・横書きのみ)

[0.85, 1.3]

[最小, 最大] の2要素。文字ごとに曲ごと固定の倍率が決まります。 文字サイズと送り幅の両方に効くので、行幅の計算・折返し・中央揃えも揺らぎ込みで一貫します。

2.7 FocusWord(1単語だけ拡大・横書きのみ)

{ "scale": 1.4, "pick": "longest" }
キー 必須 意味
scale 数値 0より大 対象単語の倍率
pick "longest" | "random" 文字数最長(同数なら先頭)/ ランダム(曲ごとに固定)

charScaleRange と併用すると倍率は掛け算になります。


3. よくある間違い(禁止事項)

  • 縦書きに path / charScaleRange / focusWord を書かない。 engine が横書きでのみ解釈するため、 書いても何も起きません(エラーにもならないので気づけません)。
  • anchors を空配列にしない。 配置先が無くなり歌詞が表示されません。
  • x / y にピクセル値を書かない。 0〜1 の比です(960 ではなく 0.5)。
  • 既定値と同じキーを書かないmaxLines: 1 / lineGap: 0.15 / scaleMode: "fixed" / placement が 実質無意味な候補1個での "cycle" など)。
  • 時間や音に反応する値を書かない。 LayoutSpec に数式・アニメーションはありません。 動かしたいなら AnimationSpec(ANIMATION_SPEC(文字の動き))の担当です。
  • 存在しないプロパティ・コメント・末尾カンマを書かない。

4. 作例

4.1 画面下部に1行(カラオケの定番)

{
  "writing": "horizontal",
  "anchors": [{ "x": 0.5, "y": 0.88, "align": "center" }],
  "placement": "fixed"
}

4.2 上下に振り分けて2行まで折り返す

{
  "writing": "horizontal",
  "anchors": [
    { "x": 0.5, "y": 0.3, "align": "center" },
    { "x": 0.5, "y": 0.7, "align": "center" }
  ],
  "placement": "cycle",
  "maxLines": 2,
  "lineGap": 0.4
}

フレーズごとに上→下→上…と入れ替わります。

4.3 縦書きで右から3列

{
  "writing": "vertical",
  "anchors": [{ "x": 0.82, "y": 0.15, "align": "start" }],
  "placement": "fixed",
  "maxLines": 3,
  "lineGap": 0.5
}

縦書きは上から下へ流れ、列は右から左へ増えます。align: "start" で上端を揃えています。

4.4 画面いっぱいの大組みを斜めに

{
  "writing": "horizontal",
  "anchors": [{ "x": 0.5, "y": 0.5, "align": "center" }],
  "placement": "fixed",
  "scaleMode": "fill",
  "baselineRotateDeg": -6
}

scaleMode: "fill" はフレーズを画面幅いっぱいまで拡大するので、文字数によって大きさが変わります。

4.5 四隅に散らして崩す

{
  "writing": "horizontal",
  "anchors": [
    { "x": 0.2, "y": 0.25, "align": "start" },
    { "x": 0.8, "y": 0.4, "align": "end" },
    { "x": 0.25, "y": 0.62, "align": "start" },
    { "x": 0.75, "y": 0.8, "align": "end" }
  ],
  "placement": "random",
  "scatter": { "offsetRatio": 0.3, "rotateDeg": 12 },
  "charScaleRange": [0.85, 1.3]
}

端のアンカーには alignstart / end で合わせ、はみ出さないようにしています。

4.6 波打たせて1単語を強調

{
  "writing": "horizontal",
  "anchors": [{ "x": 0.5, "y": 0.5, "align": "center" }],
  "placement": "fixed",
  "path": { "kind": "wave", "amplitude": 0.35, "period": 6 },
  "focusWord": { "scale": 1.5, "pick": "longest" }
}

5. AI 用プロンプトテンプレート

この文書全体を貼り付けたうえで、続けて以下を貼ってください。

ここからコピー

あなたは movlyric の歌詞レイアウト設計者です。上に貼り付けた「LayoutSpec 仕様書」に厳密に従い、LayoutSpec の JSON を1つ作成してください。

出力規則:
- JSON のみを出力する(説明文・前置き・後書きは書かない。JSON をコードフェンスで囲むのは可)
- ルートに書けるのは writing, anchors, placement, maxLines, lineGap, scaleMode, scatter, baselineRotateDeg, path, charScaleRange, focusWord のみ
- writing, anchors, placement は必須。それ以外は必要なときだけ書く
- **既定値と同じキーは書かない**(maxLines:1 / lineGap:0.15 / scaleMode:"fixed")
- writing は "horizontal" / "vertical" のいずれか
- anchors は 1〜8 個。各要素は {"x":0..1, "y":0..1, "align":"start"|"center"|"end"}
- x, y は**画面に対する比**(ピクセルではない)。0.5 が中央
- 画面端に寄せるときは align を start / end に合わせる(center のままだとはみ出す)
- placement は "fixed" / "cycle" / "random"。anchors が1個なら "fixed" にする
- scatter は {"offsetRatio":0以上, "rotateDeg":0以上}
- path は {"kind":"wave"|"arc"|"steps", "amplitude":数値, "period":0より大(任意)}
- charScaleRange は [最小, 最大] の2要素
- focusWord は {"scale":0より大, "pick":"longest"|"random"}
- **writing が "vertical" のときは path / charScaleRange / focusWord を書かない**(無視されるため)
- 時間・音・乱数に反応する値や数式は書けない(動きは別仕様の AnimationSpec が担当)
- 存在しないプロパティ・コメント・末尾カンマを書かない

作りたい歌詞の置き方:
{ここに作りたい置き方を書く}

(既存のレイアウトを修正したい場合のみ、以下に現在の JSON を貼ってください。新規作成の場合はこの節ごと削除してください)
現在の JSON:
{現在の JSON}

ここまでコピー