Play your mascot on an ESP32 board
The Masko player runs on ESP32-S3 boards with a screen. It plays your released canvas as on a phone: a loop for each pose, the moves between them, and the reactions your firmware asks for. Each clip arrives as a .mkpk pack, JPEG frames on a solid background that the board decodes as it plays.
There are two ways to put the mascot on the board:
- Over Wi-Fi, from a link. One request with an app key returns the release with a link to each clip, and the board streams the clips from those links.
- From an SD card. One zip holds the release and every clip, for a board without a network.
Both use the same release and the same packs. The ESP32 player is open source: esp32-masko-sdk, written by Marvin Schmid. It is in early development: its reference example plays a mascot.json built into the firmware, which is the delivery below, and streams the packs it lists over Wi-Fi.
What you need
- An ESP32-S3 board with PSRAM and a screen. The reference board is the Waveshare ESP32-S3-Touch-AMOLED-1.75: a 466 px round AMOLED, 8 MB PSRAM and 16 MB flash. The M5Stack StopWatch has the same chip, memory and screen.
- ESP-IDF to build the firmware. The ESP32 player's README gives the version and the commands.
- A released canvas. Each release is what the board plays; a canvas without one has nothing to send.
Over Wi-Fi, from a link
Ask for the latest release with target=esp32 and an app key of the mascot. The app key can only read this mascot's releases, so a board can make the request itself; you can also make it from your computer and give data.delivery to the firmware as its mascot.json.
curl "https://api.masko.ai/v1/canvases/CANVAS_ID/delivery?target=esp32&size=384" \
-H "Authorization: Bearer masko_app_YOUR_APP_KEY"The first time a release is asked for at a size, Masko makes its packs, for free. Until every pack is ready, the answer is 202 with status: "preparing", how many packs are ready out of total, and retry_after in seconds (also in the Retry-After header). Ask again then; it usually takes a few minutes. Later requests answer at once.
The links are permanent on assets.masko.ai when the mascot is public, and signed for a day otherwise. They serve byte ranges, so the board can stream frames instead of downloading a whole clip first. Compare release_id to know when a new release is there.
Wi-Fi speed. A 384 px pack at 24 frames per second needs about 370 KB/s while it streams (460 KB/s at quality 75). On a good home network, the reference board plays at 24 fps once the next clip is in its memory; a weak connection or a phone hotspot stutters on clips it has not loaded yet. The board keeps the clips it may play next in PSRAM, but 8 MB does not hold a whole mascot, so the SD card is steadier for a large canvas.
From an SD card, without Wi-Fi
In the app, open the canvas, choose Export, pick the size under ESP32 board and click Download for ESP32. Through the API, ask for the bundle:
curl -L -o mascot-esp32.zip \
"https://api.masko.ai/v1/canvases/CANVAS_ID/bundle?size=384" \
-H "Authorization: Bearer masko_YOUR_API_KEY"The zip holds:
mascot.json, the same delivery as above, where each clip is a file name such aspacks/rest-581594e9-384.mkpkinstead of a link.packs/, every.mkpkpack the release plays.
Unzip it at the root of the SD card. The newest release is used unless you send release_id. Playing from an SD card builds in the ESP32 player but has not been tested on a board yet. Like the link, the bundle answers 202 while packs are being made; the app's button waits and downloads the zip when they are ready. A 25-clip mascot is about 38 MB at 384 px and 50 MB at 464 px, so it needs a card: the board's built-in flash holds only a few clips.
Pack size and settings
The packs are made for your screen. Without settings, they follow the mascot's own .mkpk setting when it is on, else a 384 px pack on a 466 px screen.
| Setting | Values | Default |
|---|---|---|
size | Frame width, a multiple of 16 from 32 to 1024 | 384 |
screen_width, screen_height | The screen the frames are centred on | 466 |
fps | 1 to 60 | 24 |
quality | JPEG quality, 1 to 100 | 60 |
background_color | The colour behind the mascot, #RRGGBB (send %23 for #) | #000000 |
On the 466 px round screen, 384 keeps the whole mascot inside the circle and 464 fills the screen, with ears or feet cut by the edge on some mascots. Quality 60 looks the same as 75 on this screen and is about a fifth lighter; below 50, blocks start to show. fps=12 halves the files again, with less smooth motion, for a slow connection or a small card. For another screen, such as a 240 px round one, send size=240&screen_width=240&screen_height=240.
What a board plays
The delivery holds the same poses, moves and inputs as on any other platform, with three differences for a board:
- Each clip's file is
videos.mkpk. Edges withsource: "*"have no file: they choose the pose to go to when an input is on. - A move with
reverse: truecarries the pack of the move it returns from: play it backwards. One pack serves both directions, which halves what the board stores. - Poses have no still picture and clips have no sound.
Credits
The ESP32 player was written by Marvin Schmid, who built the .mkpk format, the ESP-IDF components and the Wi-Fi streaming, and measured them on the Waveshare board. It is MIT-licensed: hehimself/esp32-masko-sdk.
