Files
openclaw/docs/platforms/mac/icon.md
Peter Steinberger a40e43e46e feat(mac): redesign the menu bar critter to match the mascot (#104846)
* feat(mac): redesign menu bar critter to match the mascot

* fix(mac): draw happy-eye arcs upward and guard stale celebration expiry

* docs(mac): update menu bar icon states for critter redesign

* fix(mac): own celebration expiry with a start-only generation counter

* fix(mac): give voice-wake antennae real headroom at 18pt
2026-07-12 06:35:02 +01:00

48 lines
3.4 KiB
Markdown

---
summary: "Menu bar icon states and animations for OpenClaw on macOS"
read_when:
- Changing menu bar icon behavior
title: "Menu bar icon"
---
# Menu Bar Icon States
Scope: macOS app (`apps/macos`). Rendering: `CritterIconRenderer.makeIcon(...)`. Animation/state wiring: `CritterStatusLabel` + `CritterStatusLabel+Behavior.swift`.
## States
| State | Trigger | Visual |
| --------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Idle | Default | Normal blink/wiggle animation; open eyes keep a glossy glint |
| Paused | `isPaused=true` | Antennae droop ("off duty") with open eyes; no motion |
| Sleeping | Gateway disconnected/unconfigured | Antennae droop and eyes close into `⌣ ⌣` lids; no motion |
| Celebrate | Message sent (`sendCelebrationTick`) | Eyes flash happy `∩ ∩` arcs for ~0.9s plus a leg kick |
| Voice wake (big ears) | Wake word heard | Antennae perk up straight and taller (`earScale=1.9`); drops after silence |
| Working | `isWorking=true` or an active `IconState` | Faster leg wiggle (`legWiggle` up to `1.0`) plus a small horizontal offset; additive to idle wiggle |
A tool-activity badge (SF Symbol puck, e.g. `chevron.left.slash.chevron.right` for exec) can render on top of the same critter icon when a session has an active job or tool. That badge comes from `IconState`/`ActivityKind`; see [Menu bar](/platforms/mac/menu-bar) for the full state model.
## Voice wake ears
- Trigger: `AppStateStore.shared.triggerVoiceEars(ttl: nil)`, called from the voice-wake capture pipeline (`VoiceWakeRuntime`) and from voice-wake debug/test tooling (`VoiceWakeTester`, `VoiceWakeOverlayController`).
- Stop: `stopVoiceEars()`, called when capture finalizes.
- Silence window before finalizing: `2.0s` normally, `5.0s` if only the trigger word was heard and no further speech followed (`VoiceWakeRuntime.silenceWindow` / `triggerOnlySilenceWindow`).
- While boosted, idle blink/wiggle/leg/ear timers are suspended (`earBoostActive` gates the animation task in `CritterStatusLabel+Behavior`).
## Shapes and sizes
- Canvas: 18x18pt template image, rendered into a 36x36px bitmap backing store (2x) so the icon stays crisp on Retina.
- Ear scale defaults to `1.0`; voice boost sets `earScale=1.9` without changing the overall frame.
- `antennaDroop` (0-1) folds the antennae down for the paused and sleeping poses.
- Leg scurry uses `legWiggle` up to `1.0` with a small horizontal jiggle.
## Behavioral notes
- No external CLI/broker toggle for ears or working state; both are driven internally by app signals (`AppState.setWorking`, `AppState.triggerVoiceEars`) to avoid accidental flapping.
- Keep any new TTL short (well under 10s) so the icon returns to baseline quickly if a job hangs.
## Related
- [Menu bar](/platforms/mac/menu-bar)
- [macOS app](/platforms/macos)