Menu Bar Icon States and Animations for OpenClaw on macOS
This page details the visual states and animations of the menu bar icon for the OpenClaw macOS application. It is intended for developers working with CritterIconRenderer and CritterStatusLabel.
Read this when
- Changing menu bar icon behavior
Menu Bar Icon States
Scope: macOS application (apps/macos). Rendering: CritterIconRenderer.makeIcon(...). Animation and state logic: CritterStatusLabel plus CritterStatusLabel+Behavior.swift.
States
| State | Trigger | Visual |
|---|---|---|
| Idle | Default | Standard blink/wiggle animation; open eyes retain a glossy highlight |
| Paused | isPaused=true | Antennae sag ("off duty") with eyes open; animation stops |
| Sleeping | Gateway offline or not set up | Antennae sag and eyelids close into ⌣ ⌣ shapes; no animation |
| Celebrate | Message dispatched (sendCelebrationTick) | Eyes flash happy ∩ ∩ curves for about 0.9s plus a leg motion |
| Voice wake (big ears) | Trigger phrase recognized | Antennae stand upright and taller (earScale=1.9); returns after quiet period |
| Working | isWorking=true or an active IconState | Faster leg movement (legWiggle up to 1.0) plus a slight horizontal shift; adds to idle wiggle |
A tool-activity badge (SF Symbol puck, e.g. chevron.left.slash.chevron.right for execution) can display over the same critter icon when a session has an active job or tool. That badge originates from IconState/ActivityKind; refer to Menu bar for the complete state model.
Voice wake ears
- Activation:
AppStateStore.shared.triggerVoiceEars(ttl: nil), invoked from the voice-wake capture pipeline (VoiceWakeRuntime) and from voice-wake debug and test utilities (VoiceWakeTester,VoiceWakeOverlayController). - Deactivation:
stopVoiceEars(), invoked when capture finishes. - Silence interval before deactivation:
2.0sby default,5.0swhen only the trigger word was detected and no subsequent speech occurred (VoiceWakeRuntime.silenceWindow/triggerOnlySilenceWindow). - While boosted, idle blink, wiggle, leg, and ear timers are paused (
earBoostActivecontrols the animation task inCritterStatusLabel+Behavior).
Shapes and sizes
- Canvas: 18x18pt template image, rendered into a 36x36px bitmap backing store (2x) to keep the icon sharp on Retina displays.
- Ear scale defaults to
1.0; voice boost setsearScale=1.9without altering the overall frame. antennaDroop(range 0-1) folds the antennae downward for the paused and sleeping poses.- Leg scurry uses
legWiggleup to1.0with a slight horizontal shake.
Behavioral notes
- No external CLI or broker toggle for ears or working state; both are driven internally by app signals (
AppState.setWorking,AppState.triggerVoiceEars) to prevent accidental toggling. - Keep any new TTL brief (well under 10s) so the icon returns to baseline quickly if a job stalls.