Custom Assets Guide: Wake Word, Fonts, Emoji and Chat Background

Custom Assets Guide: Wake Word, Fonts, Emoji and Chat Background

The XiaoZhi firmware packs the wake word model, text font, emoji images and chat background into one assets.bin, which lives in the assets partition of the Flash. Replace that file and you change the look and the wake word of the device without touching the application code. This guide explains what assets.bin contains, how to build it, and how to write it to a device.

This page follows upstream v2.5.2 and xiaozhi-assets-generator. It only works on boards whose partition table contains an assets partition (partition table v2). Without one, the boot log shows No assets partition found.

I. What You Can Customize

ItemPurposeField
Wake wordA preset WakeNet model, or a MultiNet custom command on ESP32-S3srmodels, multinet
Text fontThe .bin font used for chat text on screentext_font
Emoji set21 emotion images in PNG or GIFemoji_collection
Chat backgroundText color, background color or image for light and dark themesskin

All of these are described by index.json inside assets.bin; see “V. The index.json Structure”.

II. The assets Partition

Partition table v2 reserves an assets partition (type data, subtype spiffs) for each Flash size. Sizes from the upstream partitions/v2/README.md:

Partition tableassets size
8m.csv2 MB
16m.csv8 MB
16m_c3.csv4 MB (limited by available mmap pages)
32m.csv16 MB

assets.bin must not exceed the partition. At boot the device verifies the header and checksum; if verification fails, the partition is not enabled.

III. Build assets.bin

Option 1: The Assets Generator (Recommended)

xiaozhi-assets-generator is a single-page app. It builds assets.bin locally in the browser and needs no backend. There are three steps:

  1. Pick the chip (esp32s3, esp32c3, esp32p4, esp32c6), the screen type and the resolution. Color is limited to 16-bit RGB565.
  2. Design the theme in four tabs: wake word, font, emoji and chat background.
  3. Review the list of items to pack and click generate. Custom fonts take longer; converted results are cached so regenerating is faster.

Rules for each tab:

Wake word

  • Preset wake words (WakeNet): ESP32-C3 / C6 support only WakeNet9s models, and ESP32-S3 / P4 support only WakeNet9 models.

    Wake wordC3 / C6 (WakeNet9s)S3 / P4 (WakeNet9)
    Hi, Lexinwn9s_hilexinwn9_hilexin
    Hi, ESPwn9s_hiespwn9_hiesp
    Ni hao Xiaozhiwn9s_nihaoxiaozhiwn9_nihaoxiaozhi_tts
    Hi, Jasonwn9s_hijason_tts2wn9_hijason_tts2
    Xiaoai Tongxue-wn9_xiaoaitongxue
    Hai Xiaoou-wn9_hai1xiao3ou1_tts3
    Ni hao Xiaorui-wn9_ni3hao3xiao3rui4_tts3
  • Custom wake word (MultiNet): the generator currently targets ESP32-S3 only. For Chinese use mn6_cn or mn7_cn with pinyin input such as ni hao xiao zhi; for English use mn6_en or mn7_en. You can set the threshold (0-100) and the timeout.

Font

  • Preset fonts are Alibaba PuHuiTi, covering about 7000 common characters: font_puhui_14_1, font_puhui_16_4, font_puhui_20_4, font_puhui_30_4 (naming: name_size_bpp).
  • Custom fonts accept TTF and WOFF, size 8-80, bpp 1, 2 or 4. The character set is GB2312 (7445 characters) or DeepSeek R1 (7405 characters, the default). Conversion uses lv_font_conv, and the output is named font_[name]_[size]_[BPP].bin.

Emoji set

A set has 21 images. neutral is the default; the others are happy, laughing, funny, sad, angry, crying, loving, embarrassed, surprised, shocked, thinking, winking, cool, relaxed, delicious, kissy, confident, sleepy, silly, confused.

  • Presets: Twemoji 32x32 or 64x64 PNG.
  • Custom: one common width and height (not larger than the screen), GIF animation or transparent PNG. neutral is required; any missing emotion falls back to neutral.

Chat background

Light and dark modes are configured separately. Defaults are #ffffff (light) and #121212 (dark). You can change the colors or use a static image. Images are fitted to the screen resolution; the format is usually an RGB565 bitmap with a 64-byte header holding an lv_image_dsc_t.

Option 2: The scripts/spiffs_assets Command Line

The firmware repository includes scripts/spiffs_assets/build.py, which packs a wake word model, a font and an emoji folder into assets.bin (Python 3.6+ required):

cd scripts/spiffs_assets

./build.py \
    --wakenet_model ../../managed_components/espressif__esp-sr/model/wakenet_model/wn9_nihaoxiaozhi_tts \
    --text_font ../../components/noto-fonts/cbin/font_noto_sans_common_20_4.bin \
    --emoji_collection ../../components/noto-fonts/png/noto-color-emoji_64/

All three arguments are optional, so you can pack only what you need. The emoji folder accepts .png and .gif. The script rebuilds the build/ folder and produces:

  • build/assets/: all resource files and index.json
  • build/assets.bin: the final SPIFFS resource file
  • build/config.json, build/output/: build configuration and intermediate files

IV. Write It to the Device

Pick one of three ways.

1. Flash it at build time

In idf.py menuconfig, open “Xiaozhi Assistant”, set Flash Assets to Flash Custom Assets and fill in Custom Assets File. The value can be a local file or an http:// or https:// URL. The next idf.py flash writes it to the assets partition.

Options:

  • Flash Default Assets (default): packs the default resources from the current sdkconfig.
  • Flash Emote Assets: selectable only when the Emote message style is enabled; builds and writes the emote resources.
  • Flash Custom Assets: uses the assets.bin you provide.
  • Do not flash assets: leaves the assets partition alone.
When CUSTOM_ASSETS_FILE is a relative path, main/CMakeLists.txt resolves it against the main/ folder, which differs from the “project directory” in the Kconfig help text. Use an absolute path to avoid a “file not found” build failure.

2. Flash the partition directly

Find the offset of the assets row in your partition table, for example 0x800000 and 8 MB in partitions/v2/16m.csv, then run:

# Replace the offset with the assets row of your partition table
esptool.py -b 460800 write_flash -z 0x800000 assets.bin

3. Let the device download it through MCP

Host assets.bin at an HTTP(S) address the device can reach, then call the user-only MCP tool self.assets.set_download_url with the url argument. The device stores the address. On its next boot after connecting to the network (before the firmware version check), it takes the address and clears it, shows the download progress, erases and writes the assets partition, and applies the new resources. The address is used once, so set it again if a download fails; the file must not be larger than the partition. For tool usage, see MCP IoT Control Usage.

V. The index.json Structure

index.json inside assets.bin describes each resource. This is the example from the generator documentation (some emoji omitted):

{
    "version": 1,
    "chip_model": "esp32s3",
    "display_config": {
        "width": 320,
        "height": 240,
        "monochrome": false,
        "color": "RGB565"
    },
    "srmodels": "srmodels.bin",
    "text_font": "font_puhui_common_30_4.bin",
    "skin": {
        "light": {
            "text_color": "#000000",
            "background_color": "#FFFFFF",
            "background_image": "background_light.raw"
        },
        "dark": {
            "text_color": "#FFFFFF",
            "background_color": "#121212",
            "background_image": "background_dark.raw"
        }
    },
    "emoji_collection": [
        { "name": "sleepy", "file": "sleepy.png" }
    ],
    "multinet": {
        "model": "mn6_cn",
        "command": "ni hao xiao zhi",
        "threshold": 20,
        "duration": 3000
    }
}

The firmware accepts indexes with version of 1 or lower; a higher version produces a prompt to upgrade the firmware.

VI. Wake Word Only: Build Options

To change just the wake word you do not need an assets.bin. Set Wake Word Implementation Type under “Xiaozhi Assistant” in menuconfig:

OptionNotes
Wakenet model with AFEDefault (ESP32-S3 / P4 / S31 with PSRAM); supports echo cancellation (AEC) where available
Wakenet model without AFEFor ESP32-C3 / C5 / C6, and ESP32 with PSRAM
Multinet model (Custom Wake Word)Custom wake word; needs ESP32-S3 / P4 / S31 with PSRAM
DisabledTurns the wake word off

With the custom wake word selected you can also set:

  • CUSTOM_WAKE_WORD: pinyin for Chinese, words separated by spaces; default xiao tu dou
  • CUSTOM_WAKE_WORD_DISPLAY: the greeting sent to the server after detection; default 小土豆
  • CUSTOM_WAKE_WORD_THRESHOLD: 1-99, smaller is more sensitive; default 20

VII. Troubleshooting

Symptom or logLikely causeFix
No assets partition found / Assets partition is disabledThe partition table has no assets partitionUse a v2 partition table or a supported board
Checksum mismatch (checksum ... does not match)Damaged assets.bin or wrong write offsetRebuild and check the offset in the partition table
The assets version N is not supported, please upgrade the firmwareThe index version is newer than the firmware supportsUpgrade the firmware, or rebuild with a matching generator
Assets file size ... is larger than partition sizeThe file exceeds the assets partitionUse fewer emoji, a smaller font size or bpp, or a larger partition table
Font not applied (Ignoring invalid text font asset)The font file is invalid or incompatible with the displayConvert the font again and check size and bpp

Related Documents

Sources