# Hermes vs OpenClaw

**类型**：YouTube 教育视频  
**状态**：✅ 制作完成  
**系列**：Jixian 频道  
**最后更新**：2026-04-20

## 概述

对比评测视频：Hermes 框架 vs OpenClaw，展示两者在 AI Agent 工程化方面的差异。

- **部署地址**：https://youtube.dev.suchka.me/2026-04-18-hermes-vs-openclaw/
- **幻灯片**：https://youtube.dev.suchka.me/2026-04-18-hermes-vs-openclaw/slides/
- **播放器**：https://youtube.dev.suchka.me/2026-04-18-hermes-vs-openclaw/player.html
- **工程路径**（gpu-local）：`/proj/youtube/2026-04-18-hermes-vs-openclaw/`

## 幻灯片列表（共 11 张）

| ID | 名称 | 说明 |
|----|------|------|
| s_hook | Hook | 开场钩子 |
| s_intro | Intro | 项目介绍 |
| s_slogan | Slogan | 品牌标语 |
| s_layers | Layers | 架构层级 |
| s_gear | Gear | 功能模块 |
| s_score | Score | 评分对比（3 个子场景，1/2/3 键切换）|
| s_verdict | Verdict | 结论 |
| s_choice | Choice | 选择建议 |
| s_cta | CTA | 行动召唤 |
| s_code | Code | 代码对比（→ 键步进 SC-1→SC-2→SC-3）|
| s_data | Data | 数据统计 |

## 播放器架构：单页合并方案

**关键决策**：放弃 iframe 嵌套，改用单页合并 HTML（`player.html`，~74KB）

### 为什么不用 iframe

| 问题 | 描述 |
|------|------|
| crossfade 闪黑 | iframe 切换时 `#000` 背景短暂露出 |
| postMessage 不可靠 | 跨 origin 的 onComplete 回调时序不稳 |

### 单页合并方案

- 所有 11 张幻灯片内联为 `<div class="slide" id="sN">`（无 iframe）
- CSS ID 用 `sN-` 前缀命名空间，避免冲突
- 每张幻灯片有独立的 `playS0()...playS10()` GSAP 动画函数
- `player.slideDone(holdMs)` 在每段 timeline 末尾调用 → 保持后自动推进
- `killLoops()` 在切换幻灯片时调用 → 清除 `repeat:-1` 的 tween（如 ticker、wheel spin）
- s6（s_score）和 s8（s_code）有子场景手动切换；s6 用 1/2/3 键，s8 用 → 步进

**结论**：多幻灯片 GSAP 演示，合并 HTML 远优于 iframe 方案。

## Chrome 录制问题与解决方案

### 问题 1：Google Translate 翻译栏

- **现象**：Chrome 自动弹出 Google Translate 工具栏，遮挡画面顶部
- **根因**：HTML 未声明 `translate="no"` 属性
- **修复**：在 `index.html` 和 `player.html` 的 `<html>` 标签加 `translate="no"`：
  ```html
  <html lang="zh" translate="no">
  ```
- **验证**：gpu-local Xvfb :99 截图确认翻译栏消失

### 问题 2：Chrome `--no-sandbox` 警告条

- **现象**：Chrome 以 `--no-sandbox` 启动时，顶部出现黄色/白色警告条（Chrome UI 级别，JS 无法移除）
- **解决方案（v12 crop 方案）**：
  - 录制分辨率：`1920x1088`（比目标高 8px，留 crop 余量）
  - 裁剪：`crop top 40px`（去掉警告条）→ `bottom pad 8px`（补回高度）
  - 最终输出：干净的 `1920x1080`

### 问题 3：X11 socket 截图（SSH 环境）

- **现象**：SSH 到 gpu-local 后，`echo $DISPLAY` 返回 `:99`，但 `import` / screengrab 命令无法连接
- **根因**：`/tmp/.X11-unix/` 目录权限，其他用户可读但 SSH session 无法访问 socket
- **解决方案**：不要用 SSH 做远程截图 → 改用 **subagent 在 gpu-local 本地执行**
  - subagent SSH session 是真实登录 shell，继承完整 DISPLAY 和 X11 环境

## 最终产出（v20）

- **文件**：`gpu-local:/proj/youtube/2026-04-18-hermes-vs-openclaw/output/final_v20_merged.mp4`
- **大小**：64.5MB
- **时长**：315 秒（约 5 分钟）
- **预览**：https://youtube.dev.suchka.me/2026-04-18-hermes-vs-openclaw/output/final_v20_merged.mp4

### v20 音频精准对齐（关键改进）

**问题**：前几版（v18g 画面 OK，但音频用 10s 粗采样对齐 → 最大误差 ±5s）

**解决方案**：用 `FAKE_DURS` 精确累加时间代替采样值

| Slide | 精确开始时间 |
|-------|-------------|
| S0 | 0s |
| S1 | 42.71s |
| S3 | 75.39s |
| S6 | 179.67s |
| ... | ... |

- 最大误差：从 ±5s 降至 **<1ms**
- 视频来源：v18g（1920x1088 录制，crop top 40px → 干净 1920x1080）

## 录制方案（capture_v12）

- **状态**：✅ 完成（v20 最终版）
- **录制时长**：约 320 秒（5 分钟），分 16 段触发 `showSlide()`
- **Xvfb 环境**：gpu-local `:99`
- **Chrome 参数**：`--no-sandbox`（Docker 环境需要）

## 基础设施

| 组件 | 配置 |
|------|------|
| 反代 | `youtube.dev.suchka.me` → Caddy（gpu-local） |
| 容器 | nginx `youtube-preview`，端口 8102 |
| 挂载 | `/proj/youtube/`（注意：**不是** `/proj/share/www/`）|
| **必须操作** | `rsync` 后执行 `chmod -R a+rX`，否则 nginx 返回 403/404 |

## 已知 Bug 记录

| Bug | 根因 | 修复方法 |
|-----|------|---------|
| `goScene()` reset 后 bubble 可见性错误 | 未重置 `visibility` | 切换 scene 时强制隐藏 |
| SC-3 context 行溢出 | 继承了 SC-2 的 18 行内容 | 独立设置 SC-3 context 行 |
| bubble 位置偏移 | `getBoundingClientRect()` 在 GSAP scroll 前调用 | 改为静态 offset |
| scroll 过冲 | 硬编码 `-320px` | 公式计算：`hl2_offsetTop - scene_height/2 + hl2_height/2 ≈ -100px` |

## 参考

- 前作：[Harness Engineering EP.02](Harness-Engineering-EP02.md)
- 录制方案：[AI 视频生产管线](../topics/AI-视频生产管线.md)
