手搓一个 Claude Code 硬件副屏:3D 打印外壳 + 本地状态机实现 AI 任务可视化
用 Claude Code 跑长任务时,经常会遇到一个挺闹心的问题:把复杂任务丢进后台,转身处理其他事情。几小时后回来一看,终端光标还在闪,表面一切正常。但仔细一查,任务早在几十分钟前就卡在了一个确认环节,就这么静默地悬停着——白白浪费了时间。
系统通知理论上能解决这个问题,但前提是你恰好守在电脑前,而且没被其他消息淹没。对于动辄跑几十分钟的后台任务,“后台静默卡死”确实是一个容易被忽略的盲区。
一、灵光乍现
于是我做了一个实体状态 Mini 副屏——用 3D 打印外壳、HDMI 小屏和本地状态服务,通过红绿灯把 Claude Code 的运行状态实时映射到桌面上。
红灯 —— AI 正在全速运行,消耗 CPU/Token;
黄灯 —— AI 等待用户确认,任务卡在半路,这是最容易被遗漏的状态;
绿灯 —— AI 空闲,任务已完成或尚未开始。
整个方案成本可控、复现门槛不高,下面按硬件组装、软件状态机实现、前端展示的顺序展开。
二、硬件准备
1、Mini 显示器外壳
外壳不需要自己从头建模,直接用开源方案即可。拓竹 MakerWorld 上搜索 "Mocintosh 摸鱼小副屏",作者提供了两款尺寸:
| 尺寸 | 分辨率 | 打印时长 | 耗材重量 |
|---|---|---|---|
| 2.8-inch(推荐) | 640×480 | 约 4.4h | 161g |
| 3.54-inch | 960×640 | 约 4.8h | 179g |
个人推荐 2.8 寸款,打印耗时更短,且 640×480 分辨率对静态状态展示完全够用。
2、HDMI显示屏
屏幕在某宝搜索 "HDMI 显示屏方案 2.8 寸麦金塔模型屏",需要注意两点:
- 必须选 HDMI 直驱方案,不要买 SPI/I2C 驱动屏,否则需要额外转接板,外壳可能不兼容;
- 注意屏幕排线方向,部分屏的 FPC 排线从左侧出,部分从右侧出,需要与外壳的走线槽匹配。
避坑提示:macOS 对 640×480 这类非标准小屏支持一般,首次连接可能只显示 1080p 导致黑屏。建议在系统设置中按住 Option 键点击"缩放"强制选择 640×480,或者在 Windows 下先调好分辨率再切换。
三、组装使用
1、安装驱动板
按照下图安装即可,注意不要压着屏幕排线,用螺丝固定驱动板。
2、组装外壳
四、软件架构:三层状态机
硬件只是躯壳,核心在于软件架构。整体分为三层:
Claude Code (Hook) → monitor.js (状态机) → 浏览器前端 (副屏展示)
1、状态灯控制
三种状态直接对应红绿灯:
红灯 / running:AI 正在执行工具或生成回复,算力拉满;
黄灯 / awaiting:本轮输出结束,但不确定是任务完成还是下一轮思考前的间隙;
绿灯 / idle:确认任务真正结束,进入空闲。
黄灯到绿灯的切换用了一个3 秒倒计时的缓冲逻辑。Claude Code 的 Agent 模式是"思考→工具→思考"的循环,两轮之间会有短暂间隙。如果直接切绿灯,灯会疯狂闪烁。加入 3 秒阈值后,只有真正空闲才会切绿灯。
2、技术架构
来看一下技术架构:
- 第一部分: 你在 Claude Code 里发消息、Claude 执行工具、Claude 回答完毕——这三个时机会自动触发脚本,把当前状态通过网络推送给一个本地服务。
- 第二部分: 这个本地服务(monitor.js)就像交通灯控制器,只做一件事:管理三种颜色。收到「开始工作」→ 立刻亮红灯,同时取消任何等待中的倒计时;收到「本轮结束」→ 亮黄灯,并悄悄启动一个 3 秒倒计时。3 秒内没有新的「开始工作」信号 → 切绿灯,说明真的结束了;3 秒内来了新的「开始工作」→ 倒计时取消,回红灯,继续干活。
- 第三部分: 浏览器里的页面每 250ms 问一次控制器「现在是什么颜色?」,拿到答案后同步给动画主题播放对应效果。
一句话总结: 红灯干活,黄灯等等,绿灯可以说话。
3、如何使用
代码放在了 GitHub 上:github.com/chenfengyan…
用户发消息
│
├─ UserPromptSubmit hook → set-state.sh busy → 红灯
│
├─ PreToolUse hook → set-state.sh busy → 红灯(持续)
│ │
│ └─ 若工具为 AskUserQuestion / AskFollowupQuestion
│ → set-state.sh waiting (persistent) → 黄灯(持续,不倒计时)
│ └─ 等待用户回复后 → UserPromptSubmit 再次触发 → 回到红灯
│
├─ Stop hook → set-state.sh waiting → 黄灯(3 秒倒计时)
│ │
│ └─ 若 Claude 继续工作(多 turn)→ PreToolUse 再次触发 → 回到红灯
│
└─ Stop hook 触发后 3 秒内无新事件
↓
monitor.js 判定为 idle → 绿灯
- Hooks 通过 curl POST 推送到 monitor.js(不再依赖文件)
- monitor.js 在内存维护状态:收到 busy 立即取消倒计时;收到 waiting 根据 persistent 字段决定行为——普通 Stop 启动 3 秒倒计时,AskUserQuestion 则持续黄灯直到用户回复
- 前端每 250ms 轮询 /api/status,严格跟随服务端状态,通过 postMessage 同步给 iframe 主题
- 绿灯由服务端倒计时决定:前端无任何计时逻辑
项目结构如下:
MyBetterDisplay/
├── start.sh # ⭐ 一键启动(首次运行这个就够了)
├── stop.sh # 停止监控服务
├── install.sh # 安装 BetterDisplay 应用
├── index.html # 监控主页(主题切换器)
├── claude-status/
│ ├── monitor.js # HTTP 监控服务(port 4242)
│ ├── set-state.sh # Hook 脚本(由 Claude Code 调用)
│ └── install-hooks.sh # 向 settings.json 注入 hooks
└── themes/ # 19 个动画主题(每个独立 HTML 文件)
快速开始:
# 脚本自动完成:检查依赖 → 注入 hooks → 启动服务 → 打开浏览器。
bash start.sh
# 停止服务
bash stop.sh
五、主题扩展
为了让 Mini 显示器不那么枯燥,除了标准红绿灯以外,还扩展了很多模式。反正都是 AI 来干活,随便扩展一下也无妨。
六、总结
3D 打印外壳 + HDMI 副屏 + 本地状态机,实现下来并不复杂。从 DIY 外壳,到组装硬件显示器,再到适配软件程序,整条链路完整,软硬件创意的结合,值得动手一试。