CSS theme system — the viewer's UI chrome (controls, panels, banners,
dialogs, menus) is now themed via plain CSS under
py/pytanga/viz/templates/themes/, with a registry.json that resolves a
theme id (dark, light, or a custom theme like pastel) to an ordered CSS
file list (base.css design tokens → per-theme tokens.css →
per-control/view sheets → full overrides/*.css). All injected <style>
blocks and inline appearance styles moved out of the JS into these files; the
factories now only assign stable semantic classes and inline computed geometry.
Backend theme selection + runtime switching — Visualizer.theme /
set_theme(id) (plus a loop-safe set_theme_async) validate against the
registry and push a theme_define message so connected viewers swap their
theme live without a page reload. list_themes() / theme_label() /
theme_css_files() are exported from pytanga.viz.
Theme-aware exports — export_snapshot / export_figure (and scene
handles) accept theme= to pack the resolved CSS into the self-contained
HTML, symmetric to how renderer JS is bundled.
Theme-aware viewport background — the 3D viewport background now follows
the active theme's --tanga-bg token (background_color=None means "follow
the theme"); standalone exports pack the same themed background.
User-provided themes — register_theme(name, path) loads a custom theme
from a local folder (tokens.css + optional overrides/*.css), served under
/themes/user/<id>/; copy_theme(id, dest) scaffolds a theme from a built-in
one.
Theme auto-reload — Visualizer.enable_theme_auto_reload() watches the
active theme's files and refreshes the viewer live on edit, backed by
refresh_theme() and a theme_define.version cache-buster.
Custom theme docs — new custom-themes.md page covering the themeable
tokens, the override class contract, and the create/load/auto-reload workflow.
Examples — new control_theming.py (controls styled from the theme CSS),
theme_switching.py (runtime set_theme switching),
custom_theme_override.py (a pastel theme with a pill button and a
switch-style checkbox override), and custom_theme_autoreload.py (a custom
theme with live editing).
Group panel theming — the group panel's appearance moved from hardcoded
inline styles to group-view.css tokens, so light and pastel themes render
the panel and title correctly.