You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/eidos/SHAPE_ENGINE_RFC.md

11 KiB

RFC — Motor de forma (shape) de Eidos

Hermano de COLOR_ENGINE_RFC.md, TYPOGRAPHY_ENGINE_RFC.md y DEPTH_ENGINE_RFC.md. Lleva el canal de forma (shape del libro Diseñando lo que ocurre) a reference-grade rompiendo el modelo de los referentes — con la jaula abierta. Es el 8º y último canal de expresión del libro sin elevar (tiempo · movimiento · presencia · profundidad · forma · color · sonido · háptica).

0. Tesis

La forma no es un número de redondeo que un elemento tiene; es una cualidad perceptual — continuidad, familia, tensión — que el sistema compone y que, en su momento, ocurre.

Todos reducen la forma a UN número: border-radius. Pero la esquina tiene más ejes que su magnitud: cuán continua es (arco circular vs superelipse), a qué familia pertenece (redondeada / continua / cortada / píldora), cómo se relaciona con las formas anidadas, y qué le ocurre cuando el elemento es presionado o confirma. Eidos trata la forma como un canal de primera clase: unificado (magnitud + continuidad + familia + armonía), y eventful (la forma puede tensarse/relajarse), bajo la jaula abierta.

1. El estudio — cómo lo hacen los referentes y dónde topan

Framework Modelo Límite estructural
Tailwind / Bootstrap escala rounded-sm…full, arco circular sin continuidad, sin armonía anidada, sin familia, estática; la esquina es un arco y punto
Material 3 shape scale + mapping por componente + (M3 Expressive) morph + familia cut arco/cut; el morph es reciente y acotado; sistema cerrado (eliges de la escala)
Apple / SwiftUI esquinas continuas (superelipse) .continuous atado a plataforma, no es token portable; no eventful; anidado manual
CSS hoy border-radius = arcos elípticos sin superelipse nativa universal (corner-shape emergente); squircles vía SVG/clip-path hacks

Límite común: forma = un número de radio de arco, propiedad estática que asignas, desligada de los elementos vecinos/anidados, sin continuidad real, y desconectada de lo que ocurre. SwiftUI es el único con continuidad — pero cerrada y por plataforma. Material es el único con familia + morph — pero arco y cerrado. Nadie los unifica ni los hace abiertos.

2. Dónde está Eidos hoy (coherente, pero no novedoso)

  • Escala de radius en --radius-{none·sm·md·lg·xl·xxl·full} (4/6/10/16/20px + pill). ✓
  • Asignada por componente vía el size primitive (radius: 'md'). ✓
  • PERO el modelo es exactamente "un número de arco circular": sin continuidad (squircle), sin armonía entre radios anidados, sin familia perceptual, y estática (nunca ocurre). Estás ~a la par de Tailwind; por debajo de SwiftUI (continuidad) y de M3 (familia + morph).

3. El modelo novel — 4 piezas

  1. Continuidad (superelipse) — un eje nuevo --shape-smoothing (0 = arco circular … 1 = superelipse tipo iOS). Output progresivo (estrategia idéntica al oklch del color): se emite border-radius (universal, el fallback) y corner-shape: superellipse(…) donde se soporta. Resuelve de raíz la esquina-de-arco que todos arrastran, sin romper a nadie.
  2. Armonía de radios anidados — radio interior derivado del exterior: interior = max(0, exterior − gap) (concéntrico), computado en calc(). Una convención --shape-nest para que tarjeta-dentro-de-tarjeta (o input-dentro-de-panel) nunca desencaje.
  3. Familia de forma — rounded · continuous · cut · pill (+ sharp). Eje perceptual, no de magnitud. Canon del eidos (como roles/variants): valores themeables, set canon.
  4. Forma eventful (lo genuinamente nuevo) — la forma se tensa/relaja al ocurrir algo: contact→aprieta esquinas (squeeze), commit→las redondea, vía la misma firma que ya dirige motion/depth. Forma-como-suceso, coordinada desde un solo evento sema.

3.bis Los dos momentos de la forma

La forma respeta el modelo de dos momentos del framework (motion F1) — no lo reinventa:

Momento Atributo (eje) Para shape Fase
estado data-state (persistente) la forma en reposo — magnitud (--radius-*) + familia + continuidad: cómo es el elemento 1
evento data-event-* (transitorio, durante el hold) el morph — apretar/redondear al contact/commit: lo que ocurre. Ordenado por sequence, junto a las firmas de motion/depth 3

Un control tiene una forma (estado) y la tensa al pulsarse (evento) — los dos momentos, nunca colapsados. Mismo rigor del libro (evento ≠ estado) llevado a la forma.

4. Doctrina — default fuerte, jaula abierta

Pieza Default fuerte Puerta abierta
escala --radius-* canónica config-driven (EidosConfig size/radius); el border-radius crudo siempre a un paso
continuidad --shape-smoothing por defecto (sutil) override global/por-componente/por-elemento; 0 vuelve al arco puro
familia set canónico (rounded/continuous/cut/pill/sharp) el set es canon pero themeable; un wrapper compone una propia sin inventar familia
anidado convención --shape-nest (concéntrico) opt-in; el cálculo es transparente (calc()), anulable
eventful contact↓apretar / commit↑redondear opt-in/opt-out (como sound/haptic/depth); registro abierto de sema; degrada con prefers-reduced-motion; la forma estática funciona sin el canal
sistema entero tema canónico applyShape(seed) runtime (hermano de applyColorScheme/applyTypeScale/applyDepth)

Es exactamente cómo ya operan color/tipografía/profundidad: canon retintable + builders runtime + primitivos siempre accesibles. Forma hereda el mismo contrato de apertura.

5. Contrato de tokens (añadidos, congelados)

Bare-prefixed por sistema (--shape-…). La magnitud sigue en --radius-* (no se renombra nada → cero rotura):

--radius-{key}        magnitud (escala existente — se mantiene)
--shape-smoothing     factor de superelipse 0..1 (Fase 1) → corner-shape: superellipse(k)
--shape-nest-gap      gap por defecto del radio anidado (Fase 2)
  • Continuidad: [style] { border-radius: var(--radius-md) } (universal) + donde se soporte corner-shape: superellipse(var(--shape-smoothing-k)) (progresivo, degrada al arco).
  • Familia: atributo data-shape='cut'|'continuous'|… o recipe del componente (no un token global) — selecciona el corner-shape / clip apropiado.
  • Anidado: border-radius: max(0px, calc(var(--_outer-radius) - var(--shape-nest-gap))) — convención en calc(), sin token de salida nuevo.

El anidado de 4 esquinas requiere radios FINITOS — a full es solo el top. A full (--radius-full = 9999px) el radio se recorta a la mitad de la dimensión menor de cada elemento. Un hijo ancho (p. ej. 16:10) no puede ser concéntrico en sus 4 esquinas: su altura cap­ea las cuatro a ~½-altura, distinto del padre. Pero sus esquinas superiores SÍ pueden valer radio_card − gap si las inferiores se quedan rectas (la restricción de altura deja de morder). Esa es la geometría del reproductor iOS: carátula con top redondeado concéntrico + base recta que encuentra los metadatos.

La regla CSS [data-shape-nest] no sirve aquí porque el valor computado del radio del padre sigue siendo 9999px (el cap es un valor usado, no legible en CSS). El demo /temas/forma lo mide (min(w,h)/2 − gap vía ResizeObserver) y lo aplica a las esquinas superiores de la carátula; las inferiores quedan a 0. El toggle "radios concéntricos" se inhabilita a full («auto: solo top») porque ahí el anidado es automático y parcial por geometría, no opcional.

6. Fases (la flexibilidad va horneada en cada una)

  1. ✅ Continuidad + escala + familias — --shape-smoothing + data-shape → corner-shape con las 4 familias (rounded/continuous/cut/scoop). Emisión progresiva: border-radius universal (la magnitud, --radius-* intactos) + corner-shape donde se soporte (degrada al arco). Config-driven + validación + test + regen. (Las familias se adelantaron aquí — son la misma mecánica corner-shape.)
  2. ✅ Armonía anidada — --shape-nest-gap + regla [data-shape-nest]: border-radius: max(0, var(--shape-outer-radius) − gap) (concéntrico).
  3. ✅ Forma eventful (momento-evento) — el morph de esquina plegado en la firma press-squeeze (cross-modal: un press = escala + sombra + esquina) + @property --shape-smoothing para que interpole. Sobre el sistema de signatures existente; degrada con reduced-motion. No un sistema paralelo.
  4. ✅ Builder runtime applyShape(seed) — dial de smoothing/nestGap + override de familias, bloque gestionado (hermano de applyColorScheme/applyTypeScale/applyDepth).
  5. ✅ Showcase + docs — /temas/forma (continuidad con dial + familias + anidado + eventful en vivo) + THEMING §30.

7. Composición con lo existente

  • Escala --radius-* → la magnitud de cada forma (se reusa, no se duplica).
  • Sistema de signatures (motion/depth) → el morph eventful (Fase 3), no un motor nuevo.
  • Dos momentos de motion → el morph es un movimiento de la forma, no un salto.
  • Bus de eventos sema → el disparo eventful (Fase 3), como sound/haptic/depth.
  • Espaciado → el gap del radio anidado (Fase 2).

No se reinventa nada: se unifica + se hace continuo, armónico y eventful lo que hoy es un número suelto, bajo la doctrina del libro.

8. Doctrina (paralela a color / tipografía / profundidad)

  • Escala + familias = canon del eidos (como roles/variants y planos): valores themeables, pero el set es canon.
  • Continuidad = cualidad por defecto, retuneable; 0 = arco puro (jaula abierta).
  • Forma eventful = capacidad del motor, opt-in con degradación (como sound/haptic/depth).
  • Theme = retintar/retunear lo perceptualmente fijo: cambia CUÁNTO redondea md o cuánta continuidad lleva, no QUÉ significa cut.
  • Jaula abierta: opinión fuerte que nunca atrapa — border-radius crudo siempre accesible.

9. Fuera de alcance

  • Blobs / formas orgánicas aleatorias y morphing de path arbitrario (la forma es perceptual, no un motor de geometría libre).
  • Recortes complejos por geometría (clip-path a medida por componente queda en cada recipe).
  • Esquinas por-lado asimétricas como sistema (el border-radius por-esquina crudo ya las cubre).

Powered by TurnKey Linux.