# ============================================================
# UI Morph Motion Prompt — Agent-Readable Spec
# ============================================================
# 说明:
# - 本文件是给 agent 执行的结构化规格。
# - 所有 # 注释用于解释字段语义,不是用户原始输入。
# - 所有键值必须被解析;执行顺序见 start.order。
# ============================================================
start:
# 启动流程:先收集输入,再展示节拍网格,最后才写代码。
order:
- "Ask me for the inputs."
- "Then show me the state list on the beat grid before you write any code."
inputs:
# 必须向用户询问以下三项,不得默认。
ask_for:
- key: ui_states
# 用户想要的 8 到 12 个 UI 状态;形状要变成这些形态。
count: "8 to 12"
examples:
- "button"
- "loader"
- "player"
- "slider"
- "toggle"
- "tabs"
- "chart"
- "command palette"
- "toast"
- key: color
# 纯黑白,或一个强调色。
allowed: "pure black and white or one accent color"
- key: song
# 约 120 BPM 的免版税歌曲,可商用。
bpm: "around 120"
license: "royalty-free"
commercial_use: true
example: "Mixkit"
direction:
# 视觉与动效总方向。
quality: "Dribbble-level UI motion"
shape:
# 一个形状,绝不切开;每个状态都是同一元素 morph 尺寸、圆角、颜色。
one_shape: true
never_cut: true
morph_properties: ["size", "radius", "color"]
content_swap: "short blur"
interaction:
# 光标驱动所有变化,包含真实点击和拖拽。
driver: "cursor"
events: ["real clicks", "real drags"]
visual:
# 暖灰画布,黑白组件,Geist 字体。
canvas: "light warm-gray"
components: "black and white"
font: "Geist"
motion:
# 全部用弹簧,最多轻微过冲。
easing: "springs everywhere"
overshoot: "tiny at most"
camera:
# 相机缩放,让每个状态填满画面。
behavior: "zoom so each state fills the frame"
loop:
# 最后一帧等于第一帧,形成无缝循环。
last_frame_equals_first: true
banned:
# 禁止项。
- "bouncy easing"
- "particle bursts"
- "glows"
- "gradients on UI chrome"
- "mismatched icon strokes"
- "dead time"
- "anything that looks like a template"
structure:
# 节奏与状态链。
bpm: 120
bars: 7
density: "something happens on every beat"
sequence:
# 必须按此顺序出现。
- "button"
- "loader"
- "check"
- "dynamic island"
- "music player with a play/pause morph"
- "scrub the progress bar"
- "it becomes a volume slider that stretches when dragged past max"
- "a toggle flips on the beat"
- "the knob becomes a liquid tab indicator"
- "the tabs open into a chart that draws itself, with a tooltip on hover"
- "it collapses into ⌘K"
- "type to filter"
- "enter"
- "toast"
- "back to the button"
build:
# 实现约束。
rules:
- id: 1
rule: "One HTML file, square 1440x1440."
detail: "Every style is computed from time inside seek(t): no CSS transitions, no timers, no state carried between frames."
- id: 2
rule: "Springs are closed-form step responses."
detail: "A value that changes target many times is the sum of one spring per change, so it stays a pure function of time."
- id: 3
rule: "The tab indicator's two edges ride different springs, so the leading edge stretches ahead of the trailing one."
detail: "Same trick for the toggle knob."
- id: 4
rule: "Drags are direct manipulation: while the cursor is held, the value is computed from its position."
detail: "On release it springs back from wherever it was."
- id: 5
rule: "Analyze the song with numpy for the beat grid and start on a downbeat."
detail: "Place every UI sound by its measured peak."
- id: 6
rule: "Render with Playwright: 4 subframes per frame, blended with ffmpeg tmix for motion blur at 60fps."
- id: 7
rule: "Render one frame per beat before the full render."
detail: "Fix anything off the grid, cramped or hard to read."
gotchas:
# 易错点。
- "Never put will-change on anything the camera scales or the text renders blurry."
- "Text that swaps inside a morphing container needs its own enter and exit timing or it overlaps."
- "Make the last frame identical to the first, cursor position and speed included, or the loop stutters."