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.
assets partition (partition table v2). Without one, the boot log shows No assets partition found.I. What You Can Customize
| Item | Purpose | Field |
|---|---|---|
| Wake word | A preset WakeNet model, or a MultiNet custom command on ESP32-S3 | srmodels, multinet |
| Text font | The .bin font used for chat text on screen | text_font |
| Emoji set | 21 emotion images in PNG or GIF | emoji_collection |
| Chat background | Text color, background color or image for light and dark themes | skin |
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 table | assets size |
|---|---|
8m.csv | 2 MB |
16m.csv | 8 MB |
16m_c3.csv | 4 MB (limited by available mmap pages) |
32m.csv | 16 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:
- Pick the chip (
esp32s3,esp32c3,esp32p4,esp32c6), the screen type and the resolution. Color is limited to 16-bit RGB565. - Design the theme in four tabs: wake word, font, emoji and chat background.
- 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 word C3 / C6 (WakeNet9s) S3 / P4 (WakeNet9) Hi, Lexin wn9s_hilexinwn9_hilexinHi, ESP wn9s_hiespwn9_hiespNi hao Xiaozhi wn9s_nihaoxiaozhiwn9_nihaoxiaozhi_ttsHi, Jason wn9s_hijason_tts2wn9_hijason_tts2Xiaoai Tongxue - wn9_xiaoaitongxueHai Xiaoou - wn9_hai1xiao3ou1_tts3Ni hao Xiaorui - wn9_ni3hao3xiao3rui4_tts3Custom wake word (MultiNet): the generator currently targets ESP32-S3 only. For Chinese use
mn6_cnormn7_cnwith pinyin input such asni hao xiao zhi; for English usemn6_enormn7_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 namedfont_[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.
neutralis required; any missing emotion falls back toneutral.
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 andindex.jsonbuild/assets.bin: the final SPIFFS resource filebuild/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 theassets.binyou provide.Do not flash assets: leaves theassetspartition alone.
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.bin3. 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:
| Option | Notes |
|---|---|
Wakenet model with AFE | Default (ESP32-S3 / P4 / S31 with PSRAM); supports echo cancellation (AEC) where available |
Wakenet model without AFE | For ESP32-C3 / C5 / C6, and ESP32 with PSRAM |
Multinet model (Custom Wake Word) | Custom wake word; needs ESP32-S3 / P4 / S31 with PSRAM |
Disabled | Turns the wake word off |
With the custom wake word selected you can also set:
CUSTOM_WAKE_WORD: pinyin for Chinese, words separated by spaces; defaultxiao tu douCUSTOM_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 log | Likely cause | Fix |
|---|---|---|
No assets partition found / Assets partition is disabled | The partition table has no assets partition | Use a v2 partition table or a supported board |
Checksum mismatch (checksum ... does not match) | Damaged assets.bin or wrong write offset | Rebuild and check the offset in the partition table |
The assets version N is not supported, please upgrade the firmware | The index version is newer than the firmware supports | Upgrade the firmware, or rebuild with a matching generator |
Assets file size ... is larger than partition size | The file exceeds the assets partition | Use 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 display | Convert the font again and check size and bpp |
Related Documents
- Custom Board Guide: add a board and choose a partition table
- Glyph Push Extension: add characters the font does not contain on demand
- Supported Boards: firmware variants for each board
- Firmware download: the basics of writing firmware
Sources
- 78/xiaozhi-esp32 v2.5.2:
scripts/spiffs_assets/README.md,main/assets.cc,main/Kconfig.projbuild,main/CMakeLists.txt,main/mcp_server.cc,partitions/v2/README.md - 78/xiaozhi-assets-generator: README