Theme reveal
The header mode toggle (src/components/mode-toggle.tsx) applies light/dark theme changes with an elliptical reveal anchored to the toggle button center.
Implementation lives in src/lib/theme-reveal.ts with styles in src/app.css.
Behavior
-
Expand — when the user picks a theme different from the load/OS baseline (State A), an ellipse grows from the toggle to cover the viewport.
-
Contract — when returning to the load/OS baseline, the ellipse shrinks back into the toggle.
-
Reduced motion — if
prefers-reduced-motion: reduce, the theme applies instantly with no animation. -
No View Transitions — browsers without
document.startViewTransitionalso apply instantly.
Mechanics
-
On click,
mode-toggle.tsxcaptures the toggle center synchronously viaelementCenter()(neverclientX/clientY— zero is a valid coordinate on mobile edges). -
applyThemeWithCircleReveal()sets CSS custom properties on<html>:-
--theme-reveal-x,--theme-reveal-y— origin in layout-viewport pixels -
--theme-reveal-rx,--theme-reveal-ry— elliptical radii (wider than tall to cover corners)
-
-
document.startViewTransition()runs the KobaltesetColorModecallback. -
After
transition.ready, the Web Animations API animates only the radii (easeOutSine, 450ms). -
transition.finishedclears the reveal dataset and CSS variables.
src/components/theme-system-sync.tsx calls syncThemeRevealBaseline() on load and when the OS color scheme changes so expand/contract direction stays correct.