Initial TrueGrowth source import

This commit is contained in:
2026-07-07 09:36:36 +08:00
commit 3b6781d695
2283 changed files with 691996 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
## Context
仓库当前已经具备以下音频相关能力:
- `audio-api-service` 能提交、轮询并提取音频生成结果
- 任务队列可以展示音频任务,并把结果插入画布
- `data/audio.ts` 会把音频包装成 SVG 卡片并作为图片元素插入
但播放行为仍缺失:
- 画布内没有统一的 `HTMLAudioElement` 或播放状态容器
- 音频卡片仅保存 `audioUrl` 和少量展示元数据
- 双击音频元素只会 `window.open(audioUrl)`
同时,`.stitch/screens.json` 中已经存在 `audio-generation-workspace` 参考,明确包含:
- 画布音频节点
- 顶部迷你播放器浮层
- 激活节点的播放态
因此本次设计目标不是重新定义音频工作区,而是把已有生成链和已有设计参考连接成最小可用闭环。
## Goals / Non-Goals
- Goals:
- 让画布中的音频组件节点能直接播放和暂停
- 用一套全局播放状态驱动画布节点动画、节点激活态与顶部浮层
- 让音频节点与顶部浮层更贴近 Stitch 参考中的轻量 HUD 方案
- 避免音频节点在缩放时出现任意方向拉伸导致的样式变形
- 保持实现范围足够小,不引入完整 DAW 或时间轴系统
- Non-Goals:
- 不实现音频编辑器、波形剪辑器、多轨混音
- 不在本次中重构媒体库为完整音频库
- 不直接把 Stitch HTML 当作运行时代码
## Decisions
- Decision: 使用单一全局音频控制器
- 通过一个共享的播放服务或 store 管理当前 `audio element`
- 同一时间只允许一个音频源处于播放状态
- 所有 UI 只订阅共享状态,不各自创建独立播放器
- Decision: 将音频结果升级为专用 Plait 音频节点
- 新增 `audio-node` 元素类型,复用 `Card` / `WorkZone``foreignObject + React` 渲染模式
- 节点自身承载音频标题、封面、波形律动、播放态和进度反馈
- 保留旧 SVG 音频贴图的兼容识别,但新插入路径统一走 `audio-node`
- Decision: 节点内交互优先采用“组件自渲染 + 全局播放器协同”
- 节点本身显示播放按钮、进度和律动反馈
- 顶部浮层是当前播放节点的全局回声,不重复承担全部主交互
- 共享播放服务负责同步节点状态、顶部浮层与错误处理
- Decision: 音频节点保持比例缩放,避免自由拉伸
- 参考 Stitch 里的固定比例音频卡片,而不是通用白板矩形
- 音频节点允许放大和缩小,但缩放过程需保持既定宽高比
- 不暴露会导致封面、波形和时间布局变形的自由四向拉伸体验
- Decision: 节点与浮层默认隐藏技术型模型信息
- `providerTaskId / clipId / clipIds / modelVersion` 继续作为内部元数据保留
- 画布节点和顶部浮层优先展示标题、时长、播放状态和语义信息
- 不在主视觉中突出 `chirp-v3` 或 clip 片段主键等技术字段
- Decision: 顶部浮层是全局播放回声,不是主编辑面板
- 节点是播放源
- 顶部浮层显示当前曲目、进度、切歌和音量控制
- 浮层应避开底部 AI 栏、右侧抽屉和顶部工具区
- Decision: 切歌能力以当前画布中的音频节点队列为基础
- 共享播放服务维护一个按画布顺序同步的临时播放队列
- 顶部浮层的上一首 / 下一首使用这条队列
- 队列只服务当前画布上下文,不升级为跨项目媒体库
- Decision: 异常情况优先采用软失败
- 如果音频 URL 无法播放,保留卡片本身
- 播放失败时给出用户提示,并退出当前播放态
- 不因播放失败破坏已插入的画布资产
- Decision: 在支持的浏览器中使用 Web Audio 频谱分析驱动节点律动
- 通过 `AudioContext + MediaElementAudioSourceNode + AnalyserNode` 从当前播放音源提取实时频谱
- 播放服务输出固定数量的 band 数据和低频脉冲强度,供当前激活节点消费
- 分析链应节流更新,避免把高频频谱刷新传播成整张画布的重渲染
- 如果浏览器或跨域策略不允许频谱分析,节点回退到当前静态/伪随机波形,不阻断播放
## Proposed Runtime Shape
```ts
interface CanvasAudioPlaybackState {
activeElementId?: string;
activeAudioUrl?: string;
activeTitle?: string;
activeClipId?: string;
activePreviewImageUrl?: string;
queue: CanvasAudioPlaybackSource[];
activeQueueIndex: number;
playing: boolean;
currentTime: number;
duration: number;
volume: number;
spectrumLevels: number[];
pulseLevel: number;
error?: string;
}
```
## Implementation Outline
1. 新增共享音频播放状态与控制器
2. 新增 `audio-node` 元素类型、渲染组件和缩放插件
3. 将音频插入链从图片元素切换为 `audio-node`
4. 将音频节点与顶部浮层收敛到 Stitch 对齐的视觉语言
5. 为共享播放服务补齐队列、上一首 / 下一首和音量状态
6. 为当前激活节点补齐实时频谱与低频脉冲
7. 为任务队列与自动插入链保持 clip 元数据透传
## Risks / Trade-offs
- 风险: 播放逻辑散落在画布、任务队列和浮层之间
- Mitigation: 统一走单个播放控制器
- 风险: 组件化节点与画布命中/拖拽交互冲突
- Mitigation: 节点交互尽量走受控按钮与事件透传,避免阻断普通选中与移动
- 风险: 远程音频 URL 失效导致卡片可见但无法播放
- Mitigation: 本次先做错误提示与退化行为,后续再考虑音频缓存
- 风险: 画布点击交互与现有双击逻辑冲突
- Mitigation: 单击处理播放,移除或弱化双击外跳逻辑

View File

@@ -0,0 +1,63 @@
# Change: 增加画布内音频播放闭环
## Why
当前仓库已经支持 Suno 音频生成、任务轮询、任务队列展示以及“插入到画布”的音频结果,但插入后的结果仍然是静态卡片:
- 画布上的音频元素本质上是带 `audioUrl` 的图片元素
- 用户无法在画布内直接播放、暂停或查看播放进度
- 当前双击行为只是打开外部音频地址,无法形成画布内的工作流闭环
- Stitch 中已经存在音频工作区设计参考,但生产代码还没有接入对应交互
这导致“音频作为一等画布资产”的体验在最后一步断开。
## What Changes
- 将当前 SVG 音频贴图替换为真正的画布音频组件节点
- 为画布音频节点增加本地播放/暂停能力、Stitch 对齐的播放态反馈,以及更克制的白板化视觉
- 增加全局唯一的音频播放状态,确保同一时间只有一个激活音源
- 约束音频节点的缩放行为,避免任意四向拉伸破坏组件比例和样式
- 让节点与顶部播放器隐藏技术性生成模型信息,只保留用户可理解的标题、状态和语义信息
- 增加顶部迷你播放器浮层,用于显示当前曲目、进度、切歌和音量控制
- 让当前播放中的音频节点在浏览器支持的情况下使用真实音频频谱驱动波形与律动反馈
- 将画布音频元素与已保留的 `providerTaskId / clipId` 元数据联动,为后续续写、重试和更多音频动作提供基础
- 为播放失败、音频地址失效等异常情况增加前端反馈
## Scope
### In Scope
- 画布音频组件节点插入、渲染和基础缩放
- 保持音频节点缩放时的整体比例和组件节奏
- 画布音频节点单击播放/暂停
- 顶部迷你播放器浮层的增强控制
- 单实例播放管理与激活态联动
- 基础播放进度展示、跳转、切歌和音量调节
- 基于 Web Audio 分析器的实时频谱可视化与软降级
- 任务队列、自动插入和画布元素之间的音频元数据贯通
### Out Of Scope
- 多轨混音或时间轴编辑
- 波形裁剪、片段拼接、infill 编辑器
- 完整的音频素材库管理与下载缓存体系重构
- 全量覆盖 Stitch 设计稿中的所有音频工作区交互
## Impact
- Affected specs:
- `canvas-audio-playback`
- Affected code:
- `packages/drawnix/src/data/audio.ts`
- `packages/drawnix/src/drawnix.tsx`
- `packages/drawnix/src/plugins/with-audio-node.ts`
- `packages/drawnix/src/components/audio-node-element/*`
- `packages/drawnix/src/services/*audio*`
- `packages/drawnix/src/components/task-queue/*`
- `packages/drawnix/src/hooks/useAutoInsertToCanvas.ts`
- `packages/drawnix/src/services/media-result-handler.ts`
## Relationship To Existing Changes
- 建立在 `add-audio-generation-suno-routing` 提供的音频生成与任务结果链路之上
- 参考 `add-stitch-design-workflow` 中已存在的 `audio-generation-workspace` 设计资产,但不会直接运行 Stitch 输出

View File

@@ -0,0 +1,106 @@
## ADDED Requirements
### Requirement: Play Canvas Audio Assets In Place
The system SHALL allow audio assets inserted onto the canvas to be played and paused directly within the workspace.
#### Scenario: Play an inserted audio node on the canvas
- **GIVEN** an audio task has completed and its result has been inserted onto the canvas
- **WHEN** the user activates the audio node
- **THEN** the system SHALL begin playback for that node inside the workspace
- **AND** SHALL not require opening the audio URL in a separate browser tab
#### Scenario: Pause the currently playing audio node
- **GIVEN** a canvas audio node is currently playing
- **WHEN** the user activates the same node again
- **THEN** the system SHALL pause playback
- **AND** SHALL update the node's active playback state accordingly
### Requirement: Render Audio As A First-Class Canvas Component
The system SHALL render newly inserted audio assets as dedicated audio components instead of static SVG image cards.
#### Scenario: Insert a generated audio result as a component node
- **GIVEN** an audio generation result includes a playable URL and metadata
- **WHEN** the result is inserted onto the canvas
- **THEN** the canvas SHALL create an audio-specific element
- **AND** the element SHALL render structured UI such as title, cover, waveform, or play state feedback
#### Scenario: Show playback feedback inside the audio node
- **GIVEN** a canvas audio node is active or currently playing
- **WHEN** the node re-renders
- **THEN** the node SHALL visually reflect the current playback state
- **AND** SHALL not appear as a plain static image thumbnail
#### Scenario: Drive waveform rhythm from the active audio signal when available
- **GIVEN** a canvas audio node is currently playing
- **WHEN** browser audio analysis is available for the active media source
- **THEN** the node waveform and rhythm feedback SHALL respond to the live audio signal instead of only using static decorative animation
- **AND** inactive nodes SHALL not require the same high-frequency visual updates
#### Scenario: Gracefully fall back when audio analysis is unavailable
- **GIVEN** a canvas audio node is currently playing
- **WHEN** browser capabilities or media origin rules prevent live audio analysis
- **THEN** playback SHALL continue
- **AND** the node SHALL fall back to a non-reactive waveform presentation without crashing the workspace
#### Scenario: Keep audio node composition stable while resizing
- **GIVEN** a canvas audio node is selected
- **WHEN** the user resizes the node
- **THEN** the node SHALL preserve its intended component proportions
- **AND** SHALL avoid arbitrary stretching that distorts the cover, waveform, and timing layout
#### Scenario: Hide technical provider details from the main node surface
- **GIVEN** a canvas audio node retains provider metadata for follow-up actions
- **WHEN** the node is rendered in the workspace
- **THEN** the visible node UI SHALL prioritize title, playback state, and user-facing semantic information
- **AND** SHALL not expose technical model or provider identifiers as a primary badge
### Requirement: Provide A Global Canvas Audio Player Overlay
The system SHALL expose a lightweight global playback overlay while canvas audio is active.
#### Scenario: Show the top player while audio is playing
- **GIVEN** a canvas audio asset is currently playing
- **WHEN** playback is active
- **THEN** the workspace SHALL display a compact playback overlay near the top center of the canvas
- **AND** SHALL show at least the current title, play state, and progress
#### Scenario: Control playback queue and volume from the overlay
- **GIVEN** the global playback overlay is visible for a canvas audio asset
- **WHEN** the user uses the overlay controls
- **THEN** the overlay SHALL support previous and next track navigation within the current canvas audio queue
- **AND** SHALL support adjusting playback volume without leaving the workspace
#### Scenario: Close the overlay and stop playback
- **GIVEN** the global playback overlay is visible
- **WHEN** the user closes the overlay
- **THEN** the system SHALL stop the active playback
- **AND** SHALL clear the current active audio state
### Requirement: Preserve Audio Provider Metadata For Follow-Up Actions
The system SHALL preserve provider-level audio identifiers from generation results through task storage and canvas insertion.
#### Scenario: Keep clip identifiers on inserted audio nodes
- **GIVEN** an audio generation result includes provider task and clip identifiers
- **WHEN** that result is inserted onto the canvas
- **THEN** the inserted audio element SHALL retain the corresponding provider task identifier and clip identifier metadata
#### Scenario: Reuse stored provider metadata after task restoration
- **GIVEN** an audio task has been persisted and later restored from storage or sync
- **WHEN** the restored result is inserted or inspected
- **THEN** the restored task result SHALL still expose the provider task identifier and clip identifiers needed for follow-up actions

View File

@@ -0,0 +1,47 @@
## 1. Runtime Model
- [x] 1.1 新增共享音频播放状态与控制器
- [x] 1.2 定义 `audio-node` 元素类型与播放元数据字段
## 2. Canvas Playback
- [x] 2.1 新增音频节点渲染组件与波形/律动视觉
- [x] 2.2 将音频节点点击行为接入播放/暂停
- [x] 2.3 让当前播放节点暴露激活态与进度反馈
- [x] 2.4 将现有双击外跳行为调整为不破坏画布内播放闭环
- [x] 2.5 将音频节点视觉收敛到 Stitch 参考,移除技术型模型信息露出
- [x] 2.6 让当前播放节点的波形与律动优先由真实音频频谱驱动
- [x] 2.7 在音频分析不可用时回退到稳定的静态/伪随机波形
## 3. Canvas Element Model
- [x] 3.1 将音频插入路径从 SVG 贴图切换到 `audio-node`
- [x] 3.2 为音频节点补充基础缩放能力
- [x] 3.3 保留旧音频贴图的兼容识别
- [x] 3.4 将音频节点缩放约束为保持比例的样式安全模式
## 4. Global Player UI
- [x] 4.1 新增顶部迷你播放器浮层
- [x] 4.2 支持基础进度显示、拖动和关闭
- [x] 4.3 播放失败时提供前端提示
- [x] 4.4 支持顶部迷你播放器的上一首 / 下一首和音量控制
- [x] 4.5 将顶部迷你播放器文案与样式收敛到 Stitch HUD 风格
## 5. Data Flow
- [x] 5.1 保证插入画布的音频元素保留 `providerTaskId / clipId`
- [x] 5.2 保证任务队列插入和自动插入路径都能接入播放链
- [x] 5.3 维护当前画布音频节点的播放队列,以支持切歌逻辑
- [x] 5.4 为共享播放服务增加实时频谱与低频脉冲输出
- [x] 5.5 将播放状态订阅收敛为选择式更新,避免频谱刷新放大成全画布高频重渲染
## 6. Verification
- [x] 6.1 验证生成完成后的音频节点可在画布内直接播放
- [x] 6.2 验证顶部迷你播放器会跟随当前播放音频更新
- [x] 6.3 验证同时只会有一个音频源处于播放中
- [x] 6.4 验证音频地址失效时会显示错误而不是无响应
- [x] 6.5 验证等比缩放不会破坏音频节点布局
- [x] 6.6 验证顶部迷你播放器可以上一首 / 下一首切换并调节音量
- [x] 6.7 验证频谱分析可用时当前播放节点会随音乐律动
- [x] 6.8 验证频谱分析不可用时仍可播放且不会导致崩溃