One of VA5's features that the students love most is its animated emojis. On the technical side, the emoji face is 150x150 RGB565 frames, up to eight per mood, seven moods. Any of them can be replaced with your own GIF, PNG, JPG or MP4 from a page the device serves.
The obvious build is to upload the GIF to the ESP32 and decode it there. I didn't, and I'd push back on anyone who tries.

All image work happens in the user's browser. GIF decode, frame extraction, resize to 150x150, RGB565 little-endian conversion, zip pack and unpack — all JavaScript, on the phone or the laptop. The ESP32 only ever receives raw frame bytes, N x 45,000 of them, and writes them to LittleFS. It never decodes an image format in its life.
That buys three things:
- no image codecs in firmware
- no PSRAM spent on decode buffers competing with a 1.4 MB audio ring buffer
- and when MP4 support arrived in v0.9, it was a JavaScript change rather than a firmware change.
Two details that matter more than they look.
- Staged atomic writes. Frames stream into /custom_stage/ and are renamed into /custom/ only once the whole upload validates. A dropped connection mid-upload can't leave a half-replaced mood on screen, and /custom_stage/ is swept on boot in case a previous upload died partway.
- The defaults are untouchable. /default/ and /custom/ are a two-directory overlay — the loader probes /custom/ first and falls back. The shipped set is never overwritten, so no sequence of uploads can brick the display. Reset one mood or all of them, any time.
The trade-off, stated plainly: customizing needs your browser online, because the page pulls omggif and JSZip from a CDN. The device itself stays local-only.
Full source: https://github.com/iollama/Voice-Assistant-5
Udi Tirosh
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.