GraphicSpec 规范文档 — 自定义"背景特效"

本文档译自日语原版。日语版为正式版本,如有出入以日语版为准。

本文档是 movlyric 背景特效(在歌词背后绘制图形、线条)定义“GraphicSpec”的完整规范。 在应用的“样式编辑器 →“背景”标签 → 背景特效 →“自定义”→ 用 AI 生成…”中使用(让歌词文字本身运动的“文字动作”是另一套体系, 其规范请见 ANIMATION_SPEC(文字动作))。 本文档的目标是:只读过此文档的 AI(或人类)也能写出可以直接粘贴到应用中并被接受的 JSON。 文档末尾附有可交给 AI 使用的提示词模板。将本文档整体作为提示词的一部分贴入同样可以正常使用。

1. 概述

背景特效是在歌词背后运动的动态图形(歌词本身的动作由另一套规范 AnimationSpec 处理)。

GraphicSpec 以"排列 N 个相同形状的图形并使其运动"的形式书写。图形共有圆形、矩形、线条、多边形四种。

每个图形的位置、大小、颜色、不透明度,可以用两种写法来决定。

  1. 定型合成(基准值 + 随机数 + 正弦波 + 漂移 + 音频)— 写法简短
  2. 数学表达式 — 可以像 0.5 + sin(t * 2 + i) * 0.2 这样自由计算,也能写条件分支,以及引用前一个图形位置的链式排布

数学表达式并不是 JavaScript。不能写赋值、循环、函数定义,只能是一个表达式返回一个数值(与电子表格公式的思路相同)。可使用的名称仅限 §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 字符串或整数 必需 §2.5 颜色
alpha Value 必需 — 不透明度,会被截断到 0~1
wrap 布尔值 可选 — 为 true 时,移出画面的图形会从对侧重新出现(用于持续流动的效果)

2.3 Value(值的写法)

有三种写法。

写法 示例 用途
数值 "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 数值 可选 — 随时间线性变化的量(每秒)。负值表示反方向
audio 对象 可选 — 使其对音频作出反应(见下)

wave

字段 类型 必需 取值范围 说明
amplitude 数值 必需 — 摆动幅度
periodMs 整数 必需 50~60000 一次往返所需时间(毫秒)。不可为小数
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" }

不能写的内容

不能写变量赋值、循环、函数定义、字符串。只能用一个表达式得出一个数值。写上表之外的名称(如 Math、Date、random 等)会报错。

2.7 依赖前一个图形的计算

px / py / psize / prot 是前一个图形(i-1)的确定值,借此可以写出链式、堆叠的排布。这些值会保持画面比例原样传入。

{ "x": "px + 0.15", "y": "py + sin(i) * 0.05" }

在开头(i = 0)时从 0 开始。想让"第一个特殊处理"时,请用 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。一个表达式只能得出一个数值
  • 用字符串写颜色:"#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 连绵延伸的线条(依赖前一个图形)

从第一条线开始,依次把下一条线放在前一条线终点附近,形成链式排布。这是使用 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,AI 容易在取值范围或单位上出错)。

以下为复制起点

你是 movlyric 的背景特效设计师。请严格遵循上面贴出的“GraphicSpec 规范文档”,创建一个 GraphicSpec 的 JSON。

输出规则:
- 只输出 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 为必需项,可用以下三种方式书写:
  (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}

复制到此为止