从hidden到home:Coucou刘海岛4状态状态机的设计与实现详解
从hidden到homeCoucou刘海岛4状态状态机的设计与实现详解【免费下载链接】coucouA tiny friend that lives in your notch (macOS) or at the top of your screen (Windows, Linux) and keeps an eye on your coding agents: Claude Code, Gemini CLI, Antigravity and more.项目地址: https://gitcode.com/gh_mirrors/co/coucouCoucou 是一款常驻macOS 刘海或 Windows 屏幕顶部的轻量应用负责盯守你的Claude Code 会话。它最迷人的刘海岛展开/收起动画背后是一套只有 4 个状态的状态机hidden、petit、home、coucou。本文将从零拆解这 4 状态状态机的设计思路、转移规则、定时器参数与跨平台移植要点即使你是新手也能看懂。先认识一下刘海岛Coucou 的工作方式非常安静没有 Claude 任务运行时屏幕上什么都没有任务一启动刘海右侧就探出一只小团子Mochi和几个迷你任务头像鼠标悬停或点击后它展开成一块 640 点宽的岛展示任务总览、审批请求、错误信息等 14 种视图。整块岛体的形态切换——何时露面、何时展开、何时收起、何时彻底隐身——全部由一个独立的纯逻辑状态机掌管代码仅 160 余行IslandStateMachine.swift。4 个状态速览hidden / petit / home / coucou状态定义见 IslandStateMachine.swift#L8-L13enum State: Equatable { case hidden // 不可见刘海尺寸 case petit // 紧凑岛刘海 耳朵 case home // 展开任务总览 case coucou // 展开打招呼动画 }状态屏幕表现典型进入方式hidden完全不可见CPU 占用趋近 0空闲 60 秒后自动收起petit刘海旁伸出紧凑小岛Mochi 迷你任务头像鼠标悬停刘海 / 工作事件闪现home展开为 640 点宽卡片显示总览或告警视图点击紧凑岛 / 收到审批告警coucou展开并播放打招呼动画应用启动时名字很有讲究petit是法语小coucou是法语里见面时的一声嗨——状态机连命名都在卖萌。hidden → petit一次探头需要多少钱这是最高频的转移鼠标进入刘海区域岛立刻从 hidden 变 petit同时播放一声俏皮的peek音效见 IslandWindowController.swift#L155-L194 中的转移回调。反过来鼠标离开后并不立刻消失而是启动一个60 秒计时器给用户留足缓冲。除了鼠标还有第二条进入路径reveal()。当 Hook 服务器报告非告警类工作事件比如某个 Claude 会话启动、开始调用工具时岛会从 hidden 闪现到 petit展示片刻后再计时收起——让你瞥一眼哦它在干活了又不打扰你。紧凑状态下右侧耳朵里还会以 2×2 网格展示最多 4 个迷你任务头像这是4 状态 14 视图分层设计的巧妙之处状态机只管岛的形态视图枚举IslandView管岛里显示什么两者解耦定义在 IslandTypes.swift#L5-L15。petit → home点击展开的家petit甚至hidden状态下点击岛立即进入home播放open音效展开到默认视图有任务显示overview总览没有则显示empty。home是信息量最大的状态左侧卡片是任务滚动列表当前聚焦任务高亮闪烁右侧卡片是各集成服务的彩色药丸标签。注意一个设计细节click()特意允许在hidden状态下也接受点击IslandStateMachine.swift#L75-L82。原因是告警弹窗后岛可能已在屏上但状态机从未收到鼠标进入事件——如果不放宽条件用户点击就会失灵。这类边界条件处理正是手写状态机相比散落在 UI 代码里的计时器更可靠的地方。展开后的home若15 秒无活动鼠标移出且无点击、输入自动收回到petit播放close音效。coucou启动时的嗨与 0.6 秒的收尾应用启动时状态机调用launch()直接进入coucou岛展开Mochi 挥手打招呼动画持续约 4.6 秒。这个状态的时间线是 4 个状态里最精巧的动画播完greetComplete若鼠标没在岛上安排0.6 秒后收起为petit——刚好衔接画布收缩动画鼠标悬停着收起延迟延长到10 秒greetHoverCollapseDelay让你有时间看清它鼠标离开不等任何计时器立即中断打招呼回到petit。完整转移规则一览表状态机对外只暴露 8 个输入方法IslandStateMachine.swift#L33-L128全部转移规则如下事件hiddenpetithomecoucou鼠标进入→ petit播 peek 音取消 60s 隐藏计时取消 15s 收起计时延长收起至 10s鼠标离开忽略启动 60s → hidden启动 15s → petit立即 → petit点击→ home→ home忽略忽略启动 /launch→ coucou→ coucou→ coucou→ coucou工作闪现 /reveal→ petit随后计时 60s忽略忽略忽略动画播完 /greetComplete忽略忽略忽略0.6s 后 → petit显式收起 /collapse忽略忽略立即 → petit立即 → petit鼠标事件的来源值得一提窗口控制器以60Hz 轮询NSEvent.mouseLocation判断光标是否落在岛区域内据此喂给状态机mouseEntered()/mouseLeft()IslandWindowController.swift#L196-L255。轮询而非事件监听让悬停判定与窗口点击穿透ignoresMouseEvents切换共用同一套几何计算逻辑集中、不易漂移。3 个定时器 2 个同步接口所有自动转移都挂在 3 个可取消的DispatchWorkItem上默认参数定义在 IslandStateMachine.swift#L20-L27参数默认值作用homeToPetitDelay15shome 无活动后收起petitToHiddenDelay60spetit 空闲后隐身greetAutoCollapseDelay0.6s问候动画结束后收尾greetHoverCollapseDelay10s问候中鼠标悬停时的收尾延迟状态机内部还埋了两个对账接口专治 UI 与状态机失步hiddenExternally()当应用自己把岛藏起来了例如最后一个任务结束直接同步状态到hidden不触发任何动画副作用。否则状态机还以为岛是petit用户下一次悬停会被吞掉。collapse()按 Esc、点 OK、点设置等场景下岛被 UI 自行折叠。状态机立即转到petit而不是等 15 秒计时器——源码注释IslandStateMachine.swift#L93-L100解释了动机等计时器会导致屏幕上已是紧凑岛状态机却认为还开着的死锁岛再也点不开。还有一个关键规则告警会钉住岛。Claude Code 请求执行命令时Hook 服务器推送告警岛直接展开到审批视图且不启动自动收起计时器直到用户点允许或拒绝Windows 移植版把这个规则显式化为pinned布尔字段fsm.ts#L19-L20告警期间置为truescheduleHomeCollapse直接跳过计时告警解除后dropPin()释放岛恢复自动收起能力。一套状态机两个平台这套 FSM 被刻意设计成零依赖不碰 AppKit不碰 Tauri只通过一个onTransition(from, to)回调对外发声。因此 Windows 端有一个近乎 1:1 的 TypeScript 移植版 fsm.ts文件头注释写明 port of IslandStateMachine.swift状态名、4 个转移输入、3 个定时器全部一致仅把DispatchWorkItem换成setTimeout并额外提供forceHome()/forcePetit()/forceHidden()三个强制跳转方法方便告警与设置项直接驱动。两端的行为契约统一记录在规格文档 SPEC.md 中§2 岛的形态、§3 行为规则这也是为什么 macOS 与 Windows 上的探头—展开—收起手感几乎分毫不差。总结小状态机带来的大省心回看整个设计Coucou 刘海岛的 4 状态状态机做对了三件事状态少而正交4 个状态覆盖了隐形、待机、工作、寒暄全部场景任何时刻岛该是什么样子只有一个答案转移集中可审计所有入口鼠标、点击、启动、告警、外部收起都收敛到 8 个方法转移规则一张表就能穷举UI 与状态机对账hiddenExternally()与collapse()保证屏幕上的岛和状态机心中的岛永远一致杜绝了点不开的幽灵状态。这套 160 行的纯逻辑类就是那个住在刘海里的小伙伴从不失态的全部秘密。本文涉及的核心文件macOS 状态机NotchBuddy/Sources/App/IslandStateMachine.swift窗口与 FSM 接线NotchBuddy/Sources/App/IslandWindowController.swift形态/视图/状态枚举NotchBuddy/Sources/App/IslandTypes.swiftWindows 端移植版windows/src/island/fsm.ts行为规格文档docs/SPEC.md【免费下载链接】coucouA tiny friend that lives in your notch (macOS) or at the top of your screen (Windows, Linux) and keeps an eye on your coding agents: Claude Code, Gemini CLI, Antigravity and more.项目地址: https://gitcode.com/gh_mirrors/co/coucou创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考