You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Real user feedback in docs/FEEDBACK.md surfaced four overlapping issues with how the duck behaves and how its modes/controls are described. They're not independent — fixing them piecemeal would land contradictory UX. This issue tracks a comprehensive redesign, with the option to ship it in phases.
Permissions remain the core feature and must never be silenced, regardless of any new chattiness or motion controls.
1. Motion / motor control — port Bambu's taper model
The complaint: The motor moves multiple times a minute. It's loud in a home office. Users want a way to keep the duck visually present but quieter.
The Bambu duck already solved this. See bambu/firmware/main/servo.cnext_hop_window() — three modes, all driven by time since last user interaction:
Mode
Behavior
ALWAYS
Alert cadence during waking hours, dormant during quiet hours
TAPER (default)
Alert (0–2 min): 4–15s hops. Settling (2–10 min): 30–60s hops. Drowsy (10 min–1 hr): 25–60 min between hops. Dormant (1 hr+): one hop / ~12 hr
INTERACTION_ONLY
Alert for 2 min after any interaction, dormant otherwise
Proposal for the Mac/Claude Code duck: port this same model (or a near-mirror) to the firmware shared between products, exposed as three named user-facing modes:
Active (= ALWAYS)
Chill (= TAPER) — default
Zen (= INTERACTION_ONLY or off entirely if motor is unwelcome)
Bambu's "quiet hours" concept is also worth bringing across (nighttime suppression).
2. Volume consistency
The complaint: "It'll quack or something pretty loudly and then proceed to speak to me in an indoor voice."
The reaction TTS respects the user volume setting; chirps / quacks / hardware tones may not. Need an audit:
Every audio output (TTS, melody, chirps, hardware piezo, serial-audio path) MUST honor the same user-set volume
Identify each path:
SpeechService TTS (say or serial-streamed Opus)
MelodyEngine (Jeopardy thinking melody)
Any chirp / squelch / notification beep
The hardware speaker's max-volume firmware path
Add a single shared outputVolume(for: AudioKind) resolver, or normalize at the synth level
This is closer to a bug than a design decision — the user already has volume control; some sound emitters just don't read it.
3. Mode names + descriptions
The complaint: "Opinions, permissions, voice" — opinions and voice are duck outputs, permissions is the user's vocal input. Two different actors smuggled into one list. Plus "Permissions Only (No-Mic)" is contradictory wording (permissions implies voice, no-mic implies no voice).
Ducky speaks opinions & alerts you to permission requests. You approve via voice.
Permissions Only
Ducky alerts you to permission requests. You approve via voice.
Companion (No-Mic)
Ducky speaks opinions & alerts you to permission requests. You approve with clicks.
Silent (?)
Ducky watches but doesn't speak. (Need to decide if this exists.)
Each description states (1) what the duck does, (2) how the user responds. Separates actor from action explicitly.
Also unclear: whether "No-Mic" means the duck's mic is off (so wake-word + voice approval are off) or something else. Mic state is conflated with mode. Likely needs its own toggle (see #4).
4. Mic on/off as a separate setting
The complaint: User wanted to silence the mic specifically (privacy, hot mic concerns) but didn't want to lose companion features. They gravitated to "No Mic" as the closest mode.
Proposal: make mic on/off a global setting, independent of mode. Like a system-wide mute, only for the mic:
Default ON for new users (so wake-word + voice approval work)
When OFF, modes that previously implied "uses mic" silently fall back to "click to approve"
Surface as a single visible toggle (status-bar icon? checkmark item?)
Combined with #3, modes become purely about what the duck does, not about how the user responds. The mic toggle controls the response channel separately.
5. Chattiness rate-limit — "comments per hour"
New idea (Danny): users should be able to tune the duck's verbosity. A "max comments per hour" knob, or a discrete slider (Quiet / Normal / Chatty), would let users dial back without going all-or-nothing.
Implementation sketch:
Token-bucket rate limiter at the eval-reaction layer (NOT the permission layer)
When over budget, the duck stays silent on a given eval — score still records, animation can still play
Permission prompts always pass through — they're the core feature and a missed one is a bug, not a feature
"Bypass for important reactions"? Maybe — e.g. very-negative ambition / very-high risk reactions always speak. Open question.
This composes with #1 (motion mode) cleanly: a user can have Chill motion + Quiet voice for a calm office, or Active motion + Chatty voice for solo coding. Two independent axes.
Suggested phasing
If this issue is too big to land in one PR, suggested order:
Why this exists
Real user feedback in
docs/FEEDBACK.mdsurfaced four overlapping issues with how the duck behaves and how its modes/controls are described. They're not independent — fixing them piecemeal would land contradictory UX. This issue tracks a comprehensive redesign, with the option to ship it in phases.Permissions remain the core feature and must never be silenced, regardless of any new chattiness or motion controls.
1. Motion / motor control — port Bambu's taper model
The complaint: The motor moves multiple times a minute. It's loud in a home office. Users want a way to keep the duck visually present but quieter.
The Bambu duck already solved this. See
bambu/firmware/main/servo.cnext_hop_window()— three modes, all driven by time since last user interaction:ALWAYSTAPER(default)INTERACTION_ONLYProposal for the Mac/Claude Code duck: port this same model (or a near-mirror) to the firmware shared between products, exposed as three named user-facing modes:
ALWAYS)TAPER) — defaultINTERACTION_ONLYor off entirely if motor is unwelcome)Bambu's "quiet hours" concept is also worth bringing across (nighttime suppression).
2. Volume consistency
The complaint: "It'll quack or something pretty loudly and then proceed to speak to me in an indoor voice."
The reaction TTS respects the user volume setting; chirps / quacks / hardware tones may not. Need an audit:
sayor serial-streamed Opus)outputVolume(for: AudioKind)resolver, or normalize at the synth levelThis is closer to a bug than a design decision — the user already has volume control; some sound emitters just don't read it.
3. Mode names + descriptions
The complaint: "Opinions, permissions, voice" — opinions and voice are duck outputs, permissions is the user's vocal input. Two different actors smuggled into one list. Plus "Permissions Only (No-Mic)" is contradictory wording (permissions implies voice, no-mic implies no voice).
User-proposed rewording (from FEEDBACK.md, lightly adjusted):
Each description states (1) what the duck does, (2) how the user responds. Separates actor from action explicitly.
Also unclear: whether "No-Mic" means the duck's mic is off (so wake-word + voice approval are off) or something else. Mic state is conflated with mode. Likely needs its own toggle (see #4).
4. Mic on/off as a separate setting
The complaint: User wanted to silence the mic specifically (privacy, hot mic concerns) but didn't want to lose companion features. They gravitated to "No Mic" as the closest mode.
Proposal: make mic on/off a global setting, independent of mode. Like a system-wide mute, only for the mic:
Combined with #3, modes become purely about what the duck does, not about how the user responds. The mic toggle controls the response channel separately.
5. Chattiness rate-limit — "comments per hour"
New idea (Danny): users should be able to tune the duck's verbosity. A "max comments per hour" knob, or a discrete slider (Quiet / Normal / Chatty), would let users dial back without going all-or-nothing.
Implementation sketch:
This composes with #1 (motion mode) cleanly: a user can have Chill motion + Quiet voice for a calm office, or Active motion + Chatty voice for solo coding. Two independent axes.
Suggested phasing
If this issue is too big to land in one PR, suggested order:
Out of scope (for this issue)
Related
docs/FEEDBACK.md— raw user feedback that drove thisbambu/firmware/main/servo.c— reference implementation for taper modes