我用 SwiftUI 做了一个 macOS 开源工具,模仿 iPhone AI 边缘虹光效果
前言
最近一段时间,我在使用 Claude Code 辅助写代码时,经常遇到一个问题:
AI Agent 在终端里执行任务,我切到浏览器或其他窗口后,很难判断它现在到底是:
- 还在思考
- 正在执行工具
- 已经完成
- 还是在等待我确认
每次都要切回终端看一眼,比较打断心流。
刚好 iPhone 的 Apple Intelligence 工作时,屏幕边缘会出现很漂亮的虹光效果。我觉得这种「余光可感知」的设计很适合 AI 编程场景,于是做了一个 macOS 小工具:EdgeGlow。
它把类似 iPhone AI 边缘虹光的效果带到了 Mac 上。
EdgeGlow 是什么?
EdgeGlow 是一个 macOS 菜单栏应用。
当 Claude Code 或其他 AI Coding Agent 工作时,它会在屏幕边缘显示流光效果;任务完成后,流光自动淡出。
效果类似:
AI 开始工作 → 屏幕边缘出现虹彩流光
AI 完成任务 → 流光淡出消失
项目地址:
https://github.com/vector4wang/EdgeGlow
效果图:
核心特性
EdgeGlow 目前支持:
- iPhone Apple Intelligence 风格的边缘虹光效果
- 5 种颜色主题:虹彩、炫酷、柔和、烈焰、冰雪
- 两种光效模式:流动模式、呼吸模式
- 多显示器支持
- 多终端支持
- 中英双语界面
- 参数可调:速度、宽度、亮度、方向
- 本地 HTTP hooks 联动
- 无遥测、无数据收集
- MIT 开源协议
性能方面:
| 指标 | 数值 |
|---|---|
| 安装包大小 | 约 892KB |
| CPU 占用 | 约 0% |
| 内存占用 | 约 50MB |
| 系统要求 | macOS 13.0+ |
快速安装
方式一:下载 Release
进入 GitHub Releases 页面下载:
https://github.com/vector4wang/EdgeGlow/releases
下载 EdgeGlow-v1.3.0.zip 后解压运行。
如果首次打开遇到 macOS 安全提示,可以右键应用,选择「打开」。
方式二:源码编译
git clone https://github.com/vector4wang/EdgeGlow.git
cd EdgeGlow
./build.sh
open Build/EdgeGlow.app
Claude Code 配置方式
EdgeGlow 的联动方式很简单:
它在本地启动一个 HTTP 服务,只监听:
127.0.0.1:9876
Claude Code hooks 在不同事件触发时调用对应接口:
/start → 显示流光
/pulse → 保持状态
/stop → 流光淡出
可以在 ~/.claude/settings.json 中添加类似配置:
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "curl -s http://127.0.0.1:9876/start"
}
]
}
],
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "curl -s http://127.0.0.1:9876/start"
}
]
}
],
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "curl -s http://127.0.0.1:9876/pulse"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "curl -s http://127.0.0.1:9876/stop"
}
]
}
]
}
}
实际使用时,EdgeGlow 设置界面也提供了「复制引导词」的方式,可以让 Claude Code 自动帮你生成配置。
工作原理
整体流程如下:
Claude Code 开始任务
↓
触发 UserPromptSubmit / PreToolUse hook
↓
curl http://127.0.0.1:9876/start
↓
EdgeGlow 显示屏幕边缘流光
↓
任务完成后触发 Stop hook
↓
curl http://127.0.0.1:9876/stop
↓
流光淡出
这样做的好处是:
- 不需要修改 Claude Code
- 不需要插件系统
- 不需要联网
- 任意支持 HTTP 请求的 Agent 理论上都能接入
为什么做成边缘流光?
传统的状态提醒方式一般有几种:
- 终端输出日志
- 系统通知
- 声音提醒
- 任务完成后弹窗
但 AI Agent 的工作过程比较特殊:它可能会频繁读文件、执行命令、等待确认,也可能持续工作几十秒到几分钟。
如果用通知,会比较打扰;如果只看终端,又需要不断切换窗口。
边缘流光的优势是:
- 不打断当前工作
- 余光就能看到状态
- 比日志和通知更轻量
- 很适合多任务场景
这也是 EdgeGlow 的核心设计目标:让 AI Agent 的状态变成环境反馈,而不是打断式提醒。
技术实现概览
EdgeGlow 使用原生 macOS 技术实现,主要包括:
Swift
SwiftUI
AppKit
Core Animation
Network.framework
UserDefaults
Combine
整体结构大致如下:
Sources/
├── main.swift # 应用入口、菜单栏
├── GlowWindow.swift # 流光窗口、光效绘制、动画
├── ControlServer.swift # 本地 HTTP 控制服务
├── HooksInstaller.swift # Agent 配置引导
├── L10n.swift # 中英文国际化
├── Settings/
│ ├── AppSettings.swift # 设置持久化
│ └── SettingsView.swift # SwiftUI 设置界面
└── Themes/
└── ColorTheme.swift # 颜色主题
技术细节:透明覆盖窗口
屏幕边缘流光需要显示在整个屏幕边缘,因此 EdgeGlow 使用一个透明的覆盖窗口。
核心思路是:
- 创建无边框透明窗口
- 覆盖所有屏幕的联合区域
- 不抢焦点
- 不影响用户点击和正常操作
多显示器环境下,需要计算所有屏幕的 union frame:
func totalScreenFrame() -> NSRect {
var frame = NSRect.zero
for screen in NSScreen.screens {
frame = NSUnionRect(frame, screen.frame)
}
return frame
}
当屏幕参数变化时,例如外接显示器插拔,重新计算路径并重建图层。
技术细节:复刻 iPhone AI 边缘虹光
默认的虹彩主题参考了 iPhone Apple Intelligence 的视觉效果。
颜色变化大致是:
紫 → 蓝 → 青 → 粉 → 橙 → 金
为了让边缘流光更接近真实霓虹效果,EdgeGlow 使用多层 CAShapeLayer 叠加:
Layer 1: 高模糊 + 低透明度,作为外层光晕
Layer 2: 中模糊 + 中透明度,作为中层扩散
Layer 3: 低模糊 + 高透明度,作为主色线
Layer 4: 无模糊 + 高亮度,作为中心亮芯
这种做法比单层描边更自然,能够模拟发光边缘的层次感。
技术细节:动画实现
一开始我尝试使用 CABasicAnimation 去驱动 lineDashPhase,类似这样:
let animation = CABasicAnimation(keyPath: "lineDashPhase")
animation.fromValue = 0
animation.toValue = perimeter
animation.repeatCount = .infinity
shapeLayer.add(animation, forKey: "flow")
但实际测试时发现,窗口隐藏后再显示,Core Animation 的状态可能会丢失,导致动画卡住、跳变或者方向异常。
后来改成直接用定时器驱动状态更新:
flowTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 60.0, repeats: true) { [weak self] _ in
self?.tickFlow()
}
每一帧只更新 lineDashPhase,实际 CPU 占用很低。
技术细节:本地 HTTP 服务
EdgeGlow 使用 NWListener 启动本地 HTTP 服务。
安全设计上做了几件事:
- 只监听
127.0.0.1 - 使用
acceptLocalOnly - 只接受 GET 请求
- 不返回 CORS 头
- 不收集任何数据
这意味着外部网络无法访问这个服务,网页 JavaScript 也无法直接跨域调用。
技术细节:多终端状态管理
如果同时打开多个 Claude Code 终端,就会出现一个问题:
一个终端完成了,不代表其他终端也完成了。
因此 EdgeGlow 需要维护一个活动状态计数或活动标识集合,只有所有任务都完成后,才让流光消失。
简化逻辑类似:
case "/start":
activeCount += 1
showGlow()
case "/stop":
activeCount = max(0, activeCount - 1)
if activeCount == 0 {
hideGlow()
}
同时还需要安全超时机制,避免 Agent 异常退出导致流光一直不消失。
适用人群
我觉得 EdgeGlow 比较适合这些场景:
- 经常使用 Claude Code 的开发者
- 同时开多个 AI Coding Agent 的用户
- 需要在多个窗口之间频繁切换的人
- 喜欢轻量原生 macOS 工具的人
- 对 AI 编程状态反馈有需求的人
总结
EdgeGlow 本质上不是一个复杂工具,它解决的是一个很小但高频的问题:
AI Agent 到底还在不在工作?
通过屏幕边缘流光,EdgeGlow 把这个状态变成了一个环境信号。你不需要切回终端,不需要看通知,余光一扫就能知道当前状态。
项目完全开源,代码也比较简单,如果你对 macOS 原生应用、SwiftUI、Core Animation 或 AI Agent 工具联动感兴趣,可以参考或一起完善。
项目地址:
https://github.com/vector4wang/EdgeGlow
欢迎 Star、Issue、PR。
更多推荐

所有评论(0)