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

Scope: macOS application (apps/macos). Rendering: CritterIconRenderer.makeIcon(...). Animation and state logic: CritterStatusLabel plus CritterStatusLabel+Behavior.swift.

States

StateTriggerVisual
IdleDefaultStandard blink/wiggle animation; open eyes retain a glossy highlight
PausedisPaused=trueAntennae sag ("off duty") with eyes open; animation stops
SleepingGateway offline or not set upAntennae sag and eyelids close into ⌣ ⌣ shapes; no animation
CelebrateMessage dispatched (sendCelebrationTick)Eyes flash happy ∩ ∩ curves for about 0.9s plus a leg motion
Voice wake (big ears)Trigger phrase recognizedAntennae stand upright and taller (earScale=1.9); returns after quiet period
WorkingisWorking=true or an active IconStateFaster 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.0s by default, 5.0s when 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 (earBoostActive controls the animation task in CritterStatusLabel+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 sets earScale=1.9 without altering the overall frame.
  • antennaDroop (range 0-1) folds the antennae downward for the paused and sleeping poses.
  • Leg scurry uses legWiggle up to 1.0 with 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.
391 words · updated Jul 27, 2026