diff --git a/src/arts/motion/index.ts b/src/arts/motion/index.ts index df78bcc76..cb526c3bf 100644 --- a/src/arts/motion/index.ts +++ b/src/arts/motion/index.ts @@ -9,8 +9,6 @@ export type { SpringConfig, SpringPhysics } from './drivers' export { isCssStatePreset } from './types' export type { - CoordinatedPreset, - CoordinatedPresetName, CssPhase, CssStatePreset, EventSignature, @@ -19,7 +17,6 @@ export type { KeyframeName, KeyframeStops, MotionConfig, - MotionCoordinatedPresets, MotionContext, MotionDom, MotionHandle, diff --git a/src/arts/motion/types.ts b/src/arts/motion/types.ts index a459bc3f9..6448594a3 100644 --- a/src/arts/motion/types.ts +++ b/src/arts/motion/types.ts @@ -154,66 +154,14 @@ export interface JsStatePreset { export type StatePreset = CssStatePreset | JsStatePreset /** - * A COORDINATED preset (RFC: eidos/MOTION_SERVICE_RFC.md §M6) — for animable - * surfaces driven by a `PresenceGroup`, where the WHEN is governed by soma's - * `data-starting-style` / `data-ending-style` (the group's release), NOT `data-state`. - * - * Unlike `CssStatePreset` (keyframes on `data-state`, which fire on MOUNT and would - * fight the coordinated cascade — the §5 finding), this declares the "outside" state - * as a TRANSITION: eidos generates `[data-animation-style='X'][data-starting-style], - * [...][data-ending-style] { …off… }` + the transition + the canonical reversible - * stagger. The motion engine never runs these (pure CSS) — they live in - * `MotionConfig.coordinated`, NOT `presets`, so the engine returns a settled handle. - */ -export interface CoordinatedPreset { - /** The "outside" state — CSS prop → value, e.g. `{ opacity: '0', transform: 'translateX(-16px)' }`. */ - readonly off: Readonly> - /** Duration token key (`'moderate'`) or raw. Overridable per-container via `--motion-cascade-duration`. */ - readonly duration?: string - /** Ease token key (`'out'`) or raw. Overridable via `--motion-cascade-ease`. */ - readonly ease?: string -} - -/** - * Type-safe, eidos/app-extensible registry of COORDINATED preset names — the value - * of a component's `animation` prop (RFC: eidos/MOTION_SERVICE_RFC.md §5, "separadas - * por rol"). It is the counterpart of eidos's `EidosMotionPresets` (which types the - * `motion` prop), but it lives HERE in `$motion` — the shared layer — so that SOMA - * components (Rail / Reveal) can type their `animation` prop WITHOUT importing eidos - * (a lower layer cannot depend on a higher one). Eidos POPULATES it with its - * built-ins (`cascade-*`) via declaration merging: - * - * declare module '$motion' { - * interface MotionCoordinatedPresets { - * 'cascade-slide': true - * } - * } - * - * The interface starts EMPTY: the names are eidos's data, not the engine's. Same - * boundary as `EidosMotionPresets` — the engine stays open at runtime; this is a - * COMPILE-TIME ergonomic for the `animation` prop only. - */ -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface MotionCoordinatedPresets {} - -/** - * The `animation` prop type — the COORDINATED counterpart of `MotionPresetName`. - * Known coordinated presets (eidos/app-merged) autocomplete; an arbitrary string is - * still accepted. Omit the prop (`undefined`) for no preset. - */ -export type CoordinatedPresetName = keyof MotionCoordinatedPresets | (string & {}) - -/** - * The motion config: keyframes + the two animation surfaces. Eidos generates CSS - * from `keyframes` + `signatures` + the css `presets`; the engine resolves + - * runs the `presets` (settled for css, driver for js). `coordinated` is M6 — - * CSS-only presets for `PresenceGroup`-driven surfaces (the engine never sees them). + * The motion config: keyframes + animation surfaces. Eidos generates CSS from + * `keyframes` + `signatures` + the css `presets`; the engine resolves + runs the + * `presets` (settled for css, driver for js). */ export interface MotionConfig { readonly keyframes?: Readonly> readonly signatures?: Readonly> readonly presets?: Readonly> - readonly coordinated?: Readonly> } export function isCssStatePreset(preset: StatePreset): preset is CssStatePreset { diff --git a/src/docs/GUIA_IMPLEMENTACION_SEMAUIX.md b/src/docs/GUIA_IMPLEMENTACION_SEMAUIX.md index e3011b810..da065b188 100644 --- a/src/docs/GUIA_IMPLEMENTACION_SEMAUIX.md +++ b/src/docs/GUIA_IMPLEMENTACION_SEMAUIX.md @@ -518,14 +518,25 @@ AudioContext se crea/resume en el primer user gesture (click/touch/keydown en do Una firma perceptiva es el conjunto de decisiones de canal coordinadas alrededor de un evento. -**Las dimensiones no son un conjunto cerrado.** El framework ships con 5 -canales canónicos (`motion`, `sound`, `color`, `presence`, `haptic`) y el -registry `SemaChannelSignatures` se extiende vía TypeScript declaration -merging cuando una app necesita `a11y`, `voice`, etc. Una family puede -no rellenar `presence`; otra puede aportar `haptic`. Una rule de -cascade puede silenciar `motion` para reducir estimulación. Los ejemplos -abajo enumeran las dimensiones relevantes para CADA evento — no una -lista canónica fija. +**Las dimensiones perceptivas no son un conjunto cerrado — pero ojo a quién +las ejecuta.** A nivel del libro, una firma compone los canales de expresión +(tiempo · motion · presencia · profundidad · forma · color · sonido · háptica). +El framework los **REPARTE por dueño** y NO los ejecuta todos en sema: + +- **sema ejecuta 2 canales runtime** — `sound` + `haptic` (los únicos + declarados en `SemaChannelSignatures`) — más el **meta-canal `visual`**, que + no realiza ninguna modalidad: solo **estampa los `data-event-*` y temporiza + el hold**. +- **eidos materializa los canales visuales** (motion · presencia · profundidad · + forma · color) reaccionando en CSS a esos `data-event-*` + `data-state` / + `data-intent`. Eidos es el **único dueño de lo visual**. + +`SemaChannelSignatures` se extiende vía TypeScript declaration merging para +añadir canales **de sema** con firma (`a11y`, `voice`, …) — NO para los +visuales, que viven en eidos. Una rule de cascade afina `sound`/`haptic`; +`motion`/`color` se ajustan en los recipes de eidos, no en la cascade. Los +ejemplos de abajo enumeran las dimensiones **perceptivas** de cada evento — +recuerda que motion/forma/color las realiza **eidos**, no sema. ### 11.1. Ejemplo: commit.save + affirm diff --git a/src/uix/eidos/MOTION_SERVICE_RFC.md b/src/uix/eidos/MOTION_SERVICE_RFC.md index b1189a60d..751d647a5 100644 --- a/src/uix/eidos/MOTION_SERVICE_RFC.md +++ b/src/uix/eidos/MOTION_SERVICE_RFC.md @@ -1,5 +1,45 @@ # RFC — Servicio de motion de UIX (coordinación de presencia cross-layer) +> ## ⚠️ RETIRADA — diseño implementado y luego ELIMINADO (2026-06-19, «Plan A») +> +> **El servicio de orquestación paralelo que diseña el cuerpo de este RFC (§4–§9 + +> Apéndices B/C: `MorfoPart.animation`, la prop `animation` ruteada, `PresenceGroup`, +> `DomCascade`, los presets coordinados `cascade-*` / `MotionConfig.coordinated`, la +> neutralización `animation: none !important`, y sus consumidores `Reveal` / `Rail`) +> se implementó, se validó… y se ELIMINÓ por completo.** El código ya no existe; este +> documento queda como **registro histórico** del diseño y su razonamiento. +> +> **Por qué (corrección del usuario — Apéndice D.2).** La animación NO es un eje +> paralelo: es **un canal de la firma del EVENTO**, y la firma la posee **sema en +> TODOS sus canales** (motion incluido). Modelar el motion coordinado como un motor +> propio —fuera del evento— producía DOS firmas para el mismo canal que convivían +> neutralizándose (Grieta 1, D.1). El libro pide UNA firma por evento, coordinada +> alrededor del evento. +> +> **El reparto correcto (hacia donde se reconstruye):** +> - **sema** lanza el evento: proyecta `data-event-*` + sonido/haptic + el hold. +> - **eidos** materializa el canal motion + la coordinación visual **reaccionando a +> `data-event-*`** (único dueño de lo visual; `arts/motion` sobrevive como _island_ +> de progressive-enhancement para lo que CSS no puede — spring / FLIP). +> - **soma** posee el lifecycle (retener / esperar / desmontar): el `Presence` island, +> que se conserva. +> - La coordinación padre↔hijo **sigue siendo necesaria**, pero **cuelga del evento de +> sema**, no de un motor paralelo. +> +> **Qué se conservó:** `arts/motion` (engine spring/waapi/rect), el `Presence` island +> (`soma/layers/presence.svelte.ts`, reducido a una sola superficie), los **state-presets** +> (`motion` prop → `data-animation-style` sobre `data-state`: `scale-fade`, `slide-fade`, +> Material shared-axis/fade-through), las **firmas sema** visuales (`present-rise` / +> `dismiss-fade`) y el **stagger Material** (`--motion-stagger-{index,each}`). Modelo +> vigente: [`eidos-motion.md`](./eidos-motion.md) (dos momentos `--event` / `--state`). +> +> **El modelo hacia adelante** está en el **[Apéndice D](#apéndice-d--re-análisis-2026-06-16-grietas-y-principios-del-re-diseño)** +> (re-análisis 2026-06-16): principio rector, discriminante de los tres dominios, plan. +> La retirada de 2026-06-19 ejecutó de golpe la limpieza que D.6 preveía incremental +> (pasos 3 + 5): dejar el terreno limpio antes de reconstruir sobre el evento. +> +> --- +> > Hermano de `eidos-motion.md` (que **extiende**, no contradice) y de los RFC de engine > (`COLOR_ENGINE_RFC.md`, `DEPTH_ENGINE_RFC.md`, …). A diferencia de aquéllos —engines > **visuales** de eidos— éste es un **servicio cross-layer** (morfo + soma + eidos + arts): @@ -21,13 +61,12 @@ > - **eidos** posee el _QUÉ visual_ y los _valores expresivos_ (keyframes, easing, stagger-ms); > - **arts/motion** ejecuta primitivas **por-nodo** (no orquesta, no gana jerarquía). > -> **Estado: M1–M4 + M5/M6 + M9 implementados** (contrato morfo · `PresenceGroup` · exit con -> retención de DOM · interrupción/reversa §8.3 · enrutado de la prop `animation` · stagger -> auto-derivado · **segunda coordinación: el modo children-DOM, `DomCascade`, cableado en el -> `dropdown-menu` real — Apéndice C**). Consumidores reales: `Reveal`/`Rail` (modo registered- -> `Presence`, §15) y `dropdown-menu` (modo children-DOM, Apéndice C). Pendiente: M7 (reduced-motion -> + SSR hardening) · M8 (text-effects) · F3 (submenús). Todo es **aditivo y opt-in**: un componente -> sin la nueva declaración funciona exactamente como hoy. +> **Estado: RETIRADO (2026-06-19).** El texto a continuación (§0–§15, Apéndices A–C) +> documenta el diseño **tal como llegó a implementarse** —M1–M4 + M5/M6 + M9, con +> `PresenceGroup` / `DomCascade` / presets coordinados y los consumidores `Reveal` / +> `Rail` / `dropdown-menu`— y que se **eliminó por completo**. Ver la nota de retirada +> al inicio y el [Apéndice D](#apéndice-d--re-análisis-2026-06-16-grietas-y-principios-del-re-diseño) +> para el modelo hacia adelante. Se conserva como registro histórico. ## Tabla de contenidos @@ -1117,6 +1156,129 @@ real computa layout aunque la pestaña esté oculta; el preview headless no (`ge (visual 100 % en eidos reutilizando el preset coordinado), el sonido sin neutralización (prueba de la Grieta 1), y el registro-por-contexto real (ítems como componentes, no `{#each}`). +> El prototipo de la Fase 0 (`/temas/animations/menu-native`) se **eliminó** en la retirada D.8 — había +> cumplido su función de validar las Decisiones A y B. Su demo hermana de dos momentos +> (`/temas/animations`) se conserva (state-presets + firma sema, no coordinación). + +### D.8 — La retirada ejecutada (2026-06-19, «Plan A») + +En lugar de la limpieza incremental de D.6 (pasos 3 + 5), el usuario optó por **retirar de golpe todo el +motor de orquestación paralelo** y dejar el terreno limpio antes de reconstruir la coordinación como canal +de la firma del evento (D.2). La retirada es **funcional y verificada** — `npm run check` no añade ningún +error (los pre-existentes son de otros tracks: icon-button, spin-field, scroll-area, palabras); las suites +de morfo / motion / soma-layers quedan verdes. + +**Eliminado (archivos borrados):** +- `soma/layers/presence-group.ts` (+ test) · `soma/layers/dom-cascade.svelte.ts` (+ test) · + `soma/layers/coordination.ts`. +- `soma/components/reveal/` · `soma/components/rail/` · `morfo/components/reveal.ts` · + `morfo/components/rail.ts`. +- Demos `web/routes/temas/animations/{presence-group,rail,compuesto,reveal,dom-cascade,dropdown-menu,menu-native}/`. + +**Eliminado (código recortado):** +- **morfo**: `MorfoPart.animation` + `MorfoAnimation` / `MorfoAnimationChildren` (types) · su schema + + invariante · `compilePartAnimation` / `CompiledPartAnimation` (compile) · re-exports. +- **arts/motion**: `CoordinatedPreset` / `CoordinatedPresetName` / `MotionCoordinatedPresets` · + `MotionConfig.coordinated`. +- **eidos**: `BUILTIN_COORDINATED_PRESETS` (`cascade-*`) · `renderCoordinatedPresetRules` + su llamada · + la neutralización `animation: none !important` · el bloque `declare module '$motion'` del registry · + `coordinated: …` en `themes/base` · las reglas `[data-cascade]` + `[data-animation-style]` del cascade en + `dropdown-menu.css`. `generated/base.css` regenerado. +- **soma**: el camino agrupado de `Presence` (`group`/`groupRole`/`pending`/`PresenceMember`/`release`/ + `unmount`/`cancel`/registro) → `presence.svelte.ts` reducido a **island de una superficie**; `FloatingShell` + pierde `pending`; el `dropdown-menu` provider pierde la prop `animation` / `data-cascade` / `getCascadeRows`. + +**Conservado:** `arts/motion` (engine spring/waapi/rect) · el `Presence` island · los state-presets +(`scale-fade`/`slide-fade`/Material) · las firmas sema visuales (`present-rise`/`dismiss-fade`) · el stagger +Material (`--motion-stagger-{index,each}`) · la doctrina state/visual · el contrato morfo (menos `animation`). + +**Próximo (sin implementar):** reconstruir la coordinación padre↔hijo como **canal de la firma del evento** +(D.2) — sema lanza el evento, eidos materializa motion + coordinación reaccionando a `data-event-*`, soma +posee el lifecycle (island). El prototipo Svelte-nativo (D.7) validó el _cómo_ visual; falta cablearlo al +evento de sema. + +### D.9 — Modelo verificado (auditoría 2026-06-19): pipeline + las dos reglas duras + +Tras la retirada, una auditoría de 8 agentes (5 lectores de ground-truth + 3 críticos adversariales) sobre +`src/uix/sema/*` + el libro fijó el modelo y cazó varios errores de framing. **El pipeline correcto, verbo +por dueño:** + +``` +morfo DEFINE el contrato semántico del evento (family/intent/verb/target/sequence/hold/a11y) + estructura (parts) + ↓ +soma DISPARA origina el evento (runtime.trigger) y envía a sema la carga semántica (engine.emit{target,name,family,intent…}) + │ — el evento es de SOMA; sema es ORNAMENTAL: sin engine, trigger corre igual (prewrite+handler+effects) + ↓ +sema RESUELVE+PUBLICA resuelve la firma (cascada de 5 capas → SOLO sound/haptic) y, por el META-canal visual, + │ estampa data-event-* en UN target vía adom (dom.apply) + abre/cierra el HOLD + │ — en paralelo, la misma emisión realiza sound/haptic (canales reales, NO por adom) + ↓ +eidos REACCIONA CSS reaccionando a data-event-* (durante el hold) + data-state/data-intent + ↓ +MOTION (y presence/depth/shape/color) — el stagger/índice lo calcula EIDOS en CSS (sibling-index/nth-child) +``` + +**Las dos reglas duras (violarlas resucita bugs ya muertos):** + +1. **Soma NUNCA escribe una `--var` visual.** El índice/ritmo del stagger es animación → es de eidos, que lo + computa en CSS desde la estructura (`sibling-index()` / `:nth-child`, como ya hacen `spinner.css` / + `avatar.css`). El `DomCascade` borrado escribía `--motion-stagger-index` desde soma — **esa** era la + violación de raíz, no solo el "motor paralelo". Soma aporta estructura (hijos en el DOM) + `data-state`; + nada visual. +2. **`data-event-*` es un sello de UN `signal.target`, NO un bus de difusión.** El projector estampa un solo + elemento; el resolver resuelve solo sound/haptic/hold. **No hay fan-out por hijo dirigido por el evento.** + La cascada de los hijos NO sale de `data-event-*` — sale de eidos leyendo estructura + `data-state`. + +**Errores de framing que la auditoría corrigió (a no repetir):** +- "sema emite el evento" → soma lo ORIGINA; sema lo procesa (`runtime.svelte.ts:696`; sin engine soma sigue). +- "el engine no ejecuta nada" → no realiza modalidad, pero RESUELVE la firma + posee el await del hold + la + persistencia (`engine.ts:198-271`). +- "eidos es un canal par del de sonido" → error de categoría: eidos NO está en `SemaChannelSignatures` (solo + sound+haptic) ni recibe dispatch; es una **capa/realm** que reacciona a los tokens. Nunca registrar un + `EidosChannel` ni meter motion/color en `SemaChannelSignatures`. +- "`data-event-*` son tokens visuales" → son tokens **semánticos compartidos**: los lee la cascada de sema + (sound/haptic) Y el CSS de eidos (`stamp.ts:5-11`). +- el canal `visual` es **META**: no realiza modalidad — solo estampa `data-event-*` + temporiza el hold + (`engine.ts:243-248`, `sema/README.md:43`). + +**Doc corregida:** `GUIA_IMPLEMENTACION_SEMAUIX.md` §11 decía "5 canales canónicos (motion, sound, color, +presence, haptic)" — stale; reescrita al split real (sema: sound+haptic+meta-visual · eidos: los visuales). + +**Consecuencia para la Fase 1 (panel + N cards):** la cascada NO se conduce estampando un `data-event-*` rico +en el contenedor. El `emerge.open` del panel cae en UN target (su flourish + sonido). La entrada escalonada +de las cards es el momento `--state` + stagger, que **eidos** calcula en CSS desde la estructura; soma solo +aporta los hijos + `data-state`. El caso dinámico (ráfaga de apertura vs alta suelta) se distingue por +`data-state` (dominio de soma), no por una `--var` que soma escriba. + +### D.10 — Prototipo de Fase 1 validado (2026-06-19) + +Prototipo descartable en `web/routes/temas/animations/panel-cascade/` (`+page.svelte` + `panel-cascade.css`): +un contenedor coordinador + N `` reales. **Valida el modelo en los tres casos difíciles**, con el +reparto verificado y **cero `--var` visual escrita por JS** (confirmado por valores computados frame-a-frame): + +- **Cascada externa** — entrada (`:nth-child` → `--row`, delay = row × ritmo) + salida en cierre de panel + (`:nth-last-child` → `--row-rev`, reverse). El índice lo computa eidos desde la estructura. +- **Borrado dinámico con retención** — al quitar cards, **soma retiene** el nodo (Svelte `out:`, leyendo la + duración de la regla de eidos) y marca `data-leaving` (flag de **estado**); **eidos pinta** la salida + (`[data-leaving]` → card-fall). Suelto → `--row-rev 0` → inmediato; en bloque → cascada inversa. Sin + `data-phase`: el `:nth-last-child` da los dos casos. +- **Anidamiento** — contenido interno de cada card cascadea componiendo el **`--row` heredado** (índice + externo de su card) + su **`--inner-row` propio** (`:nth-child` scopeado a su lista), secuenciado tras + asentar la card. Compone por **herencia de custom properties** → escala a profundidad arbitraria sin + maquinaria. + +**Hallazgos para la implementación de producción:** +- **El CSS de eidos DEBE vivir en `.css` plano**, no en ` diff --git a/web/routes/temas/animations/compuesto/+page.svelte b/web/routes/temas/animations/compuesto/+page.svelte deleted file mode 100644 index b3da58249..000000000 --- a/web/routes/temas/animations/compuesto/+page.svelte +++ /dev/null @@ -1,296 +0,0 @@ - - - - Compuesto · presets de la librería de eidos - - -
-
- ← Motion -

Compuesto presets predefinidos de eidos

-

- A diferencia de rail y - reveal —que escriben el CSS de - cascade-* a mano en la página— este compuesto usa los - presets coordinados de la LIBRERÍA de eidos - (BUILTIN_COORDINATED_PRESETS → generated/base.css). Esta página no - tiene ni una línea de CSS de animación: el componente solo nombra - animation="cascade-slide" y la librería aporta el off-state, la transición y el - stagger reversible (sobre data-starting/ending-style, M6). El selector cambia la - prop en vivo — cambia el look sin tocar la página. -

-

- Y compone los dos ejes: las superficies Rail.Item entran en - cascada (motion coordinado, data-animation-style) mientras cada - <Button> dispara su propia firma de press - (sema, contact-activate → press-squeeze). Dos nodos, dos - sistemas, sin conflicto: al pulsar un botón se comprime él, la fila no se mueve. -

-
- -
- {#each STYLES as s (s.value)} - - {/each} -
-
-
- - -
- - Para la cascada fluida, abre esta página enfocada en el browser (en preview de fondo el rAF se - throttlea). La animación NO está aquí — sale de la foundation generada. - -
- - -
- - {#each ITEMS as item (item.label)} - - - - {/each} - -
- -
{`   
-  {#each items as item}
-    
-      
-    
-  {/each}
-`}
-
- - diff --git a/web/routes/temas/animations/dom-cascade/+page.svelte b/web/routes/temas/animations/dom-cascade/+page.svelte deleted file mode 100644 index 4e034ca21..000000000 --- a/web/routes/temas/animations/dom-cascade/+page.svelte +++ /dev/null @@ -1,242 +0,0 @@ - - - - DomCascade · children-DOM (M9 F1c) - - -
-
- ← Motion -

DomCascade children-DOM · M9 F1c

-

- La segunda coordinación del servicio (RFC §M9). A diferencia de - Reveal / Rail - —donde cada ítem es un Presence registrado— aquí el owner es un solo - Presence (el contenedor) y los ítems son DOM estático: justo la - forma de un menú real. El propagador DomCascade - espeja el data-starting/ending-style del owner + un - --motion-stagger-index por orden DOM en cada ítem, reutilizando el preset - coordinado de eidos sin cambiarlo. Es la grieta que el menú destapó, ya pavimentada. -

-

- F1b validó la entrada; F1c cierra la - salida: el owner ahora espera a los ítems antes de - desmontar. Su getAnimations() no ve las transiciones de los ítems —sin - subtree— así que el DomCascade expone un pending() que el - Presence agrega. Ciérrala: los ítems salen en cascada antes de que - el contenedor desaparezca. -

-
- -
- {#each STYLES as s (s.value)} - - {/each} -
-
-
- - -
- {#if presence.isPresent} -
- {#each ITEMS as label (label)} -
{label}
- {/each} -
- {/if} -
-
- - diff --git a/web/routes/temas/animations/dropdown-menu/+page.svelte b/web/routes/temas/animations/dropdown-menu/+page.svelte deleted file mode 100644 index f85090b62..000000000 --- a/web/routes/temas/animations/dropdown-menu/+page.svelte +++ /dev/null @@ -1,229 +0,0 @@ - - - - DropdownMenu cascade · children-DOM (M9 F2) - - -
-
- ← Motion -

DropdownMenu item cascade · M9 F2

-

- El modo children-DOM sobre un componente real. El - <DropdownMenu> expone una prop animation: al activarla, las filas - del menú entran y salen en cascada reusando el preset coordinado de eidos sin - cambiarlo. El Content es el Presence dueño; el provider descubre las filas - (getCascadeRows) y propaga el lifecycle. Convive con focus-trap, dismissal, roving - focus y submenú. -

-

- Ábrelo y ciérralo: en salida, el panel espera a que las filas - salgan (F1c · pending) antes de desmontar. El foco vuelve al botón al cerrar, no al - terminar la animación. Cascadea todo: items, separadores y cabeceras, - incluyendo deshabilitados. -

- -
-
- {#each PRESETS as p (p.value)} - - {/each} -
- - -
-
- -
- - Cuenta ▾ - - - Cuenta - Perfil - Ajustes - Facturación (no disponible) - - - - Notificaciones - - - - Tema - Claro - Oscuro - Sistema - - - - Más opciones - - Exportar… - Importar… - - - - Salir - - - -

- Última selección: {lastSelected ?? '—'} -

-
-
- - diff --git a/web/routes/temas/animations/menu-native/+page.svelte b/web/routes/temas/animations/menu-native/+page.svelte deleted file mode 100644 index 964091955..000000000 --- a/web/routes/temas/animations/menu-native/+page.svelte +++ /dev/null @@ -1,216 +0,0 @@ - - -
-

Fase 0 — cierre con arrastre (persiana del panel)

-

- Al cerrar: los ítems salen en cascada (se ven) y luego el panel colapsa como persiana - (grid 1fr→0fr, sin medir en JS), con retardo → el panel los «arrastra». Es la firma de cierre - propia del panel (when: exit: 'after'). Ajusta el retardo: -

- - - -
- - {#if open} - - - {/if} -
- - {#if open} -
- {#each items as label, i (label)} -
- {label} -
- {/each} -
- {/if} -
- - diff --git a/web/routes/temas/animations/panel-cascade/+page.svelte b/web/routes/temas/animations/panel-cascade/+page.svelte new file mode 100644 index 000000000..e9c560939 --- /dev/null +++ b/web/routes/temas/animations/panel-cascade/+page.svelte @@ -0,0 +1,156 @@ + + +
+
+

Panel → cards cascade Fase 1 · modelo verificado

+

+ El estado y el lifecycle los lleva la página (rol de soma): cambia + data-state y RETIENE la card que sale (out:). La cascada es + CSS puro de eidos (panel-cascade.css); el índice por card sale + de :nth-child — nadie escribe una --var por card. +

+
+ +
+ + + +
+ + +
+ {#each cards as i (i)} +
+ + Card {i + 1} + row index {i} · delay {i}×{rhythm}ms + +
+
+
+
+
+
+
+ {/each} +
+
+ + diff --git a/web/routes/temas/animations/panel-cascade/+page.ts b/web/routes/temas/animations/panel-cascade/+page.ts new file mode 100644 index 000000000..6c31a302f --- /dev/null +++ b/web/routes/temas/animations/panel-cascade/+page.ts @@ -0,0 +1,2 @@ +// Fase 1 prototype — panel→cards cascade on the verified model. Live, no prerender. +export const prerender = false diff --git a/web/routes/temas/animations/panel-cascade/panel-cascade.css b/web/routes/temas/animations/panel-cascade/panel-cascade.css new file mode 100644 index 000000000..08b7a8c5f --- /dev/null +++ b/web/routes/temas/animations/panel-cascade/panel-cascade.css @@ -0,0 +1,157 @@ +/* + * Fase 1 prototype — the cascade, as a real eidos recipe would ship it: PLAIN global + * CSS in a .css file (no Svelte ` diff --git a/web/routes/temas/animations/presence-group/coord-item.svelte b/web/routes/temas/animations/presence-group/coord-item.svelte deleted file mode 100644 index c86ab2d8c..000000000 --- a/web/routes/temas/animations/presence-group/coord-item.svelte +++ /dev/null @@ -1,62 +0,0 @@ - - -{#if presence.isPresent} -
- ítem {index + 1} -
-{/if} - - diff --git a/web/routes/temas/animations/presence-group/coord-list.svelte b/web/routes/temas/animations/presence-group/coord-list.svelte deleted file mode 100644 index 3d029009c..000000000 --- a/web/routes/temas/animations/presence-group/coord-list.svelte +++ /dev/null @@ -1,75 +0,0 @@ - - -{#if container.isPresent} -
- {#each items as i (i)} - - {/each} -
-{/if} - - diff --git a/web/routes/temas/animations/rail/+page.svelte b/web/routes/temas/animations/rail/+page.svelte deleted file mode 100644 index 106cf4650..000000000 --- a/web/routes/temas/animations/rail/+page.svelte +++ /dev/null @@ -1,252 +0,0 @@ - - - - Rail · 2º consumidor coordinado - - -
-
- ← Motion -

Rail 2º consumidor del helper coordinado

-

- Misma coordinación que Reveal, otra forma: la raíz - ES la superficie owner, la relación es together (todo en - paralelo, el escalonado lo pone el CSS), es controlada por el padre - (bind:open, sin trigger) y no tiene eventos sema. Todo el wiring - —PresenceGroup + routing + auto-stagger— sale del helper compartido - soma/layers/coordination.ts; construir este componente fueron cuatro líneas. -

-
- -
- {#each STYLES as s (s.value)} - - {/each} -
-
-
- - -
-
- -
- - {#each ITEMS as label (label)} - {label} - {/each} - -
-
- - diff --git a/web/routes/temas/animations/reveal/+page.svelte b/web/routes/temas/animations/reveal/+page.svelte deleted file mode 100644 index 1d0773413..000000000 --- a/web/routes/temas/animations/reveal/+page.svelte +++ /dev/null @@ -1,343 +0,0 @@ - - - - Reveal · primer consumidor real - - -
-
- ← Motion -

Reveal primer consumidor real

-

- A diferencia del demo presence-group —que - construye Presence + PresenceGroup a mano— esto usa el componente - real <Reveal>: su morfo declara - panel.animation.children = { enter: 'before', exit: 'after' }, y el - provider lee ese contrato compilado para construir el grupo (RFC §4). El - panel entra, luego los ítems entran en cascada; al cerrar los ítems salen - primero mientras el panel retiene su DOM (exit-heavy §8.1), y solo después se - va el panel. El escalonado es CSS puro; soma solo decide el cuándo. El - selector cambia el prop animation, que el componente - enruta a las superficies declaradas - (Panel + Items) como data-animation-style — se nombra una vez, el sistema sabe dónde - (RFC §5). -

-

- Modo (c) — compone sema + motion (RFC Apéndice B): al abrir y al - cerrar, los eventos declaran channels: ['sound'] y suena un tono - emerge a la vez que corre la cascada. No pelean porque - eidos neutraliza su propia firma visual sobre las superficies coordinadas - (animation: none donde hay data-animation-style + - data-event-phase); la cascada es transition y sobrevive. El opt-out vive - en motion, sema intacto. (Sube el volumen; el audio arranca con el primer click.) -

-
-
- {#each STYLES as s (s.value)} - - {/each} -
- - Para la animación fluida, abre esta página enfocada en el browser (en preview de fondo el - rAF se throttlea). -
-
- - -
-
- - -
- - - {open ? '▾' : '▸'} Menú de cuenta - - - {#each ITEMS as label (label)} - {label} - {/each} - - -
-
- -