11 KiB
RFC — Motor de profundidad (depth) de Eidos
Hermano de
COLOR_ENGINE_RFC.mdyTYPOGRAPHY_ENGINE_RFC.md. Lleva el canal de profundidad (depth/presencedel libro Diseñando lo que ocurre) a reference-grade rompiendo el modelo de los referentes, no copiándolo — con la jaula abierta.
0. Tesis
La profundidad no es algo que un elemento tiene; es algo que ocurre.
Un overlay no "tiene elevación 4": enuncia una emergencia — asciende a un plano delantero al aparecer, recede al irse — gobernado por el mismo evento sema que ya dirige su motion/sound/haptic. La profundidad pasa a ser un canal de expresión de primera clase (uno de los 8 del libro), unificado (una sola noción cohere superficie + sombra + z + atmósfera), eventful (lo dispara el motor sema) y con jaula abierta (default fuerte, puertas en cada capa).
1. El estudio — cómo lo hacen los referentes y dónde topan
| Framework | Modelo | Límite estructural |
|---|---|---|
| Material 3 | elevación = tinte tonal + sombra, escala dp 0–5 |
dp = altura física con 1 foco de luz; la elevación es propiedad del componente, no expresión de un suceso; escala fija |
| Tailwind | shadow-sm…2xl presets planos |
sin modo (la sombra en dark miente), sin superficie, sin semántica |
| Apple / SwiftUI | materiales (blur/vibrancy) + sombra sutil | atado a plataforma (backdrop), no es sistema de tokens portable |
| Polaris / Carbon / Radix | escala de sombra por rol o numérica | estática; rol fijo, desligada de eventos |
Límite común (incluso M3, el más fino): profundidad = propiedad estática que asignas
- modelo de luz skeuomórfico + desconectada de lo que ocurre y de sus propias señales entre sí. Nadie trata la profundidad como expresión de un suceso. Y todos eligen un bando: Tailwind = flexible sin opinión; Material = opinión fuerte pero jaula cerrada.
2. Dónde está Eidos hoy (ya por encima de la media, pero no novedoso)
- z-index en bandas semánticas:
base · raised · sticky · dropdown · popover · tooltip · modal · toast. ✓ - Escalera de superficie tonal y mode-aware:
surface-default→raised→overlay=neutral-1→2→4(en dark, "más arriba" = más claro — el tonal-overlay de M3, ya presente). ✓ - Sombras nombradas por rol:
shadow-subtle/raised/overlay(→shadow-1/3/5), set propio por tema (THEME_BASE_DARK_SHADOW). ✓ (por encima de Tailwind) - PERO son 3 sistemas separados (eliges sombra + superficie + z a mano), la profundidad es estática (un prop) y el modelo sigue siendo el de sombra-skeuomórfica. Estás ~a la par de M3.
3. El modelo novel — 4 piezas
- Plano semántico unificado —
flush · raised · overlay · modal · recessed. Un nivel cohere superficie + sombra + z + (blur/scrim) de una vez. Nombra por rol en la jerarquía de atención, no por milímetros. - Mezcla multi-señal adaptada al modo, computada — light se apoya en sombra; dark en tinte de superficie + halo (la sombra en dark miente). Sombras derivadas del color de la superficie en OKLCH (no negro-alpha plano), reusando el motor de color. Resuelve el problema sombra-en-dark de raíz.
- Profundidad eventful (lo genuinamente nuevo) — un canal que el motor sema dispara, como sound/haptic:
emerge→sube,contact→hunde,signal/threat→empuja al frente; coordinado con el modelo de dos momentos de motion. - Atmósfera / presencia — backdrop-blur (frost) + scrim: lo que está al frente desenfoca/dimma lo que recede (solapamiento con el canal presence).
3.bis Los dos momentos de la profundidad
La profundidad respeta el modelo de dos momentos del framework (motion F1) — no lo reinventa. Eidos ya lee los dos ejes; depth añade su capa a cada uno:
| Momento | Atributo (eje) | Para depth | Fase |
|---|---|---|---|
| estado | data-state (persistente · soma/morfo) |
el plano en reposo — data-depth='{plane}': dónde está el elemento. Eidos lo aplica como un preset de estado. |
1 ✅ |
| evento | data-event-* (transitorio · sema, durante el hold) |
el ascenso / recesión — una signature de profundidad al emerge/contact: lo que ocurre. Ordenada por sequence, junto a las signatures de motion. |
3 |
Por eso un overlay tiene un plano (estado) y asciende a él (evento) — los dos momentos, nunca colapsados en uno. El canal depth es un canal nuevo expresado por el mismo modelo que ya usa motion: rigor del libro (evento ≠ estado) llevado a la profundidad.
4. Doctrina — default fuerte, jaula abierta
La capa semántica es aditiva sobre primitivos que nunca desaparecen; el set, la mezcla y el canal son extensibles/anulables por config + el registro abierto de sema.
| Pieza | Default fuerte | Puerta abierta |
|---|---|---|
| planos | set canónico (5) | el set es config-driven (EidosConfig.depth.planes); añade sheet/peek, renombra — no un enum cerrado |
| mezcla | mezcla computada por plano | retunear la mezcla por plano en config; override por componente de cualquier señal; los primitivos siguen ahí (--shadow-N, z-index, box-shadow crudo a un paso) |
| canal eventful | emerge↑ / contact↓ |
opt-in/opt-out (como sound+haptic); reglas en el registro abierto de sema (declaration merging + cascada appendable → la app añade/anula el mapa evento→profundidad); degrada con prefers-reduced-motion; la profundidad estática funciona sin el canal (eventful es aditivo, nunca un muro) |
| atmósfera | frost+scrim en overlays | amount/opacidad en config; opt-out por overlay (coste/preferencia) |
| sistema entero | tema canónico | applyDepth(seed) runtime (hermano de applyColorScheme/applyTypeScale) |
Esto no es nuevo en el framework: es exactamente cómo ya operan sema (registro abierto),
eidos (config + setCssVariables + overrides de recipe) y color/tipografía (canon retintable
- builders runtime). Depth hereda el mismo contrato de apertura.
5. Contrato de tokens (añadidos, congelados)
Bare-prefixed por sistema (--depth-…). El plano es un bundle nombrado que compone los
primitivos existentes — no los reemplaza:
--depth-{plane}-surface → var(--color-surface-{…}) (tinte tonal, mode-aware)
--depth-{plane}-shadow → var(--shadow-{…}) (gota, mode-aware vía tema)
--depth-{plane}-halo → oklab rim-light (lift en dark · Fase 2)
--depth-{plane}-z → var(--z-index-{…}) (banda)
--depth-{plane}-blur → frost backdrop-blur (Fase 4 ✅ · opt-in vía data-frost)
--depth-{plane}-scrim → atmósfera (token disponible; sin regla — backdrop por componente)
Consumo: [data-depth='{plane}'] aplica las señales aditivas seguras (sombra + z + blur);
la superficie es un token opt-in (background: var(--depth-{plane}-surface)) para no pisar
fondos de componente. Sin renombrar nada existente → cero rotura de componentes.
6. Fases (la flexibilidad va horneada en cada una)
- ✅ Plano unificado —
EidosConfig.depth+ planos canónicos + emisión--depth-{plane}-*(componen surface/shadow/z) + regla[data-depth](sombra+z) + validación + test + regen. Puertas: set config-driven, mezcla por plano, primitivos intactos, escape a raw. - ✅ Mezcla computada mode-adaptive — la sombra de gota mantiene la escala themed (slate
sutil en light / negro más opaco en dark — ya un tinte, no negro plano); Fase 2 añade el cue
halo: un rim-light de borde superior computado en oklab (color-mix(in oklab, white N%, transparent), escalado por plano: 5/7/8% en raised/overlay/ modal). Es invisible sobre superficies claras (manda la gota) y se vuelve la señal de elevación sobre superficies oscuras (donde la gota apenas se ve) — resuelve "la sombra miente en dark" sin tocar las sombras globales: vive solo en el canal depth, compuesto en elbox-shadowde[data-depth](shadow, halo). El halo derivado de la superficie + el frost atmosférico quedan para Fase 4. - ✅ Canal
deptheventful (momento-evento) — la dimensión de ELEVACIÓN vive en la firma:present-rise(emerge) hace crecer la sombra desde plano → la de reposo del elemento (sube);press-squeeze(contact) la aplana a la superficie (recede). Generic (flush = no-op), coordinado con posición/escala y con sound+haptic desde un solo evento, degradando con reduced-motion (cap global). Anulable: un tema sobreescribe los keyframes/signatures. Monta sobre el sistema designaturesexistente, no un sistema paralelo. - ✅ Atmósfera (frost) — cue
blurpor plano (overlay/modal) + regla opt-in[data-depth='{plane}'][data-frost](superficie translúcidacolor-mix80% +backdrop-filter: blur), gated para no volver translúcido un overlay opaco por defecto. + builder runtimeapplyDepth(planes)/clearDepth()(+buildDepthpuro) que retune cualquier cue de plano en vivo — hermano deapplyColorScheme/applyTypeScale. (El cuescrimqueda disponible como token; el backdrop dim de modales lo siguen gestionando los componentes, así que no se cabló a una regla.) - ✅ Showcase + docs —
/temas/profundidada profundidad de referencia: reacciona · estados (dynamic elevation) · asciende (firma) · escalera de planos · catálogo en reposo · luz vs sombra (el halo) · jaula abierta · a11y. Supera la amplitud de la referencia de elevation de Material añadiendo los dos ejes que le faltan (eventful + jaula abierta). + THEMING §29.
7. Composición con lo existente
- Escalera de superficie (color) → la señal
surfacedel plano (mode-aware gratis). - Motor de color OKLCH → sombras computadas (Fase 2) y halos.
- Dos momentos de motion → la transición de ascenso/recesión (Fase 3) es un movimiento, no un salto.
- Bus de eventos sema → el disparo eventful (Fase 3), como sound/haptic.
- z-index bands → la señal
zdel plano.
No se reinventa nada: se unifica + se hace eventful lo disperso, bajo la doctrina del libro.
8. Doctrina (paralela a color / tipografía)
- Planos + canal = canon del eidos (como roles/variants y estilos nombrados): valores themeables, pero el set es canon.
- Profundidad eventful = capacidad del motor, opt-in con degradación (como sound/haptic).
- Theme = retintar/retunear lo perceptualmente fijo: cambia CUÁNTA sombra es
overlay, no QUÉ significaoverlay. - Jaula abierta: opinión fuerte que nunca atrapa — primitivos siempre accesibles.
9. Fuera de alcance
- 3D real / perspectiva / parallax con giroscopio (la profundidad es perceptual, no un motor 3D).
- Ray-tracing de sombras por geometría (se computa el tinte/halo, no la oclusión física).