跳转至
MIGRATED

Xisound 模块 UI 实现规范 v1.0

文档定位

  • 权威性:所有模块 UI 元素的强制性实施规范。任何智能体或工程师在实现/修改模块 UI 时必须遵守,未遵守视同 PR 不合规(CI 将逐步加入自动校验)
  • 适用范围:XiStudio LinkEditor 画布 + ModuleLibrary 左侧库 + Tuning Dialog 弹窗 + XiForge UI Designer 预览;涵盖所有 DSP 算法模块(source/sink/filter/gain/mixer/...所有 20 类分类)
  • 产生背景:2026-05-08 Source/Sink 重构发现智能体遗漏 8 处 UI 元素(toggle 开关、组件库 icon+名字、画布开关、output port 设定、preset UI 位置、preset 同步、PC/DSP 切换、source 诊断 UI)· 根因是缺失前端 UI 强制规范
  • 上游D3-FE-ARCH-003 共享 UI kit 架构 §2 @xi/ui-kit · D3-FE-ARCH-001 顶层架构 §2.2 三画布分工 · Source/Sink Review v7.0
  • 下游D3-FE-ARCH-008 运行时模式切换 · D3-FE-ARCH-009 Preset 全链路

本文档对智能体的阅读要求

  • 修改模块 UI 代码前必须先读本文档相关章节
  • 提交 PR 前必须通过 §9 自查清单的所有项
  • 规范用 ✅ / ❌ 样板对照,未通过对照即视为不合格

1. 文档使命与根本原则

1.1 为什么需要本文档

现有 frontend_vue3/ 代码中 8 个具体 UI 缺陷反映了前端实施层面缺少统一的强制规范。分散在各处 tech-arch / UI kit 的 API 定义粒度太粗,智能体难以据此产出一致正确的实现。

本文档填补这一空白:

  • 每个模块必须有什么 UI 元素 · 不许少
  • 每个 UI 元素必须放在什么位置 · 不许乱放
  • 每个交互必须走什么数据流 · 不许绕路

1.2 四条根本原则(所有智能体必须认同)

编号 原则 说明
P-01 规范即契约 本文档约束的 UI 元素是产品契约的一部分,不是可选的"美观建议"。删除 toggle、漏图标、漏 preset 入口都属于功能缺失,不是"视觉偏好"。
P-02 所有模块一致 20 类分类下的所有模块(source / sink / gain / filter / eq / ...)在 UI 上共享同一套 Shell 结构(toggle + preset + argument + runtime mode 等)。模块 A 能用 B 也必须能用。
P-03 样式可变,结构不变 允许不同模块的图标/颜色/tooltip 文案不同,但强制元素的位置/存在性不允许省略。比如 toggle 必须在左上角,不能挪到右下角或删掉。
P-04 UI-Param-Preset 三向绑定 用户改 UI → 实时更新 param → 实时保存到 preset 草稿;加载 preset → 恢复 param → UI 自动刷新。三者不能脱节(§5 详述)。

2. ModuleNode 画布卡片 Shell 规范(强制)

2.1 视觉与功能结构

每个画布上的 ModuleNode 必须包含以下 7 个元素,位置固定:

┌───────────────────────────────────────────┐
│ ①toggle  ②icon  ③name                  ⑦⚙ │  ← 顶栏(固定高 24px)
├───────────────────────────────────────────┤
│ ●④输入端口                    ⑤输出端口● │
│ ●                                       ● │  ← 内容区(端口 + 可选波形预览)
│ ●                                       ● │
├───────────────────────────────────────────┤
│ ⑥status: running / idle / error           │  ← 底栏(固定高 18px)
└───────────────────────────────────────────┘
序号 元素 强制 说明
Toggle 开关(左上角) 启停模块 · 读写 linkStore.isModuleEnabled()/setModuleEnabled() · 与 Tuning Dialog 右上角开关双向同步
模块 Icon(toggle 右侧 16x16) 每个模块必须有 icon · 从 moduleLibrary.ts 的 metadata 读取 · fallback 到分类默认 icon
模块名称 + 实例编号(icon 右侧) 格式 EQ #3 / Gain #1 · 文案用 displayName || typeName · 字号 12px
输入端口(左侧排列) moduleDef.ports.inputs 读取 · 端口数量取决于模块定义
输出端口(右侧排列) moduleDef.ports.outputs 读取 · 动态格式信息(channels/sampleRate)可点击查看
运行状态指示(底栏) 颜色+文字:running(绿)/ idle(灰)/ error(红)· 从 audioEngineStore 订阅
快捷设置按钮(⚙,右上角) 点击打开 Tuning Dialog · 双击模块 body 也可

2.2 Toggle 开关的强制实现

<!-- ✅ 正确:ModuleNode.vue 中必须包含 -->
<template>
  <g class="module-node" :class="{ disabled: !isEnabled }">
    <!-- 顶栏 -->
    <g class="top-bar">
      <!-- ① toggle(左上角)-->
      <foreignObject :x="x + 4" :y="y + 4" width="20" height="20">
        <XiSwitch
          :model-value="isEnabled"
          size="xs"
          @update:model-value="onToggleEnabled"
          @click.stop
          :title="isEnabled ? '禁用该模块(旁路)' : '启用该模块'"
        />
      </foreignObject>

      <!-- ② icon -->
      <image :x="x + 28" :y="y + 6" width="16" height="16" :href="iconUrl" />

      <!-- ③ name -->
      <text :x="x + 48" :y="y + 18" class="module-name">
        {{ displayName }} #{{ module.instanceIndex }}
      </text>

      <!-- ⑦ settings -->
      <foreignObject :x="x + width - 24" :y="y + 4" width="20" height="20">
        <button class="icon-btn" @click.stop="openTuningDialog"></button>
      </foreignObject>
    </g>

    <!-- 端口 + 内容区(略) -->

    <!-- ⑥ status -->
    <g class="bottom-bar">
      <circle :cx="x + 8" :cy="y + height - 9" r="3" :fill="statusColor" />
      <text :x="x + 16" :y="y + height - 6" class="status-text">{{ statusText }}</text>
    </g>
  </g>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useLinkStore } from '@/stores/linkStore'
import { useAudioEngineStore } from '@/stores/audioEngineStore'
import { XiSwitch } from '@xi/ui-kit'

const props = defineProps<{ module: ModuleInstance; x: number; y: number; width: number; height: number }>()

const linkStore = useLinkStore()
const audioEngineStore = useAudioEngineStore()

const isEnabled = computed(() => linkStore.isModuleEnabled(props.module.instanceId))

function onToggleEnabled(value: boolean) {
  // 1. 写入 linkStore(同时会通过 WS 发 control-command)
  linkStore.setModuleEnabled(props.module.instanceId, value)
  // 2. Tuning Dialog 如果打开会自动刷新(响应式)
}

const statusColor = computed(() => { /* 从 audioEngineStore 订阅实例状态 */ })
const statusText = computed(() => { /* 同上 */ })
</script>
<!-- ❌ 错误:常见错误示例 -->
<!-- 错误 1:没有 toggle -->
<g class="module-node">
  <text>EQ #3</text>  <!-- 漏掉 toggle ① -->
</g>

<!-- 错误 2:toggle 在右上角(位置错)-->
<foreignObject :x="x + width - 24" :y="y + 4">
  <XiSwitch />  <!-- 必须在左上角 -->
</foreignObject>

<!-- 错误 3:只改本地 state,没同步到 linkStore -->
<XiSwitch v-model="localEnabled" />  <!-- ❌ Dialog 打不开同步 -->

2.3 Icon 资源与 fallback

  • 图标目录packages/ui-kit/src/assets/module-icons/{typeName}.svg(Monorepo)或 src/assets/module-icons/ (单体项目)
  • 命名规则{typeName}.svg · 例:eq-parametric.svg / source-tone.svg
  • 尺寸:24x24 原图 · 使用时 CSS width/height: 16px 缩放
  • Fallback 策略
    • Level 1:具体模块 icon(如 eq-parametric.svg
    • Level 2:分类 icon(如 filter.svg,对应 categoryDefinitions[module.category].icon emoji 渲染)
    • Level 3:通用占位 icon(module-default.svg,灰色方块+类型首字母)
  • 集成点moduleLibrary.tsModuleDefinition 必须有 iconUrl: string 字段 · 没有时由 fallback 逻辑填充

2.4 Status 状态颜色统一

状态 颜色(xi 设计令牌) 场景
running xi.success (#10B981) 模块正在处理音频
idle xi.ink-500 (#6B7280) 链路未启动或模块被 disable
error xi.danger (#EF4444) 模块报错(如加载 wav 失败)
loading xi.warning (#F59E0B) 初始化中(如 source_wav 解码)

3. ModuleLibrary 列表项渲染契约(强制)

3.1 视觉结构

左侧 ModuleLibrary 面板的每个模块卡片必须包含:

┌─────────────────────────┐
│ [Icon]  模块名称         │  ← 必须元素
│         分类 · 简短描述  │  ← 必须元素(副标题 · 灰色)
└─────────────────────────┘
  ↑ hover 时显示完整 tooltip · 拖拽时显示预览
元素 强制 说明
Icon(24x24 或 32x32) 同 §2.3 fallback 策略
模块中文名(主文案) 来自 moduleDef.displayName || moduleDef.typeName · 优先中文(i18n)
分类标签(副文案) categoryDefinitions[moduleDef.category].name 读取
简短描述(副文案继续) 来自 moduleDef.description(单行截断到 30 字)
Tooltip(hover 显示) 完整描述 + 作者 + 版本 + 示例连接图
拖拽预览(drag 时) 半透明 ghost 卡片跟随光标

3.2 正确与错误样板

<!-- ✅ 正确:ModuleLibraryItem.vue -->
<template>
  <div
    class="module-lib-item"
    :draggable="true"
    @dragstart="onDragStart"
    :title="tooltipText"
  >
    <img :src="iconUrl" :alt="moduleDef.displayName" class="lib-icon" width="24" height="24" />
    <div class="lib-text">
      <div class="lib-name">{{ moduleDef.displayName || moduleDef.typeName }}</div>
      <div class="lib-meta">
        <span class="lib-category">{{ categoryName }}</span>
        <span class="lib-desc">{{ truncate(moduleDef.description, 30) }}</span>
      </div>
    </div>
  </div>
</template>
<!-- ❌ 错误:常见反模式 -->
<!-- 错误 1:只显示类型名,没 icon 没描述 -->
<div class="module-lib-item" :draggable="true">
  {{ moduleDef.typeName }}  <!-- 用户看到 "source_wav_v1" 不知道什么意思 -->
</div>

<!-- 错误 2:有 icon 但无 alt/fallback -->
<img :src="moduleDef.iconUrl" />  <!-- iconUrl 未定义时崩溃 -->

<!-- 错误 3:分类信息丢失 -->
<div>{{ moduleDef.displayName }}</div>  <!-- 20 类模块混在一起无法快速筛选 -->

3.3 分类与检索

  • 左侧 Library 必须按 20 类 categoryDefinitions 分组折叠展示(参考 moduleLibrary.ts L46-L67)
  • 顶部必须有搜索框 + 分类筛选 chips + 认证级别筛选(Official/Verified/Community,XiVST 场景)
  • 默认展开 "source" / "sink" / "gain" 三个高频分类,其他收起

4. Tuning Dialog 统一布局规范(强制)

4.1 垂直分区

所有模块的 Tuning Dialog 必须用三段式布局:

┌──────────────────────────────────────────────┐
│ ▲ 顶部:Preset 管理区                         │  ← 强制 · 高度 48-56px
│   [下拉选 preset][保存当前为 preset][删除]    │
│   (预设名)                   [Toggle 开关]   │
├──────────────────────────────────────────────┤
│ ● 中部:Argument 参数区                       │  ← 强制 · 占据主要空间
│                                              │
│   ┌─ 输入参数 ─────────────────────────┐     │
│   │ (参数 1 控件)                     │     │
│   │ (参数 2 控件)                     │     │
│   │ ...                               │     │
│   └───────────────────────────────────┘     │
│                                              │
│   ┌─ 输出端口信息 ────────────────────┐     │
│   │ 通道数: [2 ▾]   采样率: [48000 ▾] │     │
│   │ 数据类型: Float32  |  Block: 64   │     │
│   └───────────────────────────────────┘     │
│                                              │
│   ┌─ 性能监控(可选)────────────────┐     │
│   │ CPU: 2.3%  Memory: 128KB          │     │
│   └───────────────────────────────────┘     │
├──────────────────────────────────────────────┤
│ ▼ 底部:操作区                                │  ← 强制 · 高度 40px
│   [关闭][应用][保存并关闭]        [? 帮助]    │
└──────────────────────────────────────────────┘
区域 强制 说明
顶部 Preset 管理区 所有模块都必须有 · 位置固定在 Dialog 最上方 · 详见 D3-FE-ARCH-009 Preset 全链路
顶部 Toggle 开关 与 ModuleNode 左上角 toggle 双向同步 · 格式:[🔘 启用] 文字+开关
中部 Argument 区 至少分三块:输入参数 / 输出端口信息 / 性能监控(可选)
输入参数块 moduleDef.params 渲染 · 用 <XiPropertyEditor> · 按 group 字段折叠
输出端口信息块 显示每个输出端口的 channels / sampleRate / blockSize / dataType · 可选编辑(对 source 模块)
性能监控块 ⚠️ 可选 Phase 8 后 · CPU/Memory · 错误计数
底部操作区 关闭(丢弃变更)· 应用(写入不关)· 保存并关闭(写入 + 关闭)

4.2 Argument 输入参数块的分组与类型

// moduleDef.params 的 ParamDef schema
interface ParamDef {
  key: string
  label: string
  type: 'number' | 'string' | 'boolean' | 'enum' | 'slider' | 'color' | 'freq' | 'dbGain' | 'file' | 'device'
  defaultValue: any
  min?: number
  max?: number
  step?: number
  options?: Array<{ label: string; value: any }>
  unit?: string
  tooltip?: string
  readonly?: boolean
  group?: string                   // 分组键 · 如 'eq-band-1' / 'advanced'
  groupLabel?: string              // 分组标题
  structural?: boolean             // 是否为结构性参数(见 D3-FE-ARCH-009-preset-lifecycle.md §3)
  realtime: boolean                // 是否支持运行时热更新
  externalBind?: ExternalBindRef  // Signal Flow 绑定(见 signal-flow)
}
  • 每个参数都必须渲染为对应控件slider → XiSlider / enum → XiSelect / freq → 频率输入框(支持 Hz/kHz 单位)/ file → 文件选择器(带 wav 预览)/ device → 设备下拉列表
  • 分组:相同 group 字段的参数聚在一个折叠块 · 默认展开第一组
  • structural 参数:UI 上标红外边框 + 图标 🔒 · hover 提示"修改此参数会重建 DSP 实例"

4.3 输出端口信息块(不可省略)

这是 Bug #4 的根因修复点。每个模块的输出端口必须显示:

┌─ 输出端口信息 ─────────────────────────────────┐
│ out0:  [2ch]  48000Hz  Float32  64 samples    │
│ out1:  [2ch]  48000Hz  Float32  64 samples    │
│ [配置]                                         │
└────────────────────────────────────────────────┘
  • 对 source 模块(source_wav / source_device / source_tone):通道数/采样率 用户可编辑(影响 DSP 初始化)
  • 对其他模块:通道数/采样率 只读显示(由 PortInfo propagation 自动推断,见 Source/Sink Review v7.0 §16)
  • 点击"配置":仅对 source 模块可用 · 展开高级端口设置(声道映射 / blockSize 等)

5. 参数-Preset-UI 三向同步流程(强制 · 核心数据流)

5.1 黄金法则

改参数 → 立即更新 UI + 立即更新 preset 草稿 + 发送 WS control-command 到 DSP 加载 preset → 后端返回 param set → 更新 linkStore.paramValues → UI 响应式刷新

三者不能脱节。以下时序图必须严格遵守:

5.2 用户改参数时(UI → Param → Preset)

sequenceDiagram
    participant User
    participant UI as TuningDialog
    participant Store as linkStore + presetStore
    participant WS as WebSocket
    participant BE as Backend

    User->>UI: 拖动 Gain slider(从 0dB 到 +3dB)
    UI->>UI: 触发 @update:modelValue
    UI->>Store: linkStore.updateParam(moduleId, 'gain', 3.0)
    Store->>Store: 1. 更新 paramValues(响应式 · UI 自动刷新)
    Store->>Store: 2. 标记 presetStore.dirty = true
    Store->>Store: 3. 如果启用 autoSaveDraft · 每 300ms 写 preset draft
    Store->>WS: 4. 发送 control-command {type:'update-param', moduleId, key:'gain', value:3.0}
    WS->>BE: 传递
    BE->>BE: 写入 DSP
    BE-->>WS: ack(可选)

    Note over UI,Store: UI / Store / DSP 三者现在一致
    Note over Store: presetStore.hasUnsavedChanges = true · 标题栏显示 ● 脏标记

5.3 用户加载 preset 时(Preset → Param → UI)

sequenceDiagram
    participant User
    participant UI as PresetDropdown
    participant Store as presetStore + linkStore
    participant WS as WebSocket
    participant BE as Backend

    User->>UI: 选择 preset "Rock Bass"
    UI->>Store: presetStore.loadPreset(moduleId, presetId)
    Store->>Store: 1. fetchPreset → 拿到完整 param set
    Store->>Store: 2. 批量 linkStore.updateParamBulk(moduleId, params)
    Store->>Store: 3. 响应式触发 · UI 自动刷新所有控件
    Store->>WS: 4. 批量 control-command(或 load-preset 专用命令)
    WS->>BE: 传递
    BE->>BE: 批量写入 DSP(淡入淡出避免爆音)

    Note over UI: 所有 slider/select 自动跳到新值
    Note over Store: presetStore.activePresetId = presetId
    Note over Store: presetStore.hasUnsavedChanges = false

5.4 实现要点

  • 单向数据流:UI 永远不保存 local state · 永远 binding 到 linkStore.paramValues(响应式)
  • 批量更新用 updateParamBulk:避免 N 次 WS 调用(每个 slider 单改走 updateParam;preset 加载走 updateParamBulk 一次发送)
  • 淡入淡出由后端负责:前端只管下发新值 · 后端 apply_link 路径自带淡入淡出(见 Source/Sink Review v7.0 §12.3.1)
  • 脏标记 hasUnsavedChanges:在 Tuning Dialog 标题栏显示 · 用户关闭时弹确认框
  • 详细契约:见 D3-FE-ARCH-009 Preset 全链路

5.5 常见错误

// ❌ 错误 1:UI 保存 local state(不同步到 store)
const localGain = ref(0)
function onGainChange(v: number) {
  localGain.value = v  // ❌ store / DSP 都不知道
}

// ❌ 错误 2:只改 store 不发 WS(DSP 不知道)
linkStore.paramValues.set(moduleId, { ...params, gain: v })  // ❌ 漏了 control-command

// ❌ 错误 3:加载 preset 时逐个 update(性能差 + 中间态不一致)
for (const [key, value] of Object.entries(preset.params)) {
  await linkStore.updateParam(moduleId, key, value)  // ❌ 用 updateParamBulk 一次搞定
}

// ✅ 正确
await linkStore.updateParamBulk(moduleId, preset.params)

6. 特殊模块的 UI 补充规范

本节为特定模块类型(非所有通用模块)追加的 UI 要求。

6.1 Source 模块(source_tone / source_wav / source_device)

除通用 Shell 外,额外必须:

元素 强制 说明
波形/频谱预览(内容区中间) ⚠️ 可选 source_wav 必须 · 显示当前 wav 波形缩略图 · 拖动进度条
文件选择器(argument 区) ✅(仅 wav) 支持本地上传 + 服务器文件列表 · 预览时长
设备下拉(argument 区) ✅(仅 device) 实时扫描 WASAPI 设备列表 · 显示当前采样率/通道数
加载状态指示(底栏扩展) loading(解码中)/ ready / error · 配合 §2.4 status 颜色
诊断按钮 🔍(底栏右侧) ⚠️ 强烈建议 点击显示:文件路径 / 解码器 / 内存占用 / 采样率协商日志

修复 Bug #8(wav/device 不出声): - source_wav 加载失败时:status = error(红) + 底栏显示短提示("文件不存在"/"解码失败") + 点击诊断按钮展开详情 - source_device 设备不存在时:status = error + 设备下拉显示最近一次扫描时间戳 + "重新扫描"按钮

6.2 Sink 模块(sink_device / sink_file)

元素 强制 说明
目标设备/文件显示(argument 区) 当前输出到哪里 · 清晰可见
音量标(VU meter)(内容区) 实时显示输出电平 · 每通道一条
wasapi_log.wav 查看按钮 ⚠️ 可选 对 sink_device + debug 模式 · 打开最近的 log 文件

6.3 Mixer 模块

元素 强制 说明
路由矩阵可视化(内容区) N×M 网格 · cell 显示增益 · 点击 cell 修改
矩阵预设(argument 区) 常用预设:identity / stereo-split / surround-downmix

7. 与 Signal Flow 系统的集成点

7.1 参数外部绑定标识

如果某参数的 externalBind 非空(见 D3-FE-ARCH-001 §5.8),在 Tuning Dialog 中:

  • 该参数控件变只读(不可拖动/不可输入)
  • 右侧显示绑定的信号名 + 当前实时值(小字灰色)
  • 悬停显示"已绑定到 Signal Flow"+ 跳转链接
┌─ 输入参数 ──────────────────────────────────────┐
│ Gain:  [----●---------]  +3.0 dB   [🔗 unbind] │
│        (锁定) bind to: vehicle.speed.smoothed  │
│                        实时值: 0.62 (80 km/h)  │
└─────────────────────────────────────────────────┘

7.2 Signal Flow 不影响 UI Shell 结构

即使启用了 Signal Flow 绑定,ModuleNode 卡片 Shell 的 7 个强制元素(§2.1)依然必须全部存在。只是 argument 区的某些参数显示为只读。


8. 可访问性(a11y)与 i18n 要求

  • 键盘导航:Tab 顺序:toggle → settings → argument 区控件 → 底部操作
  • ARIA 标签:toggle 用 <input type="checkbox" role="switch"> 或等效 ARIA · 所有图标按钮必须有 aria-label
  • i18n:所有文案走 @xi/store-core 的 useI18nStore · 禁止硬编码中文/英文
  • 对比度:所有文字对比度 ≥ WCAG AA(正常文本 4.5:1,大文本 3:1)
  • 颜色不作为唯一信息:status 除颜色外还有文字标签("running"/"error")· 色盲友好

9. 智能体提交 PR 前自查清单(强制)

修改任何模块 UI 代码后,提交 PR 前必须逐项确认:

9.1 ModuleNode(画布卡片)

  • 左上角有 toggle 开关
  • Toggle 与 Tuning Dialog 右上角开关双向同步(在 Dialog 里改 Toggle,画布立即响应;反之亦然)
  • 有模块 icon(fallback 链完整)
  • 有模块名称 + 实例编号(EQ #3 格式)
  • 输入输出端口完整渲染
  • 底栏有 status 指示(颜色 + 文字)
  • 右上角有设置按钮 ⚙(点击打开 Tuning Dialog)
  • Disabled 状态视觉区分(整体半透明或灰色叠加)

9.2 ModuleLibrary(左侧库)

  • 每个模块卡片有 icon(24x24)
  • 显示模块中文名 + 类型名
  • 显示分类标签 + 简短描述
  • Hover 有完整 tooltip
  • 可拖拽(拖拽时 ghost 预览)
  • 按 20 类分类分组折叠
  • 顶部有搜索框 + 分类筛选

9.3 Tuning Dialog(弹窗)

  • 顶部有 Preset 管理区(下拉 + 保存 + 删除 + 脏标记●)
  • 顶部右侧有 Toggle 开关(与 ModuleNode 同步)
  • 中部有 Argument 区(输入参数 / 输出端口信息 / 性能监控)
  • 输出端口信息完整(通道数/采样率/dataType/blockSize)
  • Argument 参数按 group 分组折叠
  • structural 参数视觉标红 + 🔒 图标
  • 底部有操作区(关闭/应用/保存并关闭)
  • externalBind 的参数视觉锁定 + 显示绑定信号名与实时值

9.4 数据流(三向同步)

  • UI 改参数立即更新 linkStore.paramValues
  • UI 改参数立即发 WS control-command
  • UI 改参数立即标记 preset dirty(● 脏标记)
  • 加载 preset 用 updateParamBulk(批量)
  • 加载 preset 后 UI 所有控件自动刷新到新值
  • 无 local state(UI 永远 bind 到 store)

9.5 Source/Sink 特殊

  • source_wav 有波形预览 + 加载/错误状态
  • source_device 有设备下拉 + 重新扫描按钮
  • 加载失败时 status=error(红)+ 底栏诊断按钮
  • sink_device/sink_file 有 VU meter 实时显示

9.6 可访问性

  • 所有图标按钮有 aria-label
  • Toggle 用 role="switch"
  • 所有文案走 i18n(无硬编码中英文)
  • 键盘 Tab 顺序合理
  • 对比度 ≥ WCAG AA

任何一项不通过,PR 必须修改后重新审核。


10. 版本与变更记录

版本 日期 作者 说明
v1.0 2026-05-09 work-cline 初稿 · 修复 2026-05-08 发现的 8 个 UI 缺陷 · 建立模块 UI 统一规范 · 核心:ModuleNode 7 元素 + ModuleLibrary icon+name + Tuning Dialog 三段式 + 三向同步时序 + 9 项自查清单

附录 A · 引用

上游: - D3-FE-ARCH-001 顶层架构(§2.2 三画布分工 · §5.8 Signal Flow) - D3-FE-ARCH-003 共享 UI kit 架构(§2 @xi/ui-kit 组件 API) - Source/Sink Review v7.0(§4.6 source/sink · §11.5 参数分类 · §16 PortInfo propagation)

同级(实现规范束): - D3-FE-ARCH-008 运行时模式(PC/DSP)切换规范 - D3-FE-ARCH-009 Preset 全链路规范

下游: - 各 app tech-arch(D2-P1 XiStudio / D2-P6 XiTune / D2-P9 XiForge 等)具体落地本规范 - Phase 8.5 实现时强制遵守本规范(见 D3-FE-ARCH-004 §2.10a PLAN-011

规范引用: - MD 写作规范 v1.1 - 文档编号规范 v1.0 - 文档代码同步政策 v1.0(D3 层 Docs-First 初稿)