AtmosphericLayout
- Layer: Layout primitive
- Base: Custom — no Ark UI dependency
Two-plane model
Section titled “Two-plane model”| Plane | Layer | Role |
|---|---|---|
| Plane 2 | z-index: 0, position: absolute | Environment — radial gradient, breathing animation. Never carries information. |
| Plane 1 | z-index: 1, position: relative | All UI — flat, static. Children provide their own layout. |
import { AtmosphericLayout } from "@risingswamp/design-system";
// Typically the outermost wrapper in Layout.tsx<AtmosphericLayout> <Flex flex="1" overflow="hidden"> <AppSidebar /> <Box flex="1">{children}</Box> </Flex></AtmosphericLayout>;| Prop | Type | Default | Description |
|---|---|---|---|
children | JSX.Element | required | Plane 1 content — your entire UI |
How the atmosphere shifts by theme
Section titled “How the atmosphere shifts by theme”The gradient’s position and colors are driven by --atm-* CSS vars scoped to html[data-theme]:
| Theme | --atm-x | --atm-y | Color | Effect |
|---|---|---|---|---|
delight | 50% | 100% | Cyan rgba(0,245,255,…) | Light from below — submarine |
relight | 65% | 0% | Amber rgba(255,200,100,…) | Light from above — dawn |
gilt | 100% | 72% | Gold rgba(232,120,20,…) | Light from the side — golden hour |
Adding a new theme requires only a new html[data-theme="vesper"] { --atm-x: …; --atm-y: …; … } block in global.css — zero component changes.
Animation
Section titled “Animation”Plane 2 uses the breathe keyframe (opacity: 0.65 → 1, 9s, infinite alternate). This is Plane 2-only — no Plane 1 elements animate on idle.
@keyframes breathe { 0% { opacity: 0.65; } 100% { opacity: 1; }}Design notes
Section titled “Design notes”- Plane 2 is
pointer-events: noneandaria-hidden="true"— it is purely decorative and fully inert. - Plane 1
overflow: hiddenprevents children from escaping the container. Children must manage their own scrolling. - Do not place information in Plane 2. Do not animate Plane 1 elements on idle. These are the two invariants of the two-plane model.
- The gradient uses
in oklabcolor interpolation to eliminate banding. Correct syntax:radial-gradient(ellipse at <pos> in oklab, ...)—in oklabgoes after the shape/position, with no comma before it. Puttingin oklabas the first argument (before the shape) causes WebKit/Tauri to strip it entirely, breaking the gradient. - The transparent stop uses
oklab(from var(--atm-2) l a b / 0)— this fades to a zero-opacity version of--atm-2rather than to black, eliminating the dark fringe at the gradient edge in oklab space. - Noise texture is generated once at mount via canvas (200×200, uniform grey, full alpha) and applied as a repeating
soft-lightoverlay at0.09opacity. This must be an inline style — Panda CSS does not generatemix-blend-modefrom themixBlendModetoken in this context.
Plane 2 Constraints (inverse of Plane 1)
Section titled “Plane 2 Constraints (inverse of Plane 1)”- Gradient only — no text, no borders, no interactive elements
pointer-events: nonealwaysaria-hidden="true"always- Animation is
breatheonly — no other motion on Plane 2