09 — EMBEDDED · 2026
CubeFeed
An ESP32-S3 desk display that serves its own configuration dashboard off its own flash: no app, no account, no cloud.
- Built
- A desk display and its firmware, which serves its own setup page.
- Stack
- ESP32-S3, Arduino C++ (arduino-cli), a PSRAM compositor, a vanilla JavaScript dashboard on flash; the device fetches its own data (Flask backend optional).
- State
- In use; last firmware change April 2026.
IN USE · UPDATED 2 OCT 2026
Firmware working; last changed April 2026
Carter Barnes · cloud engineer, federal Azure · Contact








What it is
A desk display that shows whatever you point it at: stocks, weather, crypto, air quality, news, sports, now-playing. A Waveshare ESP32-S3 1.9-inch touch display (170×320) runs the firmware and fetches the data itself; the Flask backend from the first version is now optional.
The difference is that the configuration UI lives on the device. There is no app to install and no cloud account. You open the display's own address and drag cards around.
How it works
- Firmware
- Arduino C++, compiled with arduino-cli, with a PSRAM compositor: the whole frame is composed off-screen, so the panel never tears.
- Cards
- Seven renderers behind one card interface: metric, weather, media, time, list, status and alert, each with loading, error, empty and stale states. A new data source means a new fetcher, not a new renderer.
- Layouts
- Five in the builder: stacked, grid, focused, media, minimal. One resolver pairs each layout's rectangles with its zone names, and both the device and the dashboard preview call it, so they cannot disagree about where a zone is.
- Themes
- Ten, applied across every layout.
- Dashboard
- A vanilla JavaScript single-page app on LittleFS, with zero build step.
- Sensors
- A six-axis IMU for auto-rotate, a battery and buttons. Four full-screen reactive scenes run off tilt and touch; a microphone, a light sensor and a PIR are optional and the scenes degrade without them.
By the numbers
- 7
- card renderers behind one interface
- 10
- themes, applied across every layout
- 350
- theme, layout and renderer combinations, none hand-written
- 170×320 px
- 1.9-inch touch panel
What I learned
- 01
Separating what a card is from how it is drawn is what made it scale
Ten themes by five layouts by seven renderers is 350 combinations, and none are hand-written, because a card is a data shape and a renderer is a function of theme and slot.
- 02
A compositor in PSRAM is worth it on a slow SPI panel
Drawing straight to the display is simpler and looks bad. Compose off-screen, push once.
- 03
Serving your own config UI removes a product category of problems
No app, no account, no pairing flow, no cloud outage.
- 04
Zero build step is a feature on a device
The file on flash is the file I edited. There is no bundler to debug over a serial console.
What went wrong
- 01
The dashboard's edits never reached the device
Adding or removing a card in the builder, or applying a preset, only changed the page's own state, so neither the display nor the preview showed the change. Each of those actions now pushes the config to the device and refreshes the preview.
- 02
One layout name fell through to the wrong layout
The resolver sent "stacked" to a different layout whose fixed strips are taller than the 170-pixel screen in landscape, so cards ran off the edge. Every layout is now dispatched by name, and an unknown name falls back to stacked.
