--- title: RFC — Eidos depth engine type: rfc audience: human + agent status: implemented — phases 1-5 ✅ source: migrated from src/uix/eidos/DEPTH_ENGINE_RFC.md (2026-07-02, docs-book F7.4) --- # RFC — Eidos depth engine > Sibling of [`rfc-color-engine.md`](./rfc-color-engine.md) and > [`rfc-typography.md`](./rfc-typography.md). Takes the **depth** channel > (`depth/presence` from the book *Diseñando lo que ocurre*) to reference-grade > by **breaking** the references' model, not copying it — with the **open cage**. ## 0. Thesis > **Depth is not something an element _has_; it is something that _happens_.** An overlay does not "have elevation 4": it **states an emergence** — it ascends to a front plane on appearing, recedes on leaving — governed by the **same sema event** that already drives its motion/sound/haptic. Depth becomes a **first-class expression channel** (one of the book's 8), **unified** (a single notion coheres surface + shadow + z + atmosphere), **eventful** (fired by the sema engine) and with an **open cage** (strong default, doors at every layer). ## 1. The survey — how the references do it and where they stop | Framework | Model | Structural limit | |---|---|---| | **Material 3** | elevation = tonal tint + shadow, `dp` scale 0–5 | `dp` = physical height with 1 light source; elevation is a component **property**, not the expression of a happening; fixed scale | | **Tailwind** | flat `shadow-sm…2xl` presets | no mode (the shadow *lies* in dark), no surface, no semantics | | **Apple / SwiftUI** | materials (blur/vibrancy) + subtle shadow | platform-bound (backdrop), not a portable token system | | **Polaris / Carbon / Radix** | shadow scale by role or number | static; fixed role, detached from events | **Common limit** (even M3, the finest): depth = **a static property you assign** + **a skeuomorphic light model** + **disconnected** from what happens and from its own signals. Nobody treats depth as the **expression of a happening**. And everyone picks a side: Tailwind = flexible **without opinion**; Material = **strong opinion but closed cage**. ## 2. Where Eidos stands today (already above average, but not novel) - **z-index** in semantic bands: `base · raised · sticky · dropdown · popover · tooltip · modal · toast`. ✓ - **Tonal, mode-aware surface ladder**: `surface-default→raised→overlay` = `neutral-1→2→4` (in dark, "higher" = lighter — M3's tonal overlay, already present). ✓ - **Role-named shadows**: `shadow-subtle/raised/overlay` (→ `shadow-1/3/5`), per-theme set (`THEME_BASE_DARK_SHADOW`). ✓ (above Tailwind) - **BUT** they are **3 separate systems** (you pick shadow + surface + z by hand), depth is **static** (a prop) and the model is still the skeuomorphic shadow one. You are ~on par with M3. ## 3. The novel model — 4 pieces 1. **Unified semantic plane** — `flush · raised · overlay · modal · recessed`. One level coheres surface + shadow + z + (blur/scrim) at once. Named by **role in the attention hierarchy**, not by millimeters. 2. **Mode-adapted, _computed_ multi-signal mix** — light leans on shadow; dark on surface tint + halo (the shadow lies in dark). Shadows derived from the **surface color in OKLCH** (not flat black-alpha), reusing the color engine. Solves the shadow-in-dark problem at the root. 3. **_Eventful_ depth (the genuinely new part)** — a channel the **sema** engine fires, like sound/haptic: `emerge`→rises, `contact`→sinks, `signal/threat`→ pushes to the front; coordinated with motion's **two-moments** model. 4. **Atmosphere / presence** — backdrop-blur (frost) + scrim: what is in front blurs/dims what recedes (overlap with the *presence* channel). ## 3.bis The two moments of depth Depth respects the framework's **two-moments model** (motion F1) — it does not reinvent it. Eidos already reads both axes; depth adds its layer to each: | Moment | Attribute (axis) | For depth | Phase | |---|---|---|---| | **state** | `data-state` (persistent · soma/morfo) | the **resting plane** — `data-depth='{plane}'`: where the element *is*. Eidos applies it as a state *preset*. | 1 ✅ | | **event** | `data-event-*` (transient · sema, during the `hold`) | the **ascent / recession** — a *depth signature* on `emerge`/`contact`: what *happens*. Ordered by `sequence`, next to the motion signatures. | 3 | That is why an overlay **has** a plane (state) **and ascends** to it (event) — the two moments, never collapsed into one. The depth channel is a new channel **expressed through the same model** motion already uses: the book's rigor (event ≠ state) carried to depth. ## 4. Doctrine — _strong default, open cage_ > The semantic layer is **additive** over primitives that **never disappear**; > the set, the mix and the channel are **extensible/overridable** via config + > sema's open registry. | Piece | Strong default | Open door | |---|---|---| | **planes** | canonical set (5) | the **set is config-driven** (`EidosConfig.depth.planes`); add `sheet`/`peek`, rename — not a closed enum | | **mix** | computed mix per plane | **retune the mix per plane** in config; **per-component override** of any signal; the **primitives stay** (`--shadow-N`, `z-index`, raw `box-shadow` one step away) | | **eventful channel** | `emerge↑ / contact↓` | **opt-in/opt-out** (like sound+haptic); rules in **sema's open registry** (declaration merging + appendable cascade → the app adds/overrides the event→depth map); **degrades with `prefers-reduced-motion`**; static depth **works without the channel** (eventful is additive, never a wall) | | **atmosphere** | frost+scrim on overlays | amount/opacity in config; per-overlay **opt-out** (cost/preference) | | **whole system** | canonical theme | runtime **`applyDepth(seed)`** (sibling of `applyColorScheme`/`applyTypeScale`) | None of this is **new to the framework**: it is exactly how sema (open registry), eidos (config + `setCssVariables` + recipe overrides) and color/typography (retintable canon + runtime builders) already operate. Depth inherits the same openness contract. ## 5. Token contract (additions, frozen) Bare-prefixed by system (`--depth-…`). The plane is a **named bundle** that **composes the existing primitives** — it does not replace them: ``` --depth-{plane}-surface → var(--color-surface-{…}) (tonal tint, mode-aware) --depth-{plane}-shadow → var(--shadow-{…}) (drop, mode-aware via theme) --depth-{plane}-halo → oklab rim-light (dark-mode lift · Phase 2) --depth-{plane}-z → var(--z-index-{…}) (band) --depth-{plane}-blur → frost backdrop-blur (Phase 4 ✅ · opt-in via data-frost) --depth-{plane}-scrim → atmosphere (token available; no rule — backdrop stays per-component) ``` Consumption: `[data-depth='{plane}']` applies the **safe additive** signals (shadow + z + blur); the **surface** is an opt-in token (`background: var(--depth-{plane}-surface)`) so component backgrounds are not stomped. Nothing existing is renamed → **zero component breakage**. ## 6. Phases (the flexibility is baked into each) 1. ✅ **Unified plane** — `EidosConfig.depth` + canonical planes + `--depth-{plane}-*` emission (composing surface/shadow/z) + `[data-depth]` rule (shadow+z) + validation + test + regen. Doors: config-driven set, per-plane mix, primitives intact, escape to raw. 2. ✅ **Computed mode-adaptive mix** — the drop shadow keeps the themed scale (subtle slate in light / more opaque black in dark — already a tint, not flat black); Phase 2 adds the **`halo`** cue: a top-edge rim-light **computed in oklab** (`color-mix(in oklab, white N%, transparent)`, scaled per plane: 5/7/8% on raised/overlay/modal). It is invisible over light surfaces (the drop rules) and becomes the elevation signal over dark surfaces (where the drop barely reads) — solves "the shadow lies in dark" **without touching the global shadows**: it lives only in the depth channel, composed into `[data-depth]`'s `box-shadow` (`shadow, halo`). The surface-derived halo + atmospheric frost stay for Phase 4. 3. ✅ **Eventful `depth` channel (event moment)** — the ELEVATION dimension lives in the *signature*: `present-rise` (emerge) grows the shadow from flat → the element's resting one (rises); `press-squeeze` (contact) flattens it to the surface (recedes). Generic (flush = no-op), coordinated with position/scale and with sound+haptic from **one single event**, degrading with reduced-motion (global cap). Overridable: a theme rewrites the keyframes/signatures. Mounts on the existing `signatures` system, **not** a parallel one. 4. ✅ **Atmosphere (frost)** — per-plane `blur` cue (overlay/modal) + **opt-in** rule `[data-depth='{plane}'][data-frost]` (translucent `color-mix` 80% surface + `backdrop-filter: blur`), gated so an opaque overlay does not turn translucent by default. + runtime builder **`applyDepth(planes)`** / `clearDepth()` (+ pure `buildDepth`) retuning any plane cue live — sibling of `applyColorScheme` / `applyTypeScale`. (The `scrim` cue stays available as a token; modal backdrop dimming remains component-managed, so it was not wired to a rule.) 5. ✅ **Showcase + docs** — `/temas/profundidad` at reference depth: reacts · states (dynamic elevation) · ascends (signature) · plane ladder · resting catalog · light vs shadow (the halo) · open cage · a11y. Exceeds the breadth of Material's *elevation* reference by adding the two axes it lacks (eventful + open cage). + theming reference §29. ## 7. Composition with the existing - **Surface ladder** (color) → the plane's `surface` signal (mode-aware for free). - **OKLCH color engine** → computed shadows (Phase 2) and halos. - **Motion's two moments** → the ascent/recession transition (Phase 3) is a movement, not a jump. - **Sema event bus** → the eventful trigger (Phase 3), like sound/haptic. - **z-index bands** → the plane's `z` signal. Nothing is reinvented: the dispersed pieces are **unified + made eventful**, under the book's doctrine. ## 8. Doctrine (parallel to color / typography) - **Planes + channel = eidos canon** (like roles/variants and named styles): themeable values, but the *set* is canon. - **Eventful depth = an engine capability**, opt-in with degradation (like sound/haptic). - **Theme = retint/retune the perceptually fixed**: change HOW MUCH shadow `overlay` gets, not WHAT `overlay` means. - **Open cage**: a strong opinion that never traps — primitives always reachable. ## 9. Out of scope - Real 3D / perspective / gyroscope parallax (depth is perceptual, not a 3D engine). - Geometry-based shadow ray-tracing (the tint/halo is computed, not physical occlusion).