Skip to content

RGB LED ring patterns

Hardware and data format

Decompiled: voice-agent:0x2bf5f0 opens /dev/topleds, queries ioctl 0x80047a02, and expects 36 channels. This corresponds to 12 RGB LEDs. Updates use LEDS_WS2812B_IOCTL_MULTI_SET (check-factory-reset:0x17140 references the ioctl diagnostic).

Most ring resources contain 12 #rrggbb strings per frame:

[
  {
    "duration": 0.0166,
    "colors": ["#aa0a00", "#710700", "#000000"]
  }
]

The example is abbreviated. The shared parser is in led_animation_parser.cpp; rgb_led.cpp parses hex colors. RGB and display animations can run together but use independent device nodes.

Pattern families

UX state Resources
Voice lifecycle listening_start.json, listening.json, listening_error.json, thinking_loop.json, speaking*.json
Setup settings_enter.json, settings_intro.json, settings_loader_start.json, settings_loader.json, settings_receiving.json, settings_wait.json, settings_success.json
Microphone mic_on.json, mic_off.json, mute_error.json, volume_mute.json
Volume/night mode volume.json, volume_night.json, night_mode_start.json, night_mode_stop.json, night_mode_volume_error.json
Bluetooth BT_waiting.json, BT_connected.json, BT_disconnected.json
Calls call_incoming.json, call_waiting.json, call_accept.json, call_end.json
Alarms/timers alarm.json, timer.json, reminder.json
Media start_track.json, pause_track.json, next_track.json, prev_track.json
Connectivity/errors ready.json, loading.json, connection_error.json, announcement.json, vk_notification.json
Stereo pairing CC_pairdLeft_diodes.json, CC_pairdRight_diodes.json, CC_stereoLeft_v3_diodes.json, CC_stereoRight_v3_diodes.json, stereopair_success.opus
OTA updateDownloadComplete_diodes.json
Reset hwreset_intro.json, hwreset_done.json, factoryResetJoke_diodes.json

The complete frame/channel/duration inventory is generated at firmware/manifest/led-inventory.tsv by summarize_led.py. All 97 RGB and segment JSON resources are also published verbatim as raw downloads. The interactive preview has been removed for now.

Volume animation

voice-agent contains dedicated classes including VolumeAnimationContinuousTop, VolumeAnimationOneShotTopSlow/Fast, VolumeChangeAnimationFast/Continuous, VolumeChangedFadeoutAnimation, and VolumeAnimationClock. Flags include volume_animation_fps, volume_animation_bezier, volume_animation_in_ms, volume_animation_out_ms, and volume_animation_still_ms.

Thus volume is not just a static selection of one JSON frame: the agent computes transitions and can react to audio level. Separate flags set minimum/maximum animation response for listening, TTS, and music.

Reset sequence

Decompiled from check-factory-reset:sub_10C00: while the user holds the reset combination, the RGB ring plays hwreset_intro.json (301 frames, approximately 5 seconds) in parallel with the display's reset icon. Successful completion switches to hwreset_done.json (123 frames, approximately 2 seconds). The agent then plays 30_reset_v3.flac and returns status 1 to S60, which creates the reset marker and reboots.

Resource limits and timing quirks

The resource set is shared with other Capsula variants and is not perfectly uniform:

  • alarm.json, timer.json, reminder.json, mute_error.json, night_mode_volume_error.json, volume_mute.json, and vk_notification.json contain 13 colors rather than the Mini's 12.
  • Some files use seconds instead of duration.
  • volume.json uses values such as 16.6, while most animations use fractions of a second.
  • listening.json and several other resources have zero total duration when interpreted naively.

Decompiled: the parser accepts up to 24 RGB colors, so a 13-color file is valid input. The Mini writer at voice-agent:0x2b97f0 copies only the first 36 channel bytes. Therefore the 13th RGB color is ignored on Mini, not displayed on extra hardware.

duration is a per-frame time in seconds. seconds is a timestamp form whose next duration is the timestamp difference. An FPS supplied by the consumer overrides resource durations; this is how millisecond-looking values such as 16.6 can coexist with the same parser. Consequently the generated led-inventory.tsv is an inventory, not a claim that every file plays with one universal duration interpretation.