# TVU Design System 回流候选规则 · DRAFT (2026-05-26)

> 来源：Phase B Video Sync 设计交付过程发现的通用规则。
> 状态：**暂不回流 TVU repo** — 用户要先反查 TVU DS 现有规则去重后再决定。
> 下次 review：拿这份对照 TVU DS 真源 (`tvu-design-system` repo) 现有规则，标记每条 ⊕（新增）/ ⊕mod（修改现有）/ ✗（已存在去重）。

---

## A. Component 设计规则（all TVU consumer + library 通用）

### A1. 重复 text override 抽 component property
**规则**：Variant 文本字段（title / subtitle / slot strings / delta / timing）在 ≥3 instances 间需要不同值时，**必须** 定义 component property (TEXT type)，不靠 instance-level override + detach。

**Why**：Instance text override 单次便宜，规模化（10+ instances × 5 字段）维护成本高，detach 后失去 master 更新优势。

**How to apply**：建 component variant 前 estimate 各文本字段在 deliverable 中出现的变值数。阈值 ≥3 → 必抽 property。

**触发点**：今天 12 variants 文本全 inline override，未来若 sibling 产品也消费 Session Row，会变成沉重维护包袱。

---

### A2. 品牌色必须绑 var，禁裸 hex
**规则**：任何使用 TVU brand color (BRAND green / red / blue / orange / 等) 的 fill / stroke / text 必须 `boundVariables.color` 指向 TVU library variable。**绝对禁止** 在 component 或 consumer mockup 写 raw hex。

**Why**：Brand 色在 dark/light mode、品牌迭代时统一切换。Raw hex 漏 var 绑定 = future-broken。

**How to apply**：建 component 或 mockup 前先 query 当前文件可用 TVU vars (`figma.variables.getVariableByIdAsync` + sibling probe)。无对应 var 时找 TVU DS team 加，不要将就 raw hex。

**触发点**：今天 selected stroke 漏绑（fill 绑 `UX/Brand/Match,Hover` 但 stroke 用 raw `{0.184, 0.71, 0.306}`）。修复时绑到 `UX/Brand/Brand` (`3010:102`)。

---

### A3. List row collapsed 高度 = 80px（非 72）
**规则**：TVU consumer 产品 list-row 组件 collapsed state 标准 80px (padding top=16 / bottom=16 / content area 48)。72 是 legacy 偏挤值。

**Why**：80px 留 state pill (19) + 标题 (16) + 副标题 (14, gap 3 = 33) 居中后上下各 ~7px 呼吸。72px 仅 ~3px 呼吸，视觉拥挤。

**How to apply**：所有 monitoring / dashboard / list view consumer 产品 row 高度默认 80。Library 里的 Row component master 也按 80 建。

**触发点**：用户手动改 72→80 验证更舒适。

---

### A4. 新建 component 优先 derive 自现有 mockup
**规则**：项目已含 functional row / card / panel 时，新建对应 component 通过 **clone + mutate** 派生 variant，**不要 from-scratch 重建**。

**Why**：现有 mockup 已通过 review 含正确视觉契约。Clone 自动继承。From-scratch 风险：漏复刻细节（fill var binding / stroke direction / corner radius / shadow / 间距等）。

**How to apply**：build variant 前先 inspect 现有 mockup 找 best-match starting frame → clone + 改差异部分。即使要建 12 variants 也基于 ~5 个 anchor 派生而非全新建。

**触发点**：今天 12 variants 全部从源 M0/M1 row clone 派生成功（5 anchors → 12 variants via clone + mutate）。

---

## B. Stateful list 设计 pattern（monitoring + dashboard console 通用）

### B1. Selected = 3-层 signal
**规则**：Stateful list row 的 selected 视觉必须 **三层组合**：
1. Bound-var 深色 fill（如 dark green for brand-selected）
2. 4px LEFT-only accent stroke（brand color，必须绑 var）
3. Selection-driven action chrome（e.g. remove-control / edit affordance 等仅 selected 显示的 action）

**Why**：单一视觉信号不够稳。Fill 在 dim 屏幕可能看不清；纯 stroke 在边缘视觉 noisy；纯 icon 看不出 row-level select 边界。三层叠加保证任何视觉条件下 user 能 spot selected。

**禁止**：全 border ring (4-edge stroke) — 视觉太重；仅 fill 无 accent — 与 hover 区分弱；仅 icon — selection 边界不明。

**触发点**：M2-M10 全 selected variant 均 3-层。

---

### B2. Inactive ≠ 单态
**规则**：List row "off / stopped / disabled" 状态**至少**分两个子型：
- `Inactive-Idle`（运行过有 history meta：last ran / last delta / reason）
- `Inactive-NeverStarted`（从未运行 / CTA "Set..." prompt / 无 history）

**Why**：两子型 user mental model 完全不同。Idle = "曾经跑过现在停了，可重启"；NeverStarted = "从未配置过，先配再用"。合并成单一 Inactive variant 会丢 bootstrap 引导场景。

**How to apply**：建 monitoring/list component variant 时 state property 不要只 (Active, Inactive)。考虑 (Active, Inactive-Idle, Inactive-NeverStarted) 或类似分型。

**触发点**：原 Phase B 假设 8 variants (state×selected×expanded = 2×2×2)，实际发现 Inactive 必须分两型 → 12 variants。

---

### B3. List 默认行为 = accordion 模型
**规则**：多 stateful 实体 list 默认行为：**仅 selected expanded + 其他全 collapsed + 手动 ▼ 可加扩**。

**禁止**：默认全展开（信息过载）/ hover expand（手抖闪烁）/ 单 expand 不可 user override（power user 受限）。

**Math validation 必做**：container_height ≥ N × collapsed_h + 1 × expanded_h。如不满足 → 加 scroll 或减 N。

**How to apply**：定 list 设计前先列 "1 expanded + N-1 collapsed" + "2 expanded + N-2 collapsed" 两种 size budget。

**触发点**：PM 2026-05-26 确认 + bein sports case (2 sync 并行) 验证多展开。Math: N=4 时 2exp + 2col = 200×2+80×2 = 560 < 575 容器 ✓。

---

### B4. #N 序号语义 must 文档化
**规则**：List items 用 `#N` 标号（如 Sync session #1, Slot #3）时，**必须明确文档化**它是：
- **位置序列 (sequence)**：删除后 renumber（[#1, #2, #3, #4] − #2 → [#1, #2, #3]）
- **稳定名称 (name)**：删除后保留 gap（[#1, #2, #3, #4] − #2 → [#1, #3, #4]）

**默认推荐**：
- Fungible items（如 sync session, generic slot）→ **sequence**
- Identifiable items（如 specific slot binding, channel mapping）→ **name**

**Why**：歧义会导致开发实现错。用户预期 unclear → 删除后 UX 突变 surprise user。

**触发点**：M10 Renumber rule + Design Rules card §13。

---

### B5. Cap chip 位置二义性
**规则**：List 容量计数 chip 在两个位置有不同语义：
- **PP-header 右**（or panel header right）：**informational always-on**，显示当前 / 上限 (e.g. "3/4 sessions")
- **底部 list 区**：**action prompt at cap state**，提示 user 如何继续 (e.g. "Remove one to add another · 4/4 sessions")，**replaces Add CTA**

**关键互斥**：cap state (满额) 下两位置 **不可同时显示**。PP-header chip 在 cap 时移除，仅底部 prompt 留。

**Why**：双 chip 信息冗余 + 视觉重；user 不知该看哪个。

**触发点**：M7 重做时发现原 PP-header 还留着 "Remove one to add another · 4/4" dup chip，删后唯一 source = 底部 prompt。

---

### B6. Trend indicator = icon + 数值颜色配对
**规则**：Delta / metric trend 可视化用 ↑↓ icon 时，**仅 icon 不够**。**数值本身也要染色**：
- 绿色 = good direction (e.g. delta converging ↓)
- 橙红色 = warning direction (e.g. delta diverging ↑)
- 中性色 (无 icon) = stable (within threshold)

**Why**：icon 小 + 易被忽略。数值大字号染色让 user 一眼 grasp 方向。Icon + 数值色 = 双层视觉信号。

**Rule 必须同时描述 icon 触发阈值 + 颜色映射，不要漏写颜色。**

**触发点**：Design Rules card 原 trend rule 仅描述 icon 阈值漏颜色，audit 时发现 + 补。

---

### B7. Destructive confirm dialog = 全屏 scrim + 单 dialog
**规则**：删除 / 危险操作 confirm dialog 真实用户态 = **全屏 scrim + 居中单个 dialog**。

**Scrim 标准样式（user-validated 2026-05-26 M9 终版）**：
- Fill: `{r:0, g:0, b:0}` opacity **0.2**（不是 0.5-0.6，**减黑减重**让后景仍可见）
- Effect: `BACKGROUND_BLUR` **radius 8**（毛玻璃效果，进一步柔化后景）
- 覆盖整个 frame（1920×1080 或对应视图尺寸）
- 我第一版用的 60% 纯黑 **太重**，被用户改成 20% + blur 8 — 这才是 TVU dark-theme console 标准

**Dialog 标准**：
- 用 **TVU `Notification` component instance**（不要 detach 自建）
- 建议尺寸 **480×182**（小而聚焦）—— 不要用 720×320 或更大
- 居中绝对定位（不依赖 auto-layout）

**关键区分**：
- **Mockup artifact**（design 工作区）：可能 2-3 个 dialog variant 并排放显示 variant 状态（如 "OFF session" / "ON session" / hover state）—— 这是 design tool 用法
- **真实用户态**：永远 1 dialog + 全屏遮罩 —— 这是 user 实际看到的

**禁止**：
- 在 spec mockup frame 里把 multi-variant artifact 直接当 user 态 ship
- Scrim 用 50%+ 黑（视觉过重，dark-theme console 与后景 contrast 失衡）
- Scrim 漏 BACKGROUND_BLUR（纯透明色块缺质感）
- Dialog 用 detach 后的 frame（应保持 TVU library 连接）

**How to apply**：dialog mockup 帧要明确标 "user state = ONE dialog with scrim"。Multi-variant 在专门的 "artifact / variants" 区，不进 user-flow frames。

**触发点**：M9 v1 用 1580×474 (含 2 dialog 并排) 当 overlay → user 指出错误 → v2 重做为 720×320 V2 backdrop clone + 60% 黑 scrim → user 进一步改为 480×182 TVU Notification + 20% scrim + blur 8（最终版）。

---

## C. Spec mockup 文件 layout 规则（Figma 文件级）

### C1. Multi-state 必须覆盖「默认 + 越权」
**规则**：List-state mockup 必须同时含：
- **规则默认态**（e.g. accordion: 只 selected expanded）
- **User-overridden 态**（e.g. multi-expand 主动加展 / all-collapsed 主动全收 / over-cap attempt 等）

**Why**：只画默认态 = reader 知道规则但不知道 user diverge 时会怎样。开发实现时遇到 edge case 没参考。

**How to apply**：spec frame 列表要 explicit 列 "default behavior frame" + "user override frames" 各一份。

**触发点**：M5 (default accordion) + M-MultiExp (user multi-expand) + M8 (user all-collapsed) 三态覆盖。

---

### C2. 2-col 阅读 grid for spec 文件
**规则**：Figma section 含 10+ frames 时用 **2-col × N-row** grid layout：
- Col 1 x=section_left + 100
- Col 2 x=col1 + frame_w + 200 gap
- Row pitch = frame_height + 400 (含 state-label 居中 + 上下 breathing)
- 阅读顺序：左→右，上→下 (M1, M2 / M3, M4 / ... / M9, M10)

**Why**：scatter placement / 5-col layout user 难 follow 阅读顺序。2-col 自然 left-to-right top-to-bottom，与 reading habit 匹配。

**Pitch 400 gap 由 state-label h ≈ 148 + 上下各 ~125 padding 推出。**

**触发点**：本 session 原 1280 pitch (gap=200) state-label 上下仅 47px 太挤；改 1480 (gap=400) 后舒适。

---

### C3. State-label = what + why + invariants
**规则**：每个 spec frame 的 state-label **必须含三类信息**：
- **What**：frame 在展示什么（基本场景描述）
- **Why**：why this state matters（业务场景 / user intent / 决策 context）
- **Invariants**：rules being demonstrated（哪些规则在此 frame 体现）

**Why**：只 what = reader 知道画了什么但不知 design intent。Why + invariants 让 label 自带 design rationale，未来 review / dev handoff 不用反查 PRD。

**Bad example**：`M5 · 2 sessions accordion`
**Good example**：`M5 · 2 Sessions · #1 selected expanded · default accordion. Demonstrates rule: only currently-selected row expanded by default (other collapsed). Common when user added a session and switched focus.`

**触发点**：M-MultiExp label 含 "bein sports case (Slot1↔Slot2 + Slot3↔Slot4)" 业务场景 — 这才是 label 该写的样子。

---

## 反查 TVU DS 时建议核对项

```
tvu-design-system/
├── design/conventions/         ← 跟 A 类对照
├── design/patterns/            ← 跟 B 类对照  
└── design/spec-mockup/         ← 跟 C 类对照
```

每条规则在 TVU DS 现有 doc 中可能：
- ✗ **已存在** — 标记 dedupe，本规则不必回流
- ⊕mod **部分存在但需扩展** — 现有规则可补本规则细节
- ⊕ **完全新增** — 现有 DS 无此规则，可直接 PR 进 TVU DS

---

**Next action**：用户反查 TVU DS 现有规则 → 标记每条 ✗/⊕mod/⊕ → 决定回流子集。
