# 2026-05-13 — Layout A-逐行（line-by-line bilingual interleaving）pattern 发现

## 触发任务

给 TVU-SaaS-Dashboard-20230619 文件中 `Option 3 — Design Annotations` frame（node `1781:93`）的 22 个英文 text node 加中文双语。是 Claude Code 之前写的 UX 交付文档英文版，用户要求加 ZH 显示在 EN 右边、用 mockup-conventions §双语支持 的格式。

## 翻车 → 升级路径

**首版（按 §双语支持 当时已有的 Layout A-右）**：所有 22 个 text node 一刀切 append `EN + 2-space + ZH` 到末尾，对单行 node（title / "📐 CALCULATION" / "✋ UX DELIVERY"）效果好——同行内联、ZH 在右侧弱化。但对 9 个多行 body（公式 + bullet 列表）效果不好——ZH 整块接在 EN 全块末尾，从最后一行 EN 右侧开始 wrap，下面继续 wrap 几行。**没有一一对应**。

用户反馈 "看起来效果没有很好，没有一一对应上"，圈出了 4 个 EN bullet 行下面的 ZH 整块。

**第二版（line-by-line 重写）**：把 8 个多 line 的 body 按 `\n` split 成行数组，每行 EN 后接对应 ZH（`EN_line + 2-space + ZH_line + \n` 进下一行）。每个 ZH range 单独套 Noto Sans SC + 小 2px + opacity 0.45。每条 bullet/公式行 EN/ZH 同视框 1:1 对齐。用户满意。

## 新 pattern：Layout A-逐行（line-by-line interleaved）

**形态**：同一 text node 内，按 EN 自然分行（`\n` 或 `•`）拆段，每段后内联 ZH，再 `\n` 进下一段。继承 Layout A-右 的所有规则（同节点 / 2-space 分隔 / Noto Sans SC / 小 2px / opacity 0.45），区别在于"拆 line"。

**适用**：多行 bullet 列表 / 多行公式 / 含 `\n` 的结构化正文。**前提**：EN 已自然分行，且每行 EN+ZH 能塞进容器宽度。EN 是无 `\n` 无 `•` 的整段 prose 时仍走 Layout B（上下分节）。

**反例**：未拆 line 就整块内联（EN 全段 + 2-space + ZH 全段）→ ZH 在 EN 末尾继续 wrap，工程师看不到一一对应。

**技术陷阱**：`node.characters = newChars` 后，Figma 会按位置保留旧字符的样式。如果旧文本（首版）末尾是 Noto Sans SC opacity 0.45，新文本相同位置的字符会继承这个污染。修复：set characters 后先用 `setRangeFontName/Size/Fills` 对 `(0, newChars.length)` 强制 reset 为 EN 样式，再对每个 ZH range 套 ZH 样式。

## 通用教训

1. **设计规范的"内联式"不是单一形态**。Layout A-右 是单行 case 的语法糖，多行 case 需要 A-逐行 sub-form——首版翻车根因是"用单行 case 的规则强套多行 case"。
2. **"一一对应"是双语 UX 交付的核心诉求**，比"格式统一"重要。Layout B 上下分节也满足"双语都有"但破坏视框对齐；A-逐行 在能放下时严格优于 B。
3. **conventions 回流入口很重要**。这次 pattern 没写进 memory / skill / 个人笔记——按 `mockup-conventions.md §回流入口` 用户拍板后直接 commit 到 conventions，未来任何 AI 起 mockup 任务读这章就能命中。

## 回流落点

- 文件：`docs/internal/mockup-conventions.md` §双语支持
- Commit：`f7bbe010`（23 insert / 6 delete）
- 改动：表格新增 1 行（A-逐行）+ 决策树 3 分支 → 4 分支 + 技术实现段补代码骨架 + 视觉优先级段下加 "逐行内联 > 上下分节" 原则 + 反例改写 + 验收清单 + 1 条
