11 KiB
| title | type | audience | status | source |
|---|---|---|---|---|
| RFC — Eidos depth engine | rfc | human + agent | implemented — phases 1-5 ✅ | 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.mdandrfc-typography.md. Takes the depth channel (depth/presencefrom 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
- 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. - 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.
- 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. - 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)
- ✅ 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. - ✅ 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
halocue: 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]'sbox-shadow(shadow, halo). The surface-derived halo + atmospheric frost stay for Phase 4. - ✅ Eventful
depthchannel (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 existingsignaturessystem, not a parallel one. - ✅ Atmosphere (frost) — per-plane
blurcue (overlay/modal) + opt-in rule[data-depth='{plane}'][data-frost](translucentcolor-mix80% surface +backdrop-filter: blur), gated so an opaque overlay does not turn translucent by default. + runtime builderapplyDepth(planes)/clearDepth()(+ purebuildDepth) retuning any plane cue live — sibling ofapplyColorScheme/applyTypeScale. (Thescrimcue stays available as a token; modal backdrop dimming remains component-managed, so it was not wired to a rule.) - ✅ Showcase + docs —
/temas/profundidadat 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
surfacesignal (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
zsignal.
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
overlaygets, not WHAToverlaymeans. - 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).