Stitch 交付的 DESIGN.md 设计系统已落地到本项目 (
static/style.css+ canvas 绘制配色),结构与交互仍是本项目自己的框架(canvas 时间线 / pointer 拖拽 / 三文件零依赖)。落地与未落地:已落地
- 颜色 token 全套(表面分层 Tier0–3 / 功能色语义),DOM 与 canvas 共用同一套值
- 字体 Inter + JetBrains Mono(字体栈 + 在线加载,离线自动回退系统字体)
- 结构高度与规范一致:菜单 26px / 走带条 34px / 轨道行 88px / 状态栏 24px
- 0–2px 圆角、1px 结构边框、内凹井(读数/输入)、浮层阴影;按钮/输入/滑块/复选全套重画
- 功能色落到真实功能:静音红
#ef4444/ 独奏黄#eab308/ 吸附绿#22c55e/ 自由变调紫#a855f7/ 滑音橙#f97316/ whip 青#2dd4bf/ 选中蓝#3b82f6/ 播放头玫红#f43f5e- 轨道身份色标(面板左侧 4px + 序号
01/02),用低饱和标签色(规范禁止拿功能色做装饰)- 钢琴窗音符 = 半透明填充 + 1px 描边;滑音键保留橙色滑音轨迹线;键盘黑白键对比拉开
- 静音 / 被独奏压掉的轨道素材自动变暗到 38%
- 状态栏拆成"左=消息 / 右=快捷键提示(截断)",读数与数字全用等宽 + 表格数字
有意未落地(框架优先)
- Stitch 版是"TRACK INSPECTOR 列表 + TRACK HEADER 列 + CHANNEL STRIP"三段式布局; 我们仍是"左侧轨道面板 + 单一 canvas 时间线",避免动交互模型
- 图标仍用字符(🧲/🌀 已去色当单色图标);换 SVG 图标集是下一步
- 第二工具栏(POINTER/SPLIT/ENVELOPE 工具模式)、automation 子通道折叠、旋钮(Knob)、VU 表、 迷你钢琴卷缩略图:未做(当前靠快捷键 + 右键菜单,无模式切换)
用途:把当前界面按功能拆成组件,标清每个组件的职责、状态与交互,方便重做一套更现代的视觉。 技术约束见第 6 节(时间线是 canvas 绘制,不是 DOM,视觉可以重做但别改成"每个块一个 div")。
人力 VOCAL 多轨音频编辑器(本地跑在浏览器里,Linux 原生,不走 Wine)。 核心工作流:导入人声素材 → 用 MIDI 音符矫正/接管人声音高(FL 式滑音:一个长音上叠多个滑音键)→ 调音量/声像/FX → 混音导出。 次要工作流:素材块裁剪/拉伸/变调、复制粘贴、轨道级"自由变调"(不跟 MIDI)。
使用者画像:做人力 VOCAL(鬼畜调教/翻唱对齐)的创作者,长时间盯屏、高频拖拽、键盘优先、讨厌等待与误触。
| 层 | 名称 | 高度 | 说明 |
|---|---|---|---|
| 1 | 菜单栏 | ~26px | File / Edit / View 三个下拉 + 右侧工程名 |
| 2 | 工具栏 | ~34px | 走带、位置读数、BPM、吸附、网格、循环、缩放、总音量、引擎标识(单行,会换行) |
| 3 | 主体 | 自适应 | 左:轨道面板(240px) · 右:时间线 canvas + whip 连线层(SVG) |
| 4 | 状态栏 | ~24px | 单行消息(操作反馈/报错),蓝=信息 红=错误 |
| 5 | 浮层 | — | ① 右键菜单 ② 轨道 FX 面板 ③ 钢琴窗(全屏) ④ 拖文件提示覆盖层 |
File:导入音频/媒体(多选,mp3/m4s/mp4/webm…)、导入 MIDI、保存工程(下载 .json)、打开工程、导出混音、新建空工程、加载演示工程Edit:撤销/重做、在播放头切开、删除、变调 ±1、重置变调/拉伸、应用所有 whipView:放大/缩小/适应工程、网格刻度 6 档- 右侧:当前工程文件名(灰、右对齐)
| 组件 | 功能 | 状态 |
|---|---|---|
| ▶ ⏸ ⏹ | 播放/暂停/停止 | 播放中 ▶ 可高亮 |
| 位置读数 | 小节.拍.十分位 | 秒(等宽字体) |
每帧刷新 |
| BPM 数字框 | 20–300,改 BPM 会让"跟随BPM"的轨按节拍变速变位 | — |
| 🧲 吸附开关 | 开=拖拽吸附网格 / 关=自由拖 | 开(绿)/关 两态,与钢琴窗内 🧲 同状态双向同步 |
| 网格下拉 | 1拍 / 1/2拍 / 1/4拍 / 1/8拍 / 1秒 / 帧(30fps) | 主时间线用;钢琴窗有自己独立的一份 |
| 循环勾选 | 播放是否在循环区内循环 | — |
| - + 适应 | 时间轴缩放 | — |
| 总音量 | 0–1.5 滑条 | — |
| 引擎标识 | 引擎: world+rubberband 之类 |
只读信息 |
一行的组成(从上到下 3 行):
- 轨道名输入框 + 🌀 whip 拖拽把手(仅当该轨有 MIDI 块时出现)
- 音量滑条(0–1.5)
- 声道滑条(-1 左 ~ +1 右) + 一排小按钮:
±(自由变调轨)♩(跟随BPM)FXM(静音)S(独奏)✕(删除空轨)
- 状态:
♩/FX/±/M/S都是"点亮=开"的小按钮;M 红、S 黄、♩ 绿、± 紫、FX 橙 - 整行右键 → 轨道菜单:
自由变调轨(带✓)、跟随 BPM(带✓)、断开本轨发出的 whip、删除轨道 - 🌀 交互:按住拖到目标轨=建立接管;右键=断开;单击只提示(防误触)
- 面板与时间线垂直滚动同步
- 标尺条(34px):小节线+小节号(4/4)或整秒;点/拖=定位播放头;Shift+拖=划循环区
- 循环区:半透明蓝覆盖 + 上下把手
- 轨道行:交替底色 + 分隔线
- 轨道行(左侧 240px 面板):编号
01/02… + 名称 + 音量/声道滑块 +±(自由变调轨)♩(跟随BPM)FXMS✕+ MIDI 轨才有🌀(whip 拖拽把手)- 上下拖拽换序:拖行内空白或编号 → 青色插入指示线 → 松手换序;换序后 whip 连线立即按新位置重画(连线两端锚在面板右边缘,只在时间线画布里走,不会压到滑块)
- 换序不影响接管关系(whip 按轨道 id 关联),块/钢琴窗跟着行走
- 结构标记带(块底部 11px):暗蓝小节刻度 + transition 标记(红/橙/黄/蓝 按置信度);悬停出
#markTip详情;点击标记 = 在该处切开(与 S/M 分割同一套字段处理) - 音频块:矩形 + 波形缩略 + 名称 + 参数徽标 + 音量线(可拖) + 左上/右上淡化把手 + 左右裁剪把手 + 宽度≥40px 时出现音量/淡化区
- 同轨重叠 = 自动交叉淡化:重叠区画 X(前块淡出 / 后块淡入的交叉斜线)+ 一层淡蓝底色(
rgba(150,172,205,.13));每个重叠区只由后一块画一次(两块算出的区间完全相同)。语义见 README「同轨自动交叉淡化」——重叠区不是两遍叠着放,而是只有一路声音- 徽标集合(同一行文字拼接,这是信息密度的关键,视觉需要重新组织):
[Pitch +2](算法变调量)、[Rate 0.94](拉伸率)、[MIDI接管](正被 MIDI 接管)、[脱离MIDI](块级不接管)、[自由变调轨]、[循环源](素材回绕)、渲染中… - 选中共 2 态:未选(暗蓝)/ 选中(亮蓝+亮边框);多选=同一个"选中"高亮
- 徽标集合(同一行文字拼接,这是信息密度的关键,视觉需要重新组织):
- MIDI 块:紫色块 + 内部音符缩略图(自动按音高范围压缩到行高)+
[MIDI][转调-4]徽标 + 右缘加长把手 - 播放头:红色竖线 + 顶部小三角
- 框选:蓝色虚线框(右键拖拽触发)
- 横向滚动条:底部 12px
- whip 连线(SVG 覆盖层):从源轨 🌀 出发的贝塞尔曲线 → 目标轨左侧绿点+横杠;拖拽中显示黄色虚线草稿;落点轨道高亮绿框
头部(单行):标题 钢琴窗 — 块名 [转调+n] · 块头 4.030s (第 3 小节) · 已裁头/缩放 + 滑音 开关 + 🧲 + 钢琴窗独立网格下拉(1拍…1/16拍,1秒,帧) + 试听(chip) 勾选 + 操作提示(单行省略) + ✕
主体(canvas):
- 左侧 钢琴键列(64px):黑白键 + 每 C 标
C4之类 - 顶部 标尺(22px):块内时间(0 = 块头,小节 1 = 块头;MIDI 块彼此离散,每块从自己的 0 开始数;块的绝对位置写在标题里)——点/拖=定位播放头(映射到时间轴绝对时刻,与外侧同步),右键=网格刻度菜单
- 音符区网格:小节线(粗) / 拍线(中) / 细分线(细,太密自动隐藏)
- 音符:普通=紫色矩形 + 右缘把手;滑音键=橙色 + 一条从"当前音高"斜拉到自身音高的滑音轨迹线(越长越平缓);选中=高亮描边
- 播放头:红竖线(映射自外侧播放头;播放中实时跟随,越过右侧 60px 时视图自动滚到 25% 处 —— 与主时间线同一套做法)
- 框选虚线框;底部横向滚动条 交互(键盘/鼠标语义,重做视觉时不能丢):
建/改音符即发声(三角波短音,60ms 节流):空白处按下建音符立刻响、上下拖改音高边拖边响、点左侧键盘列单独听该键。目的:不用看音名也知道自己按的是哪个音。 | 操作 | 行为 | |---|---| | 空白点按 | 新增音符(长度=当前网格) | | 拖动音符 | 移动(横向吸附到时间轴网格;纵向=音高,往上=音高更高)| | 拖右缘 | 拉长(超出块尾时块自动加长)| | Shift + 拖 | 临时忽略吸附做微调 | | Alt + 点 | 删除音符 | | 右键拖 | 框选音符 | | 滚轮 | 上下翻音高 | | Ctrl + 滚轮 | 缩放(20–600 px/s)| | Delete | 删选中音符(只删音符,不碰块)| | Esc | 关窗 |
- 右键菜单(块/轨道共用一套样式):条目 + 分隔线;带
✓的开关项;当前作用数量写进标题(删除 (3 块) [Del]) - 轨道 FX 面板:EQ 低/中/高(±12dB)、合唱(开关+深度+速率)、混响(开关+湿度+衰减)、激励器(开关+量)
- 拖文件覆盖层:虚线绿框 +
松手导入 (ffmpeg 支持的音频/视频/m4s 都行),仅真拖文件时出现 - 网格刻度菜单(钢琴窗标尺右键):7 档,当前项带 ✓
- 音高接管 vs 自由变调:块级
[MIDI接管]/[脱离MIDI];轨级±点亮 +[自由变调轨] - 滑音:钢琴窗橙色键 + 滑音轨迹线(用户主要靠这个判断"滑到哪")
- 渲染中:算法渲染是异步的(几十 ms ~ 几秒),要有进度/等待的可视反馈 + 播放门(渲染没完成不播)
- 循环源:素材回绕的接缝虚线(REAPER 式),要能看出"这里是接缝"
- M/S 与 FX 的实时性:改动立刻影响播放(音量/声像/FX 是活参数)
- 多选:Ctrl+点 / 右键加选 / 右键拖框选,多选后变调/移动/删除作用于全部
- 误触防御:全站禁止文本选中;Delete 在钢琴窗内不碰时间线块
背景 #14171c 时间线底 #12151a 标尺 #1b2027 行交替 #151920 / #171b22
音频块 #2d4257(未选) / #3d5f92(选中) MIDI块 #332b4d / #4a3d6e
音符 #b49ae0(普通) / #f0a030(滑音) 播放头 #ff5555 循环区 #5aa0ff
whip 连线 #7fd4a8 滑音轨迹 #ffd58a 滚动条 #3f5a78
字体 13px system-ui(读数用 ui-monospace) 轨道行高 88px 标尺高 34px 块内容左右把手各 5px
- 主题:深色(长期盯屏);风格偏"工程软件"(信息密度高、边框细、颜色低饱和 + 状态色点亮)
- 字体层级很少:13px 主体 / 11px 标签与徽标 / 10px canvas 内文字
- 时间线 = 单张 canvas(1800×900 里可能上千个块,DOM 方案会卡);面板/菜单/浮层才是 DOM
- 无前端框架:
static/index.html+static/app.js+static/style.css三个文件,改样式只动 CSS 最安全 - 图标现在用字符 emoji(🌀 🧲 ♩ ± ✕ ▶⏸⏹)→ 换成 SVG 图标集是安全的(要同步改
index.html里的字符串) - 交互全走 pointer events + pointer capture(拖拽时鼠标可以飞出元素);不要换成依赖 mouseenter 的方案
- 禁止文本选中(
user-select:none),输入框除外 - 时间线/钢琴窗共用同一套时间坐标(秒 ↔ 小节),视觉重做别引入第二套时间基准,否则"点标尺定位"会失准
Space 播放/暂停 · S 在播放头切开 · Del 删除 · Ctrl+Z/Y 撤销/重做 · Ctrl+C/X/V 复制剪切粘贴 · Ctrl+S 保存工程(下载 json) · Ctrl+A 已屏蔽(防误选)· = - ±1 半音 · + _ ±12 半音 · B / N 设循环区头/尾 · 拖拽时 Shift 忽略吸附 · Alt+拖块=滑动素材内容 / Alt+拖右缘=拉伸 · Ctrl+滚轮 缩放 · 钢琴窗内 Alt+点 删音符、Delete 只删音符
- Design token 先行:颜色/圆角/间距/字号/状态色(选中·警告·渲染中·成功)
- 工具栏 + 轨道面板(信息密度最高、最影响观感)
- 时间线块的层级与徽标体系(现在是"一行文字堆徽标",最值得重新设计:建议改成小色块/图标 + 悬浮详情)
- 钢琴窗(滑音轨迹线是特色,值得做成视觉亮点)
- 浮层面板(菜单/FX/网格菜单)统一质感