# 05-视听多媒体与产物交互物理学 (/docs/v1/05)

<p align="center">
  [⬅️ 上一篇：第四篇：动效物理学、着色器与环境光影](04-动效物理学、着色器与环境光影.md) · [📚 返回总目录](Claude%20Design%20System%20(CDS).md) · [下一篇：第六篇：系统级桌面架构与协作拓扑 ➡️](06-系统级桌面架构与协作拓扑.md)
</p>

---

## 第五篇：视听多媒体与产物交互物理学 [#第五篇视听多媒体与产物交互物理学]

> **技术领域与英文指代**：`Audiovisual, Lightbox & Artifacts Experience`
> **分析溯源**：基于 **REA (Reverse Engineer Anything) v6.5.0** 提取自 macOS 生产包 `/Applications/Claude.app`（`@ant/desktop v2.37337.1`，Build 时间戳 `2026-10-13T22:16:06Z`），深度解构核心音频驱动 `/Applications/Claude.app/Contents/Resources/ion-dist/audio/voice/`、核心样式资产 `c6a992d55-sXiDGMFQ.css`、画廊与缩放平移算法 `c4b054ed5-BGjH-Uu6.js`、View Transitions 无缝形变 `cd5136de8-BDys1vAN.js`、Epitaxy 隔离沙箱 `c58115fda-BKnbLmi3.js` 以及代码流式高亮引擎 `c19e90103-CvUj-0ZH.js`。

---

### 5.1 语音模式与 Web Audio 物理声学系统 [#51-语音模式与-web-audio-物理声学系统]

> **技术领域与英文指代**：`Voice Mode & AudioWorklet Architecture`

#### 5.1.1 官方流式音频架构分析解密：AudioWorklet 与 SharedArrayBuffer 环形缓冲 (`audioSinkWorklet.js`) [#511-官方流式音频架构分析解密audioworklet-与-sharedarraybuffer-环形缓冲-audiosinkworkletjs]

在语音大模型实时对话（如 Claude Voice / Realtime API）场景下，传统的 `AudioContext.decodeAudioData` 或单次 `AudioBufferSourceNode` 调度会因为主线程垃圾回收（GC）或长任务阻塞而产生致命的爆音、破音或断断续续。

#### 1. 核心生产反编译源码取证 (`audioSinkWorklet.js`) [#1-核心生产反编译源码取证-audiosinkworkletjs]
Anthropic 采用现代浏览器的 `AudioWorkletProcessor` 在独立的高优先级音频渲染线程中运行，并通过 `SharedArrayBuffer` 与 `Atomics` 原子操作实现主线程与音频线程之间的**无锁零拷贝生产-消费者队列（RingBuffer）**（完整取证自 `/Applications/Claude.app/Contents/Resources/ion-dist/audio/voice/audioSinkWorklet.js`）：

```javascript
// audioSinkWorklet.js: Atomics 驱动的环形无锁缓冲区
var RD = 0;
var WR = 1;
var UNDERRUNS = 2;
var PLAYED = 3;
var HEADER_SLOTS = 4;
var HEADER_BYTES = HEADER_SLOTS * Uint32Array.BYTES_PER_ELEMENT;

var RingBuffer = class {
  constructor(sab) {
    this.indices = new Uint32Array(sab, 0, HEADER_SLOTS);
    this.storage = new Float32Array(sab, HEADER_BYTES);
    this.capacity = this.storage.length;
  }

  static allocate(capacity) {
    const bytes = HEADER_BYTES + capacity * Float32Array.BYTES_PER_ELEMENT;
    const Ctor = typeof SharedArrayBuffer !== "undefined" ? SharedArrayBuffer : ArrayBuffer;
    return new Ctor(bytes);
  }

  // 生产者（主线程 / Opus 解码器写入 PCM 样本）
  push(input) {
    const wr = Atomics.load(this.indices, WR);
    const rd = Atomics.load(this.indices, RD);
    const n = Math.min(input.length, this._availableWrite(rd, wr));
    if (n === 0) return 0;

    const tail = this.capacity - wr;
    if (n <= tail) {
      this.storage.set(input.subarray(0, n), wr);
    } else {
      this.storage.set(input.subarray(0, tail), wr);
      this.storage.set(input.subarray(tail, n), 0);
    }
    Atomics.store(this.indices, WR, (wr + n) % this.capacity);
    return n;
  }

  // 消费者（AudioWorklet 高优先级线程以约 375Hz 频率读取，每帧 128 样本）
  pop(output) {
    const rd = Atomics.load(this.indices, RD);
    const wr = Atomics.load(this.indices, WR);
    const n = Math.min(output.length, this._availableRead(rd, wr));
    if (n === 0) return 0;

    const tail = this.capacity - rd;
    if (n <= tail) {
      output.set(this.storage.subarray(rd, rd + n));
    } else {
      output.set(this.storage.subarray(rd, this.capacity));
      output.set(this.storage.subarray(0, n - tail), tail);
    }
    Atomics.store(this.indices, RD, (rd + n) % this.capacity);
    return n;
  }

  _availableRead(rd, wr) {
    return (wr - rd + this.capacity) % this.capacity;
  }
  _availableWrite(rd, wr) {
    return this.capacity - 1 - this._availableRead(rd, wr);
  }
};

// 音频帧处理器 (以 128 样本为一量度，48kHz 下每秒执行 375 次)
var AUDIO_SINK_PROCESSOR_NAME = "audio-sink-processor";
class AudioSinkProcessor extends AudioWorkletProcessor {
  process(_inputs, outputs) {
    const channel = outputs[0]?.[0];
    if (!channel) return true;

    const read = this.ring.pop(channel);
    if (read < channel.length) {
      // 欠载保护：不足部分用 0 填充静音，并触发欠载检测，绝不输出爆音
      channel.fill(0, read);
      if (this.hasStarted && this.gapReady) {
        this.dryGapPending = true;
        if (read === 0 && !this.drainPosted) {
          this.notifyDrained();
        }
      }
    }
    return true;
  }
}
registerProcessor(AUDIO_SINK_PROCESSOR_NAME, AudioSinkProcessor);
```

---

#### 5.1.2 四大官方 SFX 交互音效与 30% 舒适声学规范 (`shared-8-4Jj8qhmU.js`) [#512-四大官方-sfx-交互音效与-30-舒适声学规范-shared-8-4jj8qhmujs]

在桌面端与语音模式中，过度刺耳的蜂鸣提示音会破坏 Claude 温润的人文调性。Anthropic 在 `shared-8-4Jj8qhmU.js` 中确立了严格的**30% 舒缓音量原则**与硬件路由：

```javascript
// shared-8-4Jj8qhmU.js: 官方音效调度器
function createSoundElement(url, volume = 0.3) {
  if (typeof window === "undefined") return null;
  let audio = new Audio(url);
  // 核心声学标准：全局固定 30% 音量，温和舒适，绝不产生惊吓感
  audio.volume = volume;
  return audio;
}

async function initClaudeSoundPipeline() {
  let AudioContextClass = window.AudioContext || window.webkitAudioContext;
  let ctx = new AudioContextClass();
  
  // 四大官方交互音效矩阵（实际存储于 /audio/voice/sfx/）
  let sfxMap = {
    "enter_voice_mode":     createSoundElement("/audio/voice/sfx/enter_voice_mode.mp3", 0.3),
    "exit_voice_mode":      createSoundElement("/audio/voice/sfx/exit_voice_mode.mp3", 0.3),
    "disconnected":         createSoundElement("/audio/voice/sfx/disconnected.mp3", 0.3),
    "tool_approval_needed": createSoundElement("/audio/voice/sfx/tool_approval_needed.mp3", 0.3)
  };

  // 通过 AudioContext 目的节点进行直通低延迟连接
  Object.values(sfxMap).forEach(audio => {
    if (audio && ctx) {
      ctx.createMediaElementSource(audio).connect(ctx.destination);
      audio.load();
    }
  });

  // 支持 setSinkId 独立选择外接会议扬声器或耳机
  let selectedSpeakerId = getSelectedSpeakerDevice();
  if (selectedSpeakerId && typeof ctx.setSinkId === "function") {
    await ctx.setSinkId(selectedSpeakerId);
  }
}
```

| 音效标识 | 物理文件路径 | 声学特征与设计动机 | 触发时机 |
| :--- | :--- | :--- | :--- |
| `enter_voice_mode` | `sfx/enter_voice_mode.mp3` | 双音阶上扬泛音，清脆柔和（9.7KB） | 用户点击麦克风开启语音交互通道 |
| `exit_voice_mode` | `sfx/exit_voice_mode.mp3` | 单音阶下沉泛音，平缓收束（10.4KB） | 用户主动挂断或语音闲置超时 |
| `tool_approval_needed` | `sfx/tool_approval_needed.mp3` | 温暖的木质敲击共振双音（9.2KB） | 模型触发高风险电脑使用或 Bash 待确认 |
| `disconnected` | `sfx/disconnected.mp3` | 微弱的电平降调衰减音（10.7KB） | WebSocket / SSE 连接中断 |

> **开源落地推荐**：本仓库推荐采用基于原生 Web Audio API 振荡器的零外部资源合成方案：[`code-examples/ClaudeAudioPlayer.ts`](../code-examples/ClaudeAudioPlayer.ts)。

---

#### 5.1.3 6 频段非线性 Gamma 幂律波形动效 (`LiveMicActivityBars`) [#513-6-频段非线性-gamma-幂律波形动效-livemicactivitybars]

在语音交互中，麦克风波形如果直接绑定分贝线，会因为低音轰鸣导致视觉上总是“顶格”，而说话停顿时的背景噪音又会导致微小抖动。

Anthropic 在 `c4a1e6da6-B9dxf4-D.js` 中构建了 **LiveMicActivityBars** 算法：

```mermaid
flowchart LR
    Mic["麦克风音频流"] --> FFT["512 点 FFT 频域分析 (smoothing=0.5)"]
    FFT --> DecibelClamp["动态分贝截断 (-70dB 至 -10dB)"]
    NoiseGate["8% 噪声门限过滤 (Math.max(0, u - 0.08) / 0.92)"]
    DecibelClamp --> NoiseGate
    NoiseGate --> GammaComp["0.7 次幂非线性 Gamma 压缩 (f^0.7 * 1.5 * weight)"]
    GammaComp --> MotionInterpolate["Framer Motion 弹性高度映射 (4px - 24px)"]
```

#### 核心数学公式与生产反编译算法 [#核心数学公式与生产反编译算法]
```javascript
// c4a1e6da6-B9dxf4-D.js
// 1. Web Audio AnalyserNode 配置
analyser.fftSize = 512;
analyser.smoothingTimeConstant = 0.5; // 消除帧间视觉毛刺
analyser.minDecibels = -70;          // 静音底噪基准线
analyser.maxDecibels = -10;          // 正常说话饱和上限

// 2. 核心 6 频段能量提取与 Gamma 幂律映射公式
for (let b = 0; b < 6; b++) {
  let rawEnergy = computeAverageBinEnergy(dataArray, b); // [0.0, 1.0]
  let noiseFloor = 0.08; // 8% 噪声门限：彻底消除空调背景杂音引发的虚假微动
  let gated = Math.max(0, rawEnergy - noiseFloor) / (1 - noiseFloor);
  
  // 核心视觉物理学：0.7 次幂非线性 Gamma 压缩
  // 放大微弱的人声细语，同时压制高分贝爆音，使波形动态范围分布极度均匀
  let compressed = Math.min(1, Math.pow(gated, 0.7) * 1.5 * bandWeights[b]);
  
  // 映射至 4px - 24px 物理高度
  let targetHeight = 4 + (24 - 4) * compressed;
  motionValues[b].set(targetHeight);
}
```

> **生产级组件落地**：[`code-examples/LiveMicActivityBars.tsx`](../code-examples/LiveMicActivityBars.tsx)。

---

#### 5.1.4 5 大官方语音人格与声学特征解构 [#514-5-大官方语音人格与声学特征解构]

Claude 语音模式提供了 5 种经过严格声学调优与情绪定位的官方音色人格（实际存储于 `/Applications/Claude.app/Contents/Resources/ion-dist/audio/voice/selection/`）：

```
voice-personas/
├── airy                     # 空灵柔和 (Airy): 呼吸感强、语速适中，适合深度思考与陪伴
├── buttery                  # 醇厚顺滑 (Buttery): 磁性饱满、亲和力强，默认主推人格
├── glassy                   # 清澈明朗 (Glassy): 咬字清晰、高频透亮，适合代码讲解与教学
├── mellow                   # 沉稳温润 (Mellow): 语调舒缓、低频共鸣，适合夜间阅读与长文本
└── rounded                  # 饱满圆润 (Rounded): 节奏轻快、干脆利落，适合效率型问答
```

---

#### 5.1.5 双向流式声学拓扑：STT 语音听写 (`openDictation`) 与 24kHz 宽频带 TTS 朗读 (`openReading`) [#515-双向流式声学拓扑stt-语音听写-opendictation-与-24khz-宽频带-tts-朗读-openreading]

在 Claude Desktop 2.0 中，语音能力不仅限于被动的音效播放或单向录音，而是构建了完整的**全双工实时流式声学管线**（源码取证自 `frame-shell-dictate-C9D4b04p.js` 与 `frame-shell-speak-CBGDxR0k.js`）：

##### 1. 1 小时连续差分语音听写引擎 (`openDictation`) [#1-1-小时连续差分语音听写引擎-opendictation]

```javascript
// frame-shell-dictate-C9D4b04p.js
var WORKLET_URL = "/assets/v1/cb2b919a8-BamlKQVF.js";
var MAX_DICTATION_DURATION = 36e5; // 3,600,000ms = 严格 1 小时持续听写上限

// 核心前缀差分增量结算算法：仅向输入框发射新增 Delta，消除光标闪烁
function computeDictationDelta(lastSettled, currentText) {
  if (!currentText.startsWith(lastSettled)) {
    return { add: "", settled: currentText };
  }
  let delta = currentText.slice(lastSettled.length);
  return delta.trim() === ""
    ? { add: "", settled: lastSettled }
    : { add: delta, settled: currentText };
}

async function openDictation(options) {
  let session = audioPipeline.dictation({
    language: options.language,
    maxDuration: MAX_DICTATION_DURATION,
    settleAtPauses: true, // 核心声学断句：说话停顿时自动触发物理沉降
  });

  let settledText = "";

  session.on("result", (event) => {
    // 分离暂态推测文本 (interim) 与已定稿文本 (settled)
    let { add, settled } = computeDictationDelta(settledText, event.settled);
    settledText = settled;
    if (add !== "") options.onFinal(add);
    options.onPartial(event.interim);
  });

  session.on("state", (state) => {
    if (state === "idle") {
      options.onEnded("completed");
    }
  });

  await session.start();
  return {
    stop: async () => session.stop(),
    cancel: () => session.cancel(),
  };
}
```

##### 2. 24kHz 宽频带 TTS 与实时字词级高亮跟随 (`openReading`) [#2-24khz-宽频带-tts-与实时字词级高亮跟随-openreading]

```javascript
// frame-shell-speak-CBGDxR0k.js
var TTS_WIDEBAND_SAMPLE_RATE = 24000; // 24kHz 超高采样率，达到广播级人声解析度

function openReading(options) {
  let reader = getVoiceSession(options.organizationId).readAloud({
    voice: options.voice,
    sampleRate: TTS_WIDEBAND_SAMPLE_RATE,
  });

  // 核心视觉与声学联动：实时高频捕获朗读光标位置 (Karaoke 字词高亮)
  reader.on("position", (pos) => {
    options.onPosition({
      charIndex: pos.charIndex,
      wordLength: pos.wordLength,
    });
  });

  reader.on("state", (state) => {
    if (state.name === "speaking") {
      options.onSpeaking();
    }
  });

  return {
    ended: reader.speak(options.text),
    stop: () => reader.stop(),
  };
}
```

* **卡拉 OK 式高亮联动 (Karaoke Highlight Sync)**：通过 `onPosition` 事件，前端会话气泡能以毫秒级精度为当前发音的词句附加 `.cds-read-aloud-active` 高亮样式；
* **断句自动沉降 (Settle at Pauses)**：听写管道借助麦克风前端静音检测（VAD），在自然呼吸间隙将 `interim` 候选词转为 `settled` 最终文本，实现零卡顿输入。

---

### 5.2 多模态媒体查看器与画廊转场物理学 [#52-多模态媒体查看器与画廊转场物理学]

> **技术领域与英文指代**：`Lightbox, Pan/Zoom & Shared Element Transitions`

#### 5.2.1 物理常数与阻尼阈值矩阵 (Extracted Physical Constants) [#521-物理常数与阻尼阈值矩阵-extracted-physical-constants]

在 `c4b054ed5-BGjH-Uu6.js` 头部，Anthropic 确立了一组极其严苛的物理常数：

```javascript
// c4b054ed5-BGjH-Uu6.js: 核心物理学与阻尼常数
var ae = 2;        // 最小最大缩放倍数 (Math.max(naturalWidth / fitWidth, 2))
var oe = 4;        // 手势死区过滤阈值 (Math.hypot(dx, dy) < 4px 判定为手部微抖，不触发拖拽)
var se = 0.01;     // 滚轮缩放指数因子 (Math.exp(-deltaY * 0.01))
var v = 1.05;      // 缩放吸附下限 (当 scale <= 1.05 时自动顺滑吸附回 1.0)
var ce = 1.25;     // 单次触击/跳变放大默认比例
var y = 0.7;       // 视口阻尼溢出系数
var le = 2;        // 虚拟画廊跑道预加载跨度 (Math.abs(t - O) <= 2，前后仅预载 2 帧)
```

在 `c6a992d55-sXiDGMFQ.css` 中提取出对应的弹窗进出场关键帧：
```css
.animate-lightbox-backdrop-in { animation: .2s ease-out fade-in; }
.animate-lightbox-content-in  { animation: .25s ease-out scale-in; }
```

---

#### 5.2.2 View Transitions API 共享元素无缝变形（FLIP Morphing & Object-Fit 分析计算） [#522-view-transitions-api-共享元素无缝变形flip-morphing--object-fit-分析计算]

在 Claude 中点击对话气泡或文件卡片里的图片时，图片**从对话流里的缩略图无缝平滑膨胀展开至全屏 Lightbox**；关闭时又能精准原路飞回缩略图。

#### 核心生产源码取证 (`cd5136de8-BDys1vAN.js`) [#核心生产源码取证-cd5136de8-bdys1vanjs]

```javascript
// 1. 动态提取生效圆角 (向上穿透 5 层 DOM 捕获真实裁剪半边距)
function S(element, fallbackRadius) {
  let curr = element;
  for (let i = 0; curr && i < 5; i++) {
    let style = getComputedStyle(curr);
    if ((curr.tagName === "IMG" || style.overflow === "hidden" || style.overflow === "clip") 
        && style.borderRadius !== "0px" && style.borderRadius !== "") {
      return style.borderRadius;
    }
    curr = curr.parentElement;
  }
  return fallbackRadius;
}

// 2. 针对 object-fit: contain 图像的精确内切剪裁百分比算法
function T(img) {
  if (img.tagName !== "IMG") return null;
  let { naturalWidth: nw, naturalHeight: nh } = img;
  if (!(nw > 0 && nh > 0)) return null;
  let style = getComputedStyle(img);
  if (style.objectFit !== "contain" && style.objectFit !== "scale-down") return null;

  let rect = img.getBoundingClientRect();
  let padL = parseFloat(style.paddingLeft) || 0, padT = parseFloat(style.paddingTop) || 0;
  let padR = parseFloat(style.paddingRight) || 0, padB = parseFloat(style.paddingBottom) || 0;
  let availW = rect.width - padL - padR, availH = rect.height - padT - padB;
  if (!(availW > 0 && availH > 0)) return null;

  let scale = Math.min(availW / nw, availH / nh);
  if (style.objectFit === "scale-down") scale = Math.min(scale, 1);

  let renderW = nw * scale, renderH = nh * scale;
  let insetTop = (availH - renderH) / 2 + padT;
  let insetRight = (availW - renderW) / 2 + padR;
  let insetBottom = (availH - renderH) / 2 + padB;
  let insetLeft = (availW - renderW) / 2 + padL;

  let toPercent = (val, total) => `${Number((100 * val / total).toFixed(3))}%`;
  return {
    inset: `${toPercent(insetTop, rect.height)} ${toPercent(insetRight, rect.width)} ${toPercent(insetBottom, rect.height)} ${toPercent(insetLeft, rect.width)}`
  };
}
```

---

#### 5.2.3 仿射变换与以光标为锚点的 Pan / Zoom 物理学数学公式 [#523-仿射变换与以光标为锚点的-pan--zoom-物理学数学公式]

当图片放大时，如果简单使用中心点缩放，用户想看细节的位置会被推移出屏幕。Claude 的核心是**以当前鼠标指针（或双指中心点）为物理世界不变不动点（Fixed Anchor Point）**：

$$\begin{cases}
c = \frac{S_{\text{target}}}{S_{\text{current}}} \\
\text{idealTx} = O_x - (O_x - \text{idealTx}_{\text{prev}}) \cdot c \\
\text{idealTy} = O_y - (O_y - \text{idealTy}_{\text{prev}}) \cdot c \\
\text{tx} = \text{clamp}(\text{idealTx}, \text{maxTx}) \\
\text{ty} = \text{clamp}(\text{idealTy}, \text{maxTy})
\end{cases}$$

其中允许平移的最大物理边界 $\text{maxTx}, \text{maxTy}$ 根据视口与图像尺寸动态解算：
$$\text{maxTx} = \max\left(0, \frac{\text{fitWidth} \cdot S - \text{viewportWidth}}{2}\right) \cdot \min\left(1, \max\left(0, \frac{S - 1.05}{0.95}\right)\right)$$

#### 核心生产源码取证 (`c4b054ed5-BGjH-Uu6.js`) [#核心生产源码取证-c4b054ed5-bgjh-uu6js]

```javascript
// 核心锚点平移缩放方程
function pe(fitInfo, currentPos, targetScale, pointerPos) {
  let maxTx = calcMaxTranslate(fitInfo.fitWidth, fitInfo.viewportWidth, targetScale);
  let maxTy = calcMaxTranslate(fitInfo.fitHeight, fitInfo.viewportHeight, targetScale);
  let offsetX = pointerPos ? pointerPos.clientX - fitInfo.fitCenterX : 0;
  let offsetY = pointerPos ? pointerPos.clientY - fitInfo.fitCenterY : 0;

  let c = targetScale / currentPos.scale;
  let idealTx = offsetX - (offsetX - currentPos.idealTx) * c;
  let idealTy = offsetY - (offsetY - currentPos.idealTy) * c;

  let tx = clamp(idealTx, maxTx);
  let ty = clamp(idealTy, maxTy);
  return { ...fitInfo, scale: targetScale, idealTx, idealTy, tx, ty, maxTx, maxTy };
}

// 滚轮指数缩放监听与 4px 拖拽死区捕获
function handleWheel(e) {
  if (e.ctrlKey) {
    e.preventDefault();
    let zoomRatio = Math.exp(-e.deltaY * 0.01);
    let newScale = Math.min(Math.max(currentScale * zoomRatio, 1), maxScale);
    if (newScale <= 1.05) {
      resetZoom(); // 自动吸附回归 1.0
    } else {
      applyAnchorZoom(newScale, e.clientX, e.clientY);
    }
  }
}
```

---

#### 5.2.4 75vw 画廊跑道视口与前后两帧预加载架构 [#524-75vw-画廊跑道视口与前后两帧预加载架构]

在拥有多张图片附件（多轮会话或批量上传）的画廊中，Claude 使用了一套独特的 **75vw 弹性跑道与滑动视口模型**：

```css
/* 跑道滑动位移方程 */
.gallery-runway {
  gap: 32px;
  transform: translateX(calc(12.5vw - var(--active-index) * 75vw - var(--active-index) * 32px));
  transition: transform 300ms cubic-bezier(0.165, 0.84, 0.44, 1);
}
.gallery-slide {
  width: 75vw;
}
.gallery-slide[data-active="true"] {
  opacity: 1;
}
.gallery-slide[data-active="false"] {
  opacity: 0.4;
  cursor: pointer;
}
.gallery-slide[data-active="false"]:hover {
  opacity: 0.75;
}
```

* **视口布局精髓**：每个幻灯片宽度恰好为 `75vw`（屏幕宽度的 $\frac{3}{4}$），起始偏移量设为 `12.5vw`（刚好处于屏幕正中央）。两侧各露出 `12.5vw - 32px` 的相邻图片边缘，给用户明确的“画廊可左右滑动”视觉暗示。
* **虚拟预加载机制**：通过 `Math.abs(index - currentIndex) <= 2`，跑道上只保留当前项及前后各两张的真实 DOM 与高清图片，避免在百图大聊天记录中爆掉显存。

> **生产级组件落地**：[`code-examples/MediaLightboxViewer.tsx`](../code-examples/MediaLightboxViewer.tsx) 与 [`code-examples/useClaudeSharedElementTransition.ts`](../code-examples/useClaudeSharedElementTransition.ts)。

---

### 5.3 双栏弹性分割与折叠物理学 [#53-双栏弹性分割与折叠物理学]

> **技术领域与英文指代**：`Artifacts Split-Pane Resizer & Docking Physics`

在 Artifacts 产物展示、代码编辑与长文档审查场景中，Claude 拥有精密的可拖拽左右双栏分割与折叠交互（源码取证自 `shared-22-DYCF-SVs.js` 与 `c909d93e7-BsSzOQcm.js`）。

#### 5.3.1 核心生产反编译算法取证 (`shared-22-DYCF-SVs.js`, `c909d93e7-BsSzOQcm.js`) [#531-核心生产反编译算法取证-shared-22-dycf-svsjs-c909d93e7-bsszoqcmjs]

```javascript
// 拖拽激活与光标指针跟随
w = e => {
  if (e.pointerId !== u) return;
  if (!p.current) {
    if (Math.abs(t) < qM && Math.abs(r) < qM) return; // qM 为 4px 移动死区
    p.current = !0;
    d(!0);
    l.setAttribute("data-pane-dragging", String(c.current));
    y.showCursor("move");
  }
  // 计算基于容器宽度的浮点比例，默认锚定 0.5 (50%)
  let i = oN(n, c.current, BM(XM(l), parseFloat(getComputedStyle(l).getPropertyValue("--df-pane-row")) || .5, e.clientX, e.clientY));
  m.current = i;
  iN(i);
};

// Escape 键拦截与快速回滚
C = e => {
  if (e.key === "Escape" && p.current) {
    e.preventDefault();
    e.stopImmediatePropagation();
    // 立即终止拖拽并恢复原分割比例
    _.abort();
    x("cancelled");
  }
};
```

#### 5.3.2 连续指针动力学与事件屏蔽护盾 (Pointer Stream & Iframe Shield) [#532-连续指针动力学与事件屏蔽护盾-pointer-stream--iframe-shield]
- **Iframe 事件防吞噬护盾**：当用户在主窗口拖拽分割条时，一旦光标划过展示 HTML/React 产物的子 iframe，iframe 的内部 DOM 会截断主窗口的 `pointermove` 与 `pointerup` 事件，导致拖拽死锁。Claude 的解决机制是在拖拽激活时向全局注入 `data-pane-dragging="true"`，在预览容器上方强制覆盖一层透明的 `pointer-events: none` 阻断层；
- **4px 移动死区与 Escape 恢复**：设定 4px 阈值防止单击或轻微手颤激活拖拽；在拖拽过程中随时按 `Escape` 键可取消操作并瞬间回滚至先前的分割比例。

#### 5.3.3 双击居中吸附 (50/50 Snap) 与边缘折叠门限 (Docking Threshold) [#533-双击居中吸附-5050-snap-与边缘折叠门限-docking-threshold]
- **双击归位**：双击分割条上的胶囊手柄（Pill Handle），立即触发弹性重置，将视口精准平分（50/50 居中吸附）；
- **边缘折叠门限 (Docking)**：当拖拽比例超过临界值（如右栏宽度 < 18% 或视口像素 < 420px）时，系统自动触发吸附折叠，将右栏收起为侧边微型挂钩，为主聊天流释放完整阅读空间。
- **极值约束钳制**：左栏会话流最小保留 380px，右栏 Artifacts 最小保留 420px。

> **生产级组件落地**：[`code-examples/ArtifactsSplitPaneResizer.tsx`](../code-examples/ArtifactsSplitPaneResizer.tsx)。

---

### 5.4 工件预览沙箱与隔离通信架构 [#54-工件预览沙箱与隔离通信架构]

> **技术领域与英文指代**：`Artifacts Sandbox & Epitaxy Architecture`

Claude 拥有强大的动态渲染（React/SVG/Mermaid/HTML）能力，其底层运行在代号为 **Epitaxy** 的隔离容器中。

#### 5.4.1 核心生产反编译代码取证 (`c58115fda-BKnbLmi3.js` / `cd5a31703-B4nKQMBN.js`) [#541-核心生产反编译代码取证-c58115fda-bknblmi3js--cd5a31703-b4nkqmbnjs]

```javascript
// c58115fda-BKnbLmi3.js: Epitaxy 权限隔离与通信门禁
// 生产环境严格排除 allow-same-origin，切断同源父 DOM 穿透逃逸路径
var EPITAXY_IFRAME_SANDBOX = [
  "allow-scripts",
  "allow-forms",
  "allow-popups",
  "allow-modals"
].join(" ");

// 7 种专有 MIME 协议分发器
var EPITAXY_MIME_REGISTRY = {
  "application/vnd.ant.react":    "renderReactComponent",
  "application/vnd.ant.code":     "renderCodeHighlighter",
  "application/vnd.ant.markdown": "renderMarkdownDoc",
  "application/vnd.ant.mermaid":  "renderMermaidChart",
  "application/vnd.ant.svg":      "renderRawSvg",
  "application/vnd.ant.html":     "renderSandboxedHtml",
  "application/vnd.ant.latex":    "renderKatexMath"
};

// 用户手势激活门禁安全过滤器
window.addEventListener("message", function(event) {
  var data = event.data;
  if (!data || typeof data !== "object") return;

  // 严格校验消息来源源域与结构签名
  if (data.channel === "epitaxy_mcp_app") {
    // 核心安全防御：基于浏览器原生 userActivation 拦截未经真实用户手势激发的合成事件
    var hasActivation = (event.userActivation && event.userActivation.hasBeenActive) || false;
    if (!event.isTrusted || !hasActivation) {
      console.warn("[Epitaxy MCP App] ui/message without iframe-originated user activation blocked");
      return;
    }
    dispatchAppMessage(data.payload);
  }
});
```

> **生产级组件落地**：[`code-examples/EpitaxyIframeBridge.tsx`](../code-examples/EpitaxyIframeBridge.tsx)。

---

### 5.5 代码差异对比与多线程语法高亮系统 [#55-代码差异对比与多线程语法高亮系统]

> **技术领域与英文指代**：`Diff Viewer, Syntax Highlighter & CodeBlock`

在生成和修改代码文件时，Claude 会在 Artifacts 面板与会话气泡内呼出其专属的代码差异比对引擎（源码取证自 `c19e90103-CvUj-0ZH.js` 与 `c6a992d55-sXiDGMFQ.css`）。

#### 5.5.1 生产级 Diff 样式变量取证 (`.epitaxy-root .epitaxy-diff`) [#551-生产级-diff-样式变量取证-epitaxy-root-epitaxy-diff]

在官方混淆样式表 `c6a992d55-sXiDGMFQ.css` 中提取出的官方核心 Diff 变量定义：

```css
.epitaxy-root .epitaxy-diff {
  --diffs-font-size: var(--cds-font-size-code);
  --diffs-line-height: var(--cds-leading-code);
  --diffs-font-family: var(--cds-font-mono);
  --diffs-header-font-family: var(--cds-font-sans);
  --diffs-addition-color-override: var(--cds-text-git-added);
  --diffs-deletion-color-override: var(--cds-text-git-removed);
  --diffs-modified-color-override: var(--cds-text-accent);
  --diffs-gap-inline: var(--cds-pad-md);
  --diffs-gap-block: var(--cds-pad-xs);
}
```

#### 5.5.2 核心生产反编译算法取证 (`c19e90103-CvUj-0ZH.js`, `tree-sitter-Tbdz49RR.js`) [#552-核心生产反编译算法取证-c19e90103-cvuj-0zhjs-tree-sitter-tbdz49rrjs]

在 `c19e90103-CvUj-0ZH.js` 中提取出其流式高亮调度器 `Jh` 与 Shadow DOM 挂载函数 `Xh`：

```javascript
// Shadow DOM 隔离与双栏 Grid 锁定挂载
function Xh(e, t, n, r, i) {
  let a = e.ownerDocument,
      o = a.createElement("div"),
      s = o.shadowRoot ?? o.attachShadow({ mode: "open" });
  
  let c = a.createElement("style");
  let l = a.createElement("style");
  
  // 建立双栏网格 (gutter 行号栏与 content 代码内容栏)
  let f = a.createElement("div"); f.dataset.gutter = "";
  let p = a.createElement("div"); p.dataset.content = "";
  
  let v = 0;
  let b = () => {
    v += 1;
    // 左右两栏强制锁定相同网格跨度
    f.style.gridRow = p.style.gridRow = `span ${v}`;
  };

  // 增量消费 Worker 传递的 Tokens
  let x = Kh({
    lang: t,
    themes: n,
    onTokens: ({ recall: t, tokens: n, caughtUp: r, plain: a }) => {
      // 增量追加 span 节点，不重绘旧行
    }
  });

  return {
    accepts(e, r, i) {
      return r === t && e.startsWith(m); // 判定前缀是否承接，承接则增量追加
    },
    feed(e) {
      let t = e.slice(m.length);
      m = e;
      t && x.push(t); // 仅向 Worker 传递新增 Delta
    },
    settle() {
      x.closeWhenIdle();
    }
  };
}
```

#### 5.5.3 Shadow DOM 隔离与 CSS Grid 行高几何锁死 [#553-shadow-dom-隔离与-css-grid-行高几何锁死]
- **Shadow DOM 隔离**：高亮语法包含大量的样式规则。通过 `attachShadow({ mode: "open" })`，彻底将代码块语法样式与外层 UI 样式隔离，避免 CSS 选择器层叠膨胀；
- **行高物理锁死**：代码与行号分置于两栏，行内换行（Word Wrap）极易导致行号与代码行高不一致。Claude 采用 CSS Grid 布局，将行号栏 `f` 与代码栏 `p` 的网格跨度同步赋值为 `gridRow = span ${totalLines}`，从布局引擎底层抹平错位。

#### 5.5.4 代码块与复制 2.5s 状态机 (`saved-check-decay`) [#554-代码块与复制-25s-状态机-saved-check-decay]
Claude 的代码高亮块具有独立而优雅的头部设计与状态机动效：
* **容器外壳**：圆角 `rounded-xl (12px)`，边框 `border border-neutral-800`，背景深色 `#0d0d0c`。
* **头部工具栏**：高度 `36px`，左侧显示编程语言标签与对应图标（`.align-[-0.125em]`），右侧为复制按钮。
* **复制反馈 2.5s 状态机 (`saved-check-decay`)**：
  点击复制代码后，复制图标瞬时切换为绿色勾选图标并展示 "Copied"；经过 `2.5s` 静默展示期后，通过 CSS keyframes 自动淡隐恢复为默认复制状态：
  ```css
  @keyframes saved-check-decay {
    0%, 75% { opacity: 1; transform: scale(1); }
    100%    { opacity: 0; transform: scale(0.92); }
  }
  ```

> **生产级组件落地**：[`code-examples/StreamingDiffViewer.tsx`](../code-examples/StreamingDiffViewer.tsx) 与 [`code-examples/CodeBlock.tsx`](../code-examples/CodeBlock.tsx)。

---

<p align="center">
  [⬅️ 上一篇：第四篇：动效物理学、着色器与环境光影](04-动效物理学、着色器与环境光影.md) · [📚 返回总目录](Claude%20Design%20System%20(CDS).md) · [下一篇：第六篇：系统级桌面架构与协作拓扑 ➡️](06-系统级桌面架构与协作拓扑.md)
</p>
