v0.29.0 — Themes rebuild + colour pipeline + admin maturity
The first cut tag since v0.16.26. Three big workstreams plus the
usual tail of polish.
Heads-up: the intermediate tags v0.16.27 through v0.28.2 carry
the granular history if you want commit-by-commit detail. This
release rolls them up.
🎨 Themes — rebuilt end-to-end
The v0.16.27 purge stripped the pre-Spectra theme system; v0.29
brings it back with a real builder, image-to-theme extraction, and
a unified browse + edit page. Top-nav → Themes.
- 19 bundled themes across Light / Dark / Movement / base16. Any
theme composes with any of the 9 bundleddata-styleaxes
(Standard / Display / Editorial / Mono / Elegant / Condensed +
Bauhaus / De Stijl / Brutalist). - Unified layout — vertical strip of every theme on the left,
the builder pane in the middle, sticky preview on the right.
Bundled themes show "Duplicate to edit"; user themes are
editable with live preview tracking every input. - Image-to-theme — upload a photo or poster, k-means picks
dominant colours, the assignment heuristic spreads them across
the Spectra tokens (light/dark mode auto-detected). Calibration
source data ported from
paperlesspaper/epdoptimize
(Apache 2.0). - Auto-derive soft tints switch —
accent_N_softbecomes
mix(accent_N, bg, 0.78)on the fly when on. One less thing to
tune. - User themes persist at
data/themes/user.jsonand ride along
in the data-export ZIP. Cascade emitted from/themes/user.css
loaded alongside the bundled Spectra blocks on every composed
page.
🖨️ Colour pipeline
- Opt-in calibrated palette + tone mapping for the
esp32_bin
andpi_binrenderers. Per-device toggle dithers Floyd-Steinberg
against the panel's measured Spectra 6 / ACeP colours instead of
nominal sRGB primaries, paired with a linear tone-map pre-pass
that squeezes the source range into the calibrated black/white
band so the dither has room to spread error. Off by default —
A/B with your own content since the trade-off is content-dependent
(chromatic content tends to gain, neutral greys can pick up a
slight cool cast because the calibrated white is faintly green-blue). - Firmware-native panel orientation auto-detected from the
panel preset. The renderer packs at the firmware's row stride
regardless of how the user mounts the panel, fixing the office
Waveshare 13.3" appearing distorted after rotation. - Pre-v0.20 ESP32 manifest backfill — a startup migration adds
native_w / native_hto existingesp32_clientinstance
manifests so legacy installs paint at the right stride without
a re-add. - Eight dither modes for the
.binpackers: FS, none, Atkinson,
Jarvis-Judice-Ninke, Stucki, Bayer-8x8, halftone, crosshatch.
🔐 Admin maturity
- Change / disable / re-enable password from Settings → System
→ Authentication. With the gate disabled, the server still 403s
public IPs and only lets LAN traffic through — "trust LAN", not
"trust the internet". tesserae --reset-passwordCLI escape hatch for when the
password is lost.- Firmware splash PNGs at nine common sizes
(64 → 1024px) understatic/brand/firmware/for client
builders that want a boot image without re-running Pillow on
the device. - Dev dropdown in the top-nav (under
--dev) groups the Widget
gallery + Theme × style matrix.
✨ Editor / UI polish
- Reactive editor: floating back-to-top FAB on small viewports.
Drag along the bottom to flip side; preference persists. - Composer remounts cells on theme / style / font flip so the
new cascade actually paints instead of inheriting stale variables. - Single-card palette in the theme builder — surfaces, text,
and the six accent pairs collapsed into one card with sub-group
headings. - F1 widget pass: bolder track stroke, backing card behind the
track, team-colour stripe on standings rows, more Phosphor icons. - Weather suite visual punch: shaded line chart in
weather_hourly(12h default),cqmin-scaled hero icon in
weather_now, AQI scale inweather_air_quality, compass rose
inweather_wind, tile cards inweather_pollen_count.
📚 Docs
- README + wiki refreshed against current state (widget count, theme
tally, palette token count, removed-feature scrub). dev/writing-a-plugin.mdrewritten for Spectra — drops the
pre-purge--c-*/--theme-*/ variant-cell-option doctrine;
introduces the semantic-token list, thedata-styleaxis, and
the seven body archetypes.NOTICES.mdadded crediting paperlesspaper/epdoptimize.
Removed (vs v0.16.26)
- The pre-v0.16.27 widget
--c-bg/--c-fg/--c-data-*/
--c-ok/warn/dangertoken cascade. Spectra widgets paint from
--bg,--surface,--text-primary,--accent-1..6, etc.
directly.--c-zoomsurvived as the cell-content-zoom variable. variantcell option from widget manifests — one widget composes
with every (theme, style) pair now.plugins/themes_core/plugin — themes live in
static/style/spectra-*.css+ a Python registry, not the plugin
tree.scripts/capture_widget_variants.py— superseded by
/_test/matrixfor cross-theme / cross-style comparison.
Migration notes
- User themes from before the purge never existed under
v0.16.x's themes_core path on most installs; if you had one
hand-edited atdata/plugins/themes_core/user.json, move it to
data/themes/user.json. The schema fields changed (20 Spectra
tokens instead of the pre-purge 15), so opening it in the new
builder and re-saving is the cleanest path. - ESP32 device manifests missing
native_w / native_hare
backfilled at startup the first time you boot v0.29.0; nothing
for users to do. - Per-widget variant pickers are gone from the editor. Existing
saved pages keep working — the field just isn't read anymore —
but the same widget will render in whichever theme + style the
page picks. If you relied on a specific variant for a specific
cell, set a cell-level theme / style override instead.
Install / upgrade: docs.tesserae.
Full changelog: CHANGELOG.md.