Tesserae: E-ink dashboard companion. Compose dashboards and push to e-ink panels Developer Kayden released Tesserae, an open-source, self-hosted dashboard companion for e-ink displays that renders tile-based dashboards in headless Chromium (Playwright) at panel resolution and pushes frames to panels over MQTT or HTTP. Tesserae, licensed AGPL-3.0-or-later, applies Floyd-Steinberg dithering against each panel's measured color palette, using calibrated measurements from epdoptimize, then packs frames into the panel's native byte format — packed 4-bit Spectra 6, 1-bit mono, or 4-bit grayscale. The server requires no account and contacts api.tesserae.ink only for update checks, an anonymous install count and an opt-in daily heartbeat, while a separate hosted Tesserae Cloud is offered for users who do not want to run a server. Nine panels, one Tesserae server. Self-hosted dashboard companion for e-ink displays. Compose tile-based dashboards in a browser, render the frame headless, push it to one or more panels over MQTT or HTTP. Note Available for contract work. I'm Kayden. I created Tesserae and maintain it, with help from a growing group of contributors. I take on contracts building with AI: custom agents, MCP servers that connect AI models to your tools and data, and AI-assisted development workflows for teams. I also take on full-stack, embedded and Home Assistant projects, the same work Tesserae is built from. If Tesserae is useful to you, sponsoring helps keep it independent and actively maintained. Email me about a contract mailto:dmellok@icloud.com?subject=Contract%20work%20enquiry · Sponsor on GitHub https://github.com/sponsors/dmellok · Support on Ko-fi https://ko-fi.com/dmellok Open source under AGPL-3.0-or-later. The self-hosted server needs no account and never has to talk to us: the only outbound contact is api.tesserae.ink for update checks, an anonymous install count, and a daily aggregate heartbeat, off by default and opt-in you're asked once at first-run setup; toggle in Settings → System → Online features . Tesserae Cloud https://cloud.tesserae.ink/ is a separate hosted Tesserae for people who would rather not run a server: sign in, create a dashboard, and connect your display. This self-hosted server stays the full product and stays free, and a supported panel is not tied to the cloud: it can be pointed at a server of your own at any time, though dashboards made in the cloud are specific to it and would need recreating here. 📖 Full documentation https://docs.tesserae.ink/ : install guides, hardware quickstarts https://docs.tesserae.ink/quickstart/ , widget gallery https://docs.tesserae.ink/widgets/gallery/ , community catalog https://tesserae.ink/catalog/ , architecture deep dive https://docs.tesserae.ink/dev/architecture/ , how to build a widget https://docs.tesserae.ink/dev/writing-a-widget/ , how to add hardware support https://docs.tesserae.ink/dev/adding-hardware/ . mkdir tesserae && cd tesserae curl -fsSLO https://raw.githubusercontent.com/dmellok/tesserae/main/docker-compose.yml docker compose up -d Open http://localhost:8765 http://localhost:8765 . First request walks through password setup and the onboarding wizard. Other install paths: Home Assistant App https://docs.tesserae.ink/install/home-assistant/ , Proxmox VE helper script https://docs.tesserae.ink/install/lxc/ proxmox-ve-helper-script , LXC / MicroCloud https://docs.tesserae.ink/install/lxc/ , macOS / Linux / Pi shell installer https://docs.tesserae.ink/install/server/ , Windows PowerShell https://docs.tesserae.ink/install/server/ , manual venv https://docs.tesserae.ink/install/server/ manual-install . Server is running? Pick a hardware quickstart https://docs.tesserae.ink/quickstart/ to get a panel on the wall. Dashboards are plain HTML. The editor preview and the production render load the same URL : a headless Chromium Playwright screenshots the composition at panel resolution, so "looked fine in the editor, broke on the panel" is impossible by construction. The frame then goes through a per-device renderer: Floyd-Steinberg dithering against the panel's measured color palette Spectra 6 and ACeP panels don't actually produce sRGB primaries; calibrated measurements come from epdoptimize https://github.com/paperlesspaper/epdoptimize , then packing into the exact byte format the panel wants: packed 4-bit Spectra 6, 1-bit mono, or 4-bit grayscale. Devices are deliberately thin clients with no on-device image decoding. Always-on clients a Pi driving an Inky get frames pushed over MQTT the moment a page changes. Battery clients ESP32 wake, GET their frame over REST with If-None-Match a 304 skips both the download and the slow e-ink refresh , POST battery + RSSI telemetry, and deep-sleep on a server-driven interval. Wall-clock time comes from the HTTP Date header, so there's no SNTP on-device. browser editor Tesserae server panels ┌──────────┐ HTTP ┌──────────────────────┐ MQTT ┌─────────────┐ │ composer │─────────▶│ headless render │─────────▶│ Pi + Inky │ │ /compose │ │ dither measured │ ├─────────────┤ └──────────┘ │ palettes │ REST │ ESP32, │ │ pack panel-native │◀────────▶│ Kindle, │ │ schedule / rotate │ │ TRMNL │ └──────────────────────┘ └─────────────┘ Every layer is a drop-a-folder plugin: widgets, themes, renderers, transports, and device kinds. The seams are real directories: plugins/ https://github.com/dmellok/tesserae/blob/main/plugins · renderers/ https://github.com/dmellok/tesserae/blob/main/renderers · transports/ https://github.com/dmellok/tesserae/blob/main/transports · devices/ https://github.com/dmellok/tesserae/blob/main/devices . Build dashboards with AI MCP . Tesserae exposes an MCP https://modelcontextprotocol.io API so an agent can lay out a freeform dashboard, render a preview to check its work, and push it to a panel. It's on by default; run the tesserae-mcp https://github.com/dmellok/tesserae-mcp bridge on your agent's machine a remote agent needs the token from Settings → System → MCP . See the docs https://docs.tesserae.ink/dev/mcp/ . Server-side rendering, dumb firmware. The server pre-renders each frame into the exact bytes the panel controller wants; the device firmware https://github.com/dmellok/tesserae-device-firmware streams them straight to the panel. Adding a new panel is a board header plus one driver. The network, power, and provisioning stack never changes. Widget network egress is allowlisted. Third-party widgets declare the network hosts they need in a requires: block in plugin.json , and the host enforces the allowlist at the socket layer. An undeclared connection raises CapabilityDenied instead of phoning home. That is the extent of the containment: widgets otherwise run in-process, and the trust model is PR review of the community catalog, not a sandbox. The threat model https://docs.tesserae.ink/dev/publishing-a-widget/ is documented honestly, including what it doesn't catch. One server, a fleet of panels. Tesserae splits rendering from transport from hardware, so a single instance drives every panel in the house, each with its own dashboards, schedules, and rotations. Community widgets install from an audited catalog. Pinned release tarballs, sha256-verified, schema-validated, PR-reviewed: tesserae-widgets https://github.com/dmellok/tesserae-widgets . Tesserae renders to one of several panel families through drop-a-folder device plugins. In the tables below, ✅ means the panel has been confirmed on real hardware on my bench or via a community report ; TBD means a client and hardware profile ship but nobody has confirmed a frame on the physical panel yet. The per-renderer bench matrix lives at Screens & compatibility https://docs.tesserae.ink/compatibility/ . Some links below are affiliate links. Seeed product links and the Pimoroni Inky Frame and Inky Impression links carry a Tesserae affiliate tag: buying through one pays a small commission that goes back into the project, and a Seeed link also gets you a discount at checkout. Nothing is listed here because of it, and a panel's ✅ / TBD status means exactly what it says above. Links without the tag are plain product links. The reTerminal E-Series and XIAO ePaper family run the Tesserae-native firmware https://github.com/dmellok/tesserae-device-firmware ; flash from the browser in one click at tesserae.ink/flash https://tesserae.ink/flash Chrome / Edge, Web Serial, no toolchain . Battery-powered, no assembly required. | Model | Panel | Client | Status | |---|---|---|---| | reTerminal E1001 https://www.seeedstudio.com/reTerminal-E1001-p-6534.html?sensecap affiliate=YcT0R1h&referring service=link | 7.5" mono, 800×480 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | ✅ | | reTerminal E1002 https://www.seeedstudio.com/reTerminal-E1002-p-6533.html?sensecap affiliate=YcT0R1h&referring service=link | 7.3" Spectra 6, 800×480 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | ✅ | | reTerminal E1003 https://www.seeedstudio.com/reTerminal-E1003-p-6731.html?sensecap affiliate=YcT0R1h&referring service=link | 10.3" mono, 16-level grey, 1872×1404 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | ✅ | | reTerminal E1004 https://www.seeedstudio.com/reTerminal-E1004-p-6692.html?sensecap affiliate=YcT0R1h&referring service=link | 13.3" Spectra 6, 1200×1600 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | ✅ | | reTerminal Sticky https://www.seeedstudio.com/reTerminal-Sticky-p-6861.html?sensecap affiliate=YcT0R1h&referring service=link | 3.97" mono, 4-level grey, 480×800 portrait | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | ✅ | | XIAO ePaper EE02 https://www.seeedstudio.com/XIAO-ePaper-DIY-Kit-EE02-for-13-3-Spectratm-6-E-Ink.html?sensecap affiliate=YcT0R1h&referring service=link | 13.3" Spectra 6, 1200×1600 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | ✅ | | XIAO ePaper EE03 https://www.seeedstudio.com/XIAO-ePaper-DIY-Kit-EE03-for-10-3-Monochrome-ePaper-Display.html?sensecap affiliate=YcT0R1h&referring service=link | 10.3" mono, 16-level grey, 1872×1404 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | TBD | | XIAO 7.5" ePaper Panel https://www.seeedstudio.com/XIAO-7-5-ePaper-Panel-p-6416.html | 7.5" mono, 800×480 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | TBD | | TRMNL 7.5" OG DIY Kit https://www.seeedstudio.com/TRMNL-7-5-Inch-OG-DIY-Kit-p-6481.html?sensecap affiliate=YcT0R1h&referring service=link | 7.5" mono, 800×480 | TRMNL firmware | ✅ via BYOS | The PaperS3's screen has no controller chip: the ESP32-S3 drives the glass directly and the 16 grey levels come from a waveform table in the firmware rather than from the panel. Greyscale tuning is therefore a firmware change. Partial refresh is not implemented yet, so this panel has no tap echo or on-device touch controls, and its touch digitiser is not wired up. The link goes to M5's documentation rather than their store: M5 have marked the PaperS3 end of life and it is sold out, so this entry is for people who already own one. The original M5Paper pre-S3, classic ESP32-D0WDQ6-V3 drives the same 4.7" glass through an IT8951 controller over SPI, so it reuses the reTerminal E1003's greyscale driver. Also discontinued; this entry is for existing owners. The PaperMono 2026, Pro and Lite is a 3.97" 480x800 4-level greyscale handheld on the reTerminal Sticky's controller family, so it reuses that driver and wire format; its panel rails sit behind an I2C IO expander and its battery is read from the on-board PMIC. Confirmed on hardware; touch, microSD and the frontlight are not wired yet. | Model | Panel | Client | Status | |---|---|---|---| | M5Paper https://docs.m5stack.com/en/core/m5paper | 4.7" mono, 16-level grey, 960×540 IT8951 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | ✅ | | PaperS3 https://docs.m5stack.com/en/core/PaperS3 | 4.7" mono, 16-level grey, 960×540 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | TBD | | PaperMono / PaperMono Lite https://docs.m5stack.com/en/core/PaperMono | 3.97" mono, 4-level grey, 480×800 portrait SSD1677 | tesserae-device-firmware https://github.com/dmellok/tesserae-device-firmware | ✅ | | Panel | Resolution | Client | Status | |---|---|---|---| | Inky Impression 4" https://collabs.shop/ko5ulg 6-colour Spectra 6 | 600×400 | tesserae-device-pi https://github.com/dmellok/tesserae-device-pi | ✅ | | Inky Impression 4" legacy 7-colour ACeP | 640×400 | tesserae-device-pi https://github.com/dmellok/tesserae-device-pi | ✅ | | Inky Impression 5.7" https://shop.pimoroni.com/products/inky-impression-5-7 7-colour ACeP | 600×448 | tesserae-device-pi https://github.com/dmellok/tesserae-device-pi | ✅ | | Inky Impression 7.3" https://collabs.shop/ko5ulg 6-colour Spectra 6 | 800×480 | tesserae-device-pi https://github.com/dmellok/tesserae-device-pi | ✅ | | Inky Impression 13.3" https://collabs.shop/ko5ulg 6-colour Spectra 6 | 1600×1200 | tesserae-device-pi https://github.com/dmellok/tesserae-device-pi | ✅ | | Inky pHAT https://shop.pimoroni.com/products/inky-phat / wHAT https://shop.pimoroni.com/products/inky-what | various | tesserae-device-pi https://github.com/dmellok/tesserae-device-pi | works via pi png | The Inky Frame and the Badgers carry their own microcontroller, so they need no Raspberry Pi. The Inky Frame runs tesserae-device-inkyframe https://github.com/dmellok/tesserae-device-inkyframe Pico SDK firmware, the Tesserae fork of Carl Partridge's client: setup from a phone, button letters, signed over-the-air updates ; flash it from the browser at tesserae.ink/flash/inky-frame https://tesserae.ink/flash/inky-frame Chrome / Edge, WebUSB, no toolchain . The Badgers run tesserae-device-badger https://github.com/dmellok/tesserae-device-badger , an app inside the badge's own launcher, so the badge keeps its other apps. | Panel | Resolution | Client | Status | |---|---|---|---| | Inky Frame 7.3" https://collabs.shop/7ab9wa 6-colour Spectra 6, Pico 2 W | 800×480 | tesserae-device-inkyframe https://github.com/dmellok/tesserae-device-inkyframe | ✅ | | Inky Frame 7.3" legacy 7-colour ACeP | 800×480 | tesserae-device-inkyframe https://github.com/dmellok/tesserae-device-inkyframe | TBD | | Badger 2350 https://shop.pimoroni.com/products/badger-2350 | 264×176, 4-level grey | tesserae-device-badger https://github.com/dmellok/tesserae-device-badger | ✅ | | Badger 2040 W https://shop.pimoroni.com/products/badger-2040-w | 296×128, mono | tesserae-device-badger https://github.com/dmellok/tesserae-device-badger | TBD | | Panel | Resolution | Client | Status | |---|---|---|---| | Waveshare 13.3" Spectra 6 ESP32-S3 https://www.waveshare.com/esp32-s3-epaper-13.3e6.htm | 1200×1600 | esp32-bin https://github.com/dmellok/tesserae-device-esp32-bin | ✅ | | Waveshare 7.3" PhotoPainter ESP32-S3 https://www.waveshare.com/esp32-s3-photopainter.htm | 800×480 | photopainter-7.3-bin https://github.com/dmellok/tesserae-device-photopainter-7.3-bin | ✅ | | Waveshare 4.2" B/W ESP32 https://www.waveshare.com/4.2inch-e-paper-module.htm | 400×300 | esp32-bw https://github.com/dmellok/tesserae-device-esp32-bw | TBD | Xteink's X-series e-readers run CrossInk https://github.com/uxjulia/CrossInk firmware with Tesserae client support: the dashboard becomes the reader's sleep screen, painted on the sleep transition rather than on a timer. | Model | Panel | Client | Status | |---|---|---|---| | Xteink X3 4-level grayscale | 792×528, gray | CrossInk | ✅ | | Xteink X3 mono | 792×528, mono | CrossInk | TBD | | Xteink X4 | 800×480, mono | CrossInk | ✅ | | Xteink X4 4-level grayscale | 800×480, gray | CrossInk | ✅ | | Xteink X4 Pro | 800×480, mono | CrossInk | TBD | Community-authored clients, contributed and maintained by their authors not in the Tesserae org . Thanks to everyone building these. | Panel | Resolution | Client | Status | |---|---|---|---| | PicPak 4.2" BWRY https://docs.tesserae.ink/hardware/picpak/ | 400×300 4-colour BWRY | picpak-tesserae-client https://github.com/varanu5/picpak-tesserae-client by @varanu5 https://github.com/varanu5 | ✅ | | ZecTrix NOTE4C Devkit https://docs.tesserae.ink/hardware/note4c/ | 400×300 4-colour BWRY | note4c-tesserae-client https://github.com/varanu5/zectrix-note4c-devkit-tesserae-client by @varanu5 https://github.com/varanu5 | ✅ | | Soldered Inkplate 10 https://soldered.com/products/inkplate-10 | 1200×825 9.7" 16-level grey | tesserae.inkplate https://github.com/partridgeworks/tesserae.inkplate by @partridgeworks https://github.com/partridgeworks | ✅ | | Soldered Inkplate 6COLOR https://soldered.com/products/inkplate-6color-e-paper-display | 600×448 5.85" 7-colour ACeP | inkplate-tesserae-driver https://github.com/ripking/inkplate-tesserae-driver by @ripking https://github.com/ripking | ✅ | | Soldered Inkplate 13SPECTRA https://soldered.com/products/inkplate-13spectra | 1600×1200 13.3" Spectra 6 | inkplate-tesserae-driver https://github.com/ripking/inkplate-tesserae-driver by @ripking https://github.com/ripking | ✅ | | Pimoroni Inky Frame 7.3" https://shop.pimoroni.com/products/inky-frame-7-3 7-colour ACeP | 800×480 | tesserae.inkyframe https://github.com/partridgeworks/tesserae.inkyframe by @partridgeworks https://github.com/partridgeworks | ✅ | | Pimoroni Inky Frame 7.3" 6-colour Spectra 6 | 800×480 | tesserae.inkyframe https://github.com/partridgeworks/tesserae.inkyframe by @partridgeworks https://github.com/partridgeworks | TBD | | reMarkable 2 https://remarkable.com/products/remarkable-2 | 1404×1872 10.3" 16-level grey | tesserae.remarkable https://github.com/partridgeworks/tesserae.remarkable by @partridgeworks https://github.com/partridgeworks | ✅ | | reMarkable 1 https://remarkable.com | 1404×1872 10.3" 16-level grey | tesserae.remarkable https://github.com/partridgeworks/tesserae.remarkable by @partridgeworks https://github.com/partridgeworks | TBD | | reMarkable Paper Pro https://remarkable.com/products/remarkable-paper/pro | 1620×2160 11.8" colour | tesserae.remarkable https://github.com/partridgeworks/tesserae.remarkable by @partridgeworks https://github.com/partridgeworks | TBD | E-readers running KOReader https://koreader.rocks with the Tesserae plugin https://github.com/dmellok/tesserae-koreader . The plugin pairs with a claim code, decodes 16-level greyscale frames on the reader, and sleeps between refreshes where KOReader exposes the hardware alarm. Kindles need a jailbreak to run KOReader; Kobo does not. | Panel | Resolution | Client | Status | |---|---|---|---| | Kindle Paperwhite 2 jailbroken | 758×1024 | tesserae-koreader https://github.com/dmellok/tesserae-koreader | TBD | | Kindle Paperwhite 3/4, Voyage, Basic 4 | 1072×1448 | tesserae-koreader https://github.com/dmellok/tesserae-koreader | TBD | | Kindle Paperwhite 5, Oasis 3, Scribe | 1236×1648, 1264×1680, 1860×2480 | tesserae-koreader https://github.com/dmellok/tesserae-koreader | TBD | | Kobo Clara HD, Libra 2, Sage, Aura | various | tesserae-koreader https://github.com/dmellok/tesserae-koreader | TBD | Any client implementing the TRMNL BYOS spec https://help.trmnl.com/en/articles/12263392-connect-your-device-to-terminus-byos works against the trmnl png renderer. | Panel | Resolution | Client | Status | |---|---|---|---| | TRMNL OG https://shop.trmnl.com/products/trmnl | 800×480 | TRMNL firmware | TBD via BYOS | | TRMNL X https://shop.trmnl.com/products/trmnl-x | 1872×1404 10.3" | TRMNL firmware | TBD | | Amazon Kindle Paperwhite 2 jailbroken | 758×1024 | KOReader trmnl-display plugin https://github.com/koreader/koreader 1-bit; see the KOReader section above for the Tesserae plugin | ✅ | Anything else: pick custom in Settings → Panel and set the dimensions. If a client drives your panel, Tesserae can push frames to it. A generic CircuitPython client 400+ boards is in development; follow discussion 24 https://github.com/dmellok/tesserae/discussions/24 . Per-client setup walkthroughs the firmware repos in the Client column : Install a client https://docs.tesserae.ink/install/clients/ . Full renderer / device-kind compatibility matrix: Screens & compatibility https://docs.tesserae.ink/compatibility/ . Pre-1.0 and moving fast. Every release is documented in the CHANGELOG https://github.com/dmellok/tesserae/blob/main/CHANGELOG.md . CI runs pytest 7,700+ tests , the Lineups browser tests in Chromium, ruff, and mypy strict on the render/push pipeline modules on every push; coverage 86% at last count is measured weekly, report only. Built with AI assistance Claude Code . Architecture decisions, code review, hardware testing, and what ships vs. what doesn't are mine. The changelogs document the debugging in the open. Tesserae contacts one first-party endpoint, api.tesserae.ink , for update checks, an anonymous marketplace install count, and a daily aggregate heartbeat version, platform, deployment kind, device kinds; no exact counts . No accounts, no personal data, no IP addresses stored, no third-party analytics. It is off by default and opt-in: a fresh install asks once at first-run setup, and it's a single switch at Settings → System → Online features . Per-device diagnostics battery, RSSI, sleep cadence stay on the box. Privacy https://docs.tesserae.ink/privacy/ . - Discussions https://github.com/dmellok/tesserae/discussions for show-your-dashboard, widget pitches, and install help. - Contributing guide https://github.com/dmellok/tesserae/blob/main/.github/CONTRIBUTING.md for dev setup, the three checks pytest / ruff / mypy , and commit conventions. Good first issues https://github.com/dmellok/tesserae/labels/good%20first%20issue . - Hardware reports https://github.com/dmellok/tesserae/issues/new?template=hardware compat.yml : running an unlisted panel? A compat report is a real contribution. - Security policy https://github.com/dmellok/tesserae/blob/main/.github/SECURITY.md · Code of conduct https://github.com/dmellok/tesserae/blob/main/.github/CODE OF CONDUCT.md The server stays free even when someone runs it as a service: improvements have to stay public. And a dashboard for your home shouldn't report home. No analytics, no accounts, nothing phones out. Don't take the README's word for it; read the source. Tesserae stands on generously-licensed open source: Phosphor Icons, Chart.js, 20 typefaces under SIL OFL / Apache 2.0, the TRMNL BYOS protocol, the KOReader trmnl-display plugin, and paperlesspaper/epdoptimize https://github.com/paperlesspaper/epdoptimize 's Spectra 6 + ACeP calibrated palette measurements also shipped as selectable presets in the Calibration tab under Apache 2.0 . Full attribution: Credits https://docs.tesserae.ink/credits/ , NOTICES.md https://github.com/dmellok/tesserae/blob/main/NOTICES.md . AGPL-3.0-or-later, see LICENSE https://github.com/dmellok/tesserae/blob/main/LICENSE .