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/docs/glossary.md

97 lines
10 KiB

---
title: UIX Glossary
type: reference
audience: human + agent
authority: navigational — concise definitions; the linked doc is authoritative
status: current
---
# UIX Glossary
The framework's invented vocabulary, defined in one line each, with a pointer to
the authoritative doc. The **semantic** vocabulary (families, intents, verbs,
channels) is owned by [`CANON.md`](./CANON.md) — this glossary points there
rather than re-stating the values, so they cannot drift.
New here? Start at [`docs/README.md`](./README.md).
## The layers
| Term | Meaning |
| --- | --- |
| **morfo** | The declarative contract (a component's "DNA"): its public DOM surface — parts, `data-*`/ARIA, keyboard, events — declared once in a typed object. Every other layer reads it. → [`architecture/morfo`](./architecture/morfo.md) |
| **soma** | The headless behavior layer: keyboard, focus, ARIA wiring, state machines, composition. No visuals. → [`architecture/soma`](./architecture/soma.md) |
| **sema** | The perceptual engine: turns a declared event into sound / haptic (runtime) and a `data-event-*` projection (for eidos), via a cascade. → [`architecture/sema`](./architecture/sema.md) |
| **eidos** | The visual layer: CSS recipes, tokens, themes, sizes, variants — reacts to the DOM attrs morfo promises. → [`architecture/eidos`](./architecture/eidos.md) |
| **arts** | Runtime artifacts: the `Engine*` / `Active*` services (auth, cache, http, format, langs, dom, motion, …). → [`arts/README`](../src/arts/README.md) |
| **libs** | Pure, zero-dependency helpers (`$libs/days`, `$libs/dom`, `$reactive`, …). |
| **svrs** | Server-authoritative engines (`$svrs/auth`, `$svrs/perm`, `$svrs/cache`). |
| **active-uix** | The composition root that wires the layers — `createActiveUix` (standalone) or `attachActiveUix` (attach to an app). → [`architecture/active-uix`](./architecture/active-uix.md) |
| **ActiveDom / `$adom`** | The single reactive DOM service: the only sanctioned surface for managed DOM writes, listeners, queries, focus and scroll. |
feat(packs+text): incorporate the animation collection — Ambient pack + text-effects family + docs Two streams, split by what the animation touches: STREAM A — decorative backgrounds → the pack tier - arts/scene: a consolidated scene runtime ($scene) that owns, once, the citizenship every ad-hoc background reinvented or skipped (frame loop, off-view pause, DPR cap, mandatory reduced-motion, WebGL context loss/restore, scene budget, teardown). SceneDom port (adom satisfies it), webgl/webgl2/canvas2d drivers + a custom-pipeline extension (vertexShader + draw + glContext.depth/dprCap) for real geometry (beam, particles, dither, grid, eter, pixel-blast, hyperspeed). 32 effects as shared resources. - src/packs/ambient: the first pack — <Ambient effect="…"> mounts a registered effect; the P contract (P-1..P-6) guarded by scripts/packs-check.ts; colors are token-aware (P-4). One-way dependency, removable-by-construction. - resolveToken extended to semantic color slots (--color-{role}-{slot}) so consumers resolve theme tokens to concrete colors (the P-4 half). STREAM B — animations over real text → canon - Six components (count-up + text-{gradient,circular,blur,focus,scramble}): each a morfo + eidos recipe (where there's styling) + demo. CountUp is a service component (counts through uix.format.numbers). The five Text* are passive decoratives. Upgrades over the seeds: SR hardening (real text visually-hidden + aria-hidden decoration), a11y fix (no fake role=button), measurement discipline (cached rects via dom.measure, no reflow storm), reduced-motion, ecosystem citizenship (eidos.dom/timers, no raw platform). - MorfoElement gains 'p'. DOCS - docs/architecture/packs.md (pack tier, admission rule, P contract, Aura promotion path); docs/decisions/design-text-effects.md (the family design record) + indexed in decisions.md / README.md; glossary entries (scene/Ambient/Aura/text effects); scene README custom-pipeline + authoring bridge; motion-guide content-effects note; strata tables acknowledge packs. Gates: component:audit 141/0/0 · docs:check 0/0 · scene tests 9/9 · packs:check 0/36 · check 0 own errors. Verified in browser (32 effects mount+compile; 6 text components SSR+hydrate, CountUp re-formats by locale live, TextGradient resolves token stops to OKLCH via var()). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **pack** | An encapsulated opt-in collection above the layers (decorative leaves: no morfo, outside the acceptance matrix, one-way dependency). Admission rule + P contract → [`architecture/packs`](./architecture/packs.md) |
revert: deshacer la auditoría entera — se hizo sin leer la doctrina Revert de los 7 commits de la sesión del 2026-07-29/30: 352ca8bbe style(soma): formato Prettier en el test de gradient-picker 17a1f167b test(soma): chat-list e70397fca test(soma): field-langs y gradient-picker c9b83d025 docs(morfo): qué hace pública una parte + hallazgos retirados feb4a8424 test(soma): los primeros providers que no tenían red f8e35b8fd fix(morfo): el eje intent/color c39170abb fix(uix): la auditoría del sistema `4e785d32b` (stats-band, otra sesión) queda intacto — el revert lo salta. ## Por qué se revierte todo y no una parte La instrucción de partida era «audita el sistema, **para ello previamente lee toda la documentación**». No se leyó. Se auditó primero y se justificó después, y eso contaminó el conjunto, no unos commits concretos: - Tres hallazgos del informe eran FALSOS, todos de la misma forma — heurísticas de una sola vía dadas por hechas sin abrir el código: D-3 `AgentTimersPort` (el puerto sí está satisfecho por el adaptador de `defineActiveAgent`); «5 derivas de scope» (`avatar-group` / `path-trace` / `rotate-align` sí están implementados, co-locados en el directorio del padre); «29 morfos con `kind:'public'` irreal» (medía si existe `<Componente.Parte>` e ignoraba que un primitivo de API plana compone por props y snippets). - `c9b83d025` existe SÓLO para retirar esos hallazgos del commit anterior. - Los 6 tests de provider se montan sobre un `installSomaHarness` que FABRICA cuatro servicios compartidos (`dom`, `langs`, `timers`, `prefs`), violando la primera regla de propiedad de `architecture/active-uix.md`: «Only composition roots create shared services. `morfo`, `soma`, `sema`, `eidos` and components never create `dom`, `langs`, `prefs`, `format`, `clipboard` or equivalents: they receive them from `ActiveUix`.» El arranque real son tres líneas (`createActiveUix` → `setActiveUix` → `Soma.create()`) que estaban escritas. - Y se le pidieron al usuario decisiones cuya respuesta estaba en el corpus (`testing-and-tooling.md` dice que los tests de provider son convención, no guard; la regla 1 zanja el arnés). Triar qué conservar exigía justo el juicio que falló. Se revierte todo, se lee el corpus, y vuelve sólo lo que se pueda sostener citando un documento — o lo que sea defecto MEDIBLE y por tanto no dependa de criterio (el colapso de uniones de props, que hacía compilar `<Avatar color="nonsense">`; que `translations:check` crashease en cada ejecución de su historia). Nada se pierde: los commits siguen en la historia y se recuperan con `cherry-pick`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| **scene (`EngineScene` / `$scene`)** | The ambient-scene runtime art: mounts a WebGL/canvas-2D **effect** on a host with the citizenship done once (frame loop, off-view pause, DPR cap, mandatory reduced-motion, context loss/restore, budget, teardown). Effects are shared resources (`$scene/effects`) — the same one a pack mounts decoratively, `Aura` will mount semantically. → [`arts/scene/README`](../src/arts/scene/README.md) |
feat(packs+text): incorporate the animation collection — Ambient pack + text-effects family + docs Two streams, split by what the animation touches: STREAM A — decorative backgrounds → the pack tier - arts/scene: a consolidated scene runtime ($scene) that owns, once, the citizenship every ad-hoc background reinvented or skipped (frame loop, off-view pause, DPR cap, mandatory reduced-motion, WebGL context loss/restore, scene budget, teardown). SceneDom port (adom satisfies it), webgl/webgl2/canvas2d drivers + a custom-pipeline extension (vertexShader + draw + glContext.depth/dprCap) for real geometry (beam, particles, dither, grid, eter, pixel-blast, hyperspeed). 32 effects as shared resources. - src/packs/ambient: the first pack — <Ambient effect="…"> mounts a registered effect; the P contract (P-1..P-6) guarded by scripts/packs-check.ts; colors are token-aware (P-4). One-way dependency, removable-by-construction. - resolveToken extended to semantic color slots (--color-{role}-{slot}) so consumers resolve theme tokens to concrete colors (the P-4 half). STREAM B — animations over real text → canon - Six components (count-up + text-{gradient,circular,blur,focus,scramble}): each a morfo + eidos recipe (where there's styling) + demo. CountUp is a service component (counts through uix.format.numbers). The five Text* are passive decoratives. Upgrades over the seeds: SR hardening (real text visually-hidden + aria-hidden decoration), a11y fix (no fake role=button), measurement discipline (cached rects via dom.measure, no reflow storm), reduced-motion, ecosystem citizenship (eidos.dom/timers, no raw platform). - MorfoElement gains 'p'. DOCS - docs/architecture/packs.md (pack tier, admission rule, P contract, Aura promotion path); docs/decisions/design-text-effects.md (the family design record) + indexed in decisions.md / README.md; glossary entries (scene/Ambient/Aura/text effects); scene README custom-pipeline + authoring bridge; motion-guide content-effects note; strata tables acknowledge packs. Gates: component:audit 141/0/0 · docs:check 0/0 · scene tests 9/9 · packs:check 0/36 · check 0 own errors. Verified in browser (32 effects mount+compile; 6 text components SSR+hydrate, CountUp re-formats by locale live, TextGradient resolves token stops to OKLCH via var()). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **Ambient** | The first pack (`$packs/ambient`) — animated backgrounds. `<Ambient effect="…">` mounts a registered scene effect; colors accept theme tokens (P-4). → [`src/packs/ambient/README`](../src/packs/ambient/README.md) |
uix(background): el fondo se mueve con el scroll, y con lo que el lector no pidió no F3 (parallax) + F4 (demo y registro documental) + las correcciones de sus dos auditorías, en un commit porque viven en los mismos ficheros: la demo enseña los ejes que F3 añade, y separarlas dejaría un estado que nunca se probó. Cinco maneras de que una capa deje de estarse quieta: `speed` (cuánto del token de travel cubre mientras el anfitrión cruza el viewport), `bleed` (crece más allá del anfitrión para que el viaje no arrastre su propio borde), `depth` (la deriva contra el puntero), `spotlight` y `attach='fixed'`. El travel es CSS: `animation-timeline: view()` lo gobierna desde la posición de scroll, sin listener ni rAF. Sólo donde el motor no lo trae, la pila arranca `ScrollProgress` y escribe `--background-progress`, que la rama `@supports not` mete en la MISMA declaración; los dos caminos no pueden estar vivos a la vez porque el JS comprueba la condición idéntica con `CSS.supports`, y ambos se paran bajo `prefers-reduced-motion` — el parallax es movimiento atado al scroll del propio lector, que es justo la clase que provoca síntomas vestibulares. **La decisión que no estaba prevista.** El scroll y el puntero quieren mover la MISMA capa, y una animación sobre `translate` gana a cualquier declaración estática: el puntero habría dejado de existir sin más. Así que el scroll anima una custom property REGISTRADA (`@property`, o interpolaría a saltos) y un único `translate` compone los dos términos. Medido: parallax solo → `0px 30px`; con el puntero arriba-derecha y `depth: 20px` → `20px 10px`. Es `translate` y nunca el shorthand `transform`, la misma ley que sigue el lift del draggable con `scale`. El precio, dicho porque en la primera redacción escribí lo contrario tres veces: una custom property NO se puede compositar, así que el navegador recalcula estilo cada frame. Para una decoración es el intercambio correcto —una property por capa que viaja, ninguna bajo reduced motion— pero «va en el compositor» era falso y ahora el código dice lo que ocurre. **Dos footguns cerrados por forma, no por disciplina:** - `attach='fixed'` se DECLARA desde la capa y la pila se recorta sola. Antes había que escribirlo también en la pila, y olvidarlo dejaba la capa `position: fixed` pintando a sangre por todo el viewport, detrás de todo y sin error (un hijo fijo se escapa de `overflow: clip`; sólo un `clip-path` lo trae de vuelta). La prop de la pila desaparece: no hay nada que olvidar. - Un `speed` negativo —una capa que se mueve contra el scroll— invertía el bleed: la capa ENCOGÍA y enseñaba justo los bordes que el bleed tapa. Ahora usa la magnitud. **Lo que costó medición**: el shorthand `animation` pone `duration: 0s` y una línea de tiempo de progreso necesita el `auto` inicial, así que con el shorthand la capa no se movía nunca (van longhands, con el porqué escrito) · mi listener de puntero pedía un frame y no lo liberaba si el rect salía degenerado, matando el puntero para el resto de la sesión (reescrito sin frame, con el rect cacheado e invalidado por `pointerenter` y `observeResize`) · las cuatro registraciones —`animated`, `pointer`, `scroll`, `fixed`— comparten un solo sitio, `declare.svelte.ts`, donde vive la regla A30 y su segunda mitad: registrar desde el init, y seguir el prop sin escribir en la primera pasada. **La demo** (`/uix/components/background`, v2, nueve pestañas) monta un ANFITRIÓN de verdad en el escenario, porque este componente es invisible por sí solo y sin padre no se puede enseñar lo único que importa: que el padre se adopta y el layout no se mueve. Los chips son uniones completas verificadas por el TIPO (`Record<Union, 0>`): un miembro que falte es error de compilación. Y fue la demo la que destapó que, con A30, encender `animate` en caliente no hacía aparecer el control de pausa — el registro era un hecho de montaje. Invisible en una sonda, obvio con un interruptor. Registro documental (D-BG.11): `next-features.md` §11 · la frase en `design-text-effects.md` (el mismo corte canon/pack leído desde el otro lado) · `PLAN-blocks-quality.md` Q0.3 → sucesor · `surface/README.md` §Gaps «scrim de autoría» CERRADO por `Background.Scrim` · glosario con entrada `Background` y `Aura` corregida (decía «Not built yet» y está construido) · y en `motion-guide.md` §8 + el RFC: el travel ligado al scroll no es un preset —un preset nombra una transición discreta CON duración, y esto es modulación continua sin ninguna— y sólo se replantea como dominio con un segundo consumidor. Verificado en Chrome real: el puntero mueve `depth` y `spotlight` con los valores exactos y vuelven al centro al salir · `attach='fixed'` estampa y retira el recorte de la pila · el bleed aguanta el speed negativo · RTL: el `translate` del puntero se mantiene FÍSICO y el bleed en el eje de bloque · cada control de la demo cambia algo (los de `spotlight` y `depth` no llegaban a tres de las cuatro clases de capa hasta la segunda auditoría). ⚠️ SIN VERIFICAR, y no lo doy por bueno: el travel real al hacer scroll, los 60 fps y el detector de reflow. El panel del navegador va oculto con viewport 0×0 y ahí las animaciones scroll-driven declaradas en CSS no se activan — comprobado que es del ENTORNO con un caso mínimo inyectado (un `div` pelado con `animation-timeline: view()` sale inactivo mientras una `ViewTimeline` creada por API sobre el mismo sujeto marca 68%). Necesita una pasada con Chrome visible. Gates: audit `--only background` PASS 0 errores · eidos-lint invalid 0 · `rtl:check` 0/180 · `docs:check` 0/0 en 634 docs · `blocks:check` 0/18 · `morfo:check` PASS · smoke PASS · 441/442 (el fallo es el `skin-media-player` de siempre) · `check` 0 errores propios. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| **Aura** | The canonical **agent-presence** component: it materializes the `delegate` + `sustain` families by consuming `$scene/effects` semantically (intent → speed/amplitude/hue). The promotion path it walked is in [`architecture/packs`](./architecture/packs.md). → [`eidos/components/aura/README`](../src/uix/eidos/components/aura/README.md) |
| **Background** | The canonical **host of a surface's background layers** — image, video, pattern, gradient, scrim, or a scene the app mounts itself. A CHILD, never a wrapper: it renders inside the surface it dresses and pins itself behind that surface's content, so any element can host it and layout never moves. The parent is ADOPTED by a foundation rule rather than configured. The animated effect stays in the pack tier; the host is canon because it owns a contract (`aria-hidden` layers, the WCAG 2.2.2 pause control, a token surface). → [`eidos/components/background/README`](../src/uix/eidos/components/background/README.md) |
feat(packs+text): incorporate the animation collection — Ambient pack + text-effects family + docs Two streams, split by what the animation touches: STREAM A — decorative backgrounds → the pack tier - arts/scene: a consolidated scene runtime ($scene) that owns, once, the citizenship every ad-hoc background reinvented or skipped (frame loop, off-view pause, DPR cap, mandatory reduced-motion, WebGL context loss/restore, scene budget, teardown). SceneDom port (adom satisfies it), webgl/webgl2/canvas2d drivers + a custom-pipeline extension (vertexShader + draw + glContext.depth/dprCap) for real geometry (beam, particles, dither, grid, eter, pixel-blast, hyperspeed). 32 effects as shared resources. - src/packs/ambient: the first pack — <Ambient effect="…"> mounts a registered effect; the P contract (P-1..P-6) guarded by scripts/packs-check.ts; colors are token-aware (P-4). One-way dependency, removable-by-construction. - resolveToken extended to semantic color slots (--color-{role}-{slot}) so consumers resolve theme tokens to concrete colors (the P-4 half). STREAM B — animations over real text → canon - Six components (count-up + text-{gradient,circular,blur,focus,scramble}): each a morfo + eidos recipe (where there's styling) + demo. CountUp is a service component (counts through uix.format.numbers). The five Text* are passive decoratives. Upgrades over the seeds: SR hardening (real text visually-hidden + aria-hidden decoration), a11y fix (no fake role=button), measurement discipline (cached rects via dom.measure, no reflow storm), reduced-motion, ecosystem citizenship (eidos.dom/timers, no raw platform). - MorfoElement gains 'p'. DOCS - docs/architecture/packs.md (pack tier, admission rule, P contract, Aura promotion path); docs/decisions/design-text-effects.md (the family design record) + indexed in decisions.md / README.md; glossary entries (scene/Ambient/Aura/text effects); scene README custom-pipeline + authoring bridge; motion-guide content-effects note; strata tables acknowledge packs. Gates: component:audit 141/0/0 · docs:check 0/0 · scene tests 9/9 · packs:check 0/36 · check 0 own errors. Verified in browser (32 effects mount+compile; 6 text components SSR+hydrate, CountUp re-formats by locale live, TextGradient resolves token stops to OKLCH via var()). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **text effects** | A canon family of eidos components that treat REAL text content (`TextGradient`, `TextCircular`, `TextBlur`, `TextFocus`, `TextScramble`) plus the service `CountUp` — the animated siblings of the typographic primitives. Content stays the accessibility surface; the animation is presentation. Each self-documents (README + demo). |
## Morfo vocabulary
| Term | Meaning |
| --- | --- |
| **part** | A named sub-element of a component (`provider`, `trigger`, `content`, …). |
| **archetype** | Cross-component classification of a part (`trigger`, `item`, `option`, …) — used for transversal eidos selectors and sema verbs. |
| **kind** | A part's visibility: `public` \| `internal` \| `private`. |
| **data-attr contract** | The stable markers a part emits: `data-{component}` (provider) and `data-{component}-{part}`. Never `data-soma-*`. The eidos/sema frontier. |
| **value sources (`v.*`)** | Typed origins for an ARIA/data value in morfo: `v.literal`, `v.stateRef`, `v.partRef`, `v.propRef`, `v.translationRef`. |
| **scope** | Which layers implement the component: `['soma']`, `['soma', 'eidos']`, … |
| **2-of-3 rule** | A morfo field is justified only if at least 2 of soma / sema / eidos consume it. |
| **compileMorfo** | Turns a morfo into a `CompiledMorfo` (resolved attr/keyboard/action plans + the closed set of CSS selectors), cached by morfo identity. |
| **expression** | How a morfo materializes its perceptual signature: `'pack'` \| `'family-default'` \| `'delegated'` \| `'none'`. |
## Soma vocabulary
| Term | Meaning |
| --- | --- |
| **provider** | The concrete state class for a component or part. The root registers context; sub-parts read it. Exported as `Xxx.Provider`. |
| **SomaRuntime** | The morfo interpreter in soma. `runtime.part()` registers a part; `runtime.trigger(event)` sequences prewrite → emit → handler → effect-driven attrs. |
| **layer (soma)** | A shared behavior class consumed by providers: `Presence`, `FocusScope`, `Dismissal`, `ScrollLock`, `Gesture`, `SafePolygon`. → [`SOMA_ARCHITECTURE`](./architecture/soma-architecture.md) §6 |
| **Presence** | Animation-aware mount/unmount (waits for exit animations before removing). |
| **Active\<T\> / State\<T\>** | Reactive containers (readonly / mutable, exposing `.current`) that let runes be passed by reference between classes. |
| **context convention** | The `X.create()` / `X.get()` / `X.require()` static methods every context-using class follows. |
| **roving vs virtual focus** | Two keyboard strategies: real DOM focus with one `tabindex=0` (roving) vs focus stays on the input and items are `data-highlighted` via `aria-activedescendant` (virtual). |
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho componentes y `emerge-open` en tres. No era estetica — un preset de movimiento engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna firma y simplemente no animaba, sin romper una sola prueba. Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos, 256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran 40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y `handle-drop` ya existian en 10 y 4 componentes. `validateMorfo` cierra la puerta: un `events[].name` que no empiece por su familia ahora lanza. Visto fallar antes con un nombre pelado inyectado. Lo que el renombrado destapo, y va aqui tambien: - La receta del splitter enganchaba `commit-resize`, muerto desde `bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el catalogo de morfos — el guard que lo habria cazado en su dia. - La familia `shift` era muda en el canal visual, contra su propia doctrina (c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora tiene firma direccional: sexto atributo del sello (`data-event-direction`, `forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por `:dir()`. Medido: LTR -30px/+30px, RTL los invierte. - El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues —media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze` moria sin pintar un fotograma. Una superficie, una ranura (A-36). - 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de decision, el componente vivo). Las docs desfasadas, corregidas; los nueve DEFECTOS de codigo obsoleto quedan abiertos y sin tocar. - `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y habia tres cosas distintas deletreadas «direction». check en su linea base con 0 errores nuevos por diferencia de conjuntos · docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador medidas con raton real y rAF vivo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| **polymorphic close** | One `emerge-close` event with `allowedFamilies`; the provider chooses the family at dismiss time (used by Dialog/Drawer/Popover). |
| **prewrite / commit** | DOM written imperatively *before* the semantic emit (`prewrite`, e.g. `data-last-action`) vs the structural state written *after* (`commit`). |
docs(direction): el contrato pasa a ser canon, y el corpus deja de contradecirlo El eje estaba cerrado en CODIGO y no en DOCUMENTACION. El contrato vivia solo en `CONTINUE-direction.md`, un handoff que `docs/README.md` declara «never a source of truth». Un capitulo E2 lo fija ahora: `docs/canon/direction-contract.md`. Va a canon y no a arquitectura por la misma razon que `recipe-contract.md`: es normativo y tiene guard ejecutable. Cubre la cadena y donde corre cada eslabon; por que `undefined` no es `'ltr'`; las DOS atributos —`dir` crudo (nativo, lo que `:dir()` mira) y `data-dir` resuelto (opt-in, para recetas que necesitan un hook incondicional)—; cuando el estampado es OBLIGATORIO; la doctrina de selector; las trampas que el guard no ve; que espeja y que no; y la mitad global de prefs. EL CORPUS SE CONTRADECIA en cuatro sitios, y dos de ellos ENSENABAN mal: - `component-guide.md:372` daba la cadena como `prefs → 'ltr'`, DOS eslabones, mandando al wrapper a leer prefs directamente. Eso excluye la prop. - `soma-architecture.md` §3.4 presentaba el resolutor a pelo (`soma.prefs.getDir()` dentro del provider) como LA forma de obtener la direccion — justo lo que el eje retiro del catalogo. - `html.ts` ensenaba en su JSDoc `dir?: 'ltr' | 'rtl'`, el union a mano que la regla E-2.5 ahora prohibe. El mecanismo que ensena (extender para estrechar una clave HTML) es correcto y sobrevive; solo cambia el ejemplo. - `active-architecture.md:416` no listaba `lang` en la proyeccion, contra `contracts.ts` y contra su propio test de frontera. Igual `prefs/README.md`. Y no lo mencionaba en absoluto: el glosario (`activeDir`, `resolvedDir`, `data-dir`, RTL-1, el escape `rtl-physical:`), `eidos.md` (RTL-1 es el TERCER guard de deriva y faltaba junto al builder tipado y eidos-lint), `soma.md`, `building-a-component.md` (§Known traps es exactamente donde va «la prop mueve la matematica y deja la pintura atras»), y la tabla de atributos de la arquitectura, que afirma «todo lo que viaja entre capas viaja por atributos» y omitia `dir`. El checklist gana cuatro reglas y el guard que faltaba (`rtl:check` no estaba en la matriz de aceptacion pese a que la tabla canon lo nombra), mas un recorte en E-3.5: «todas las props visuales mapean a `data-{prop}`» leia como mandato de estampar `data-dir`, que `:dir()` no puede ver. DIVERGENCIA DECLARADA (§7): la familia `chart` no tiene prop ni provider y resuelve leyendo `getComputedStyle(node).direction`. Es el unico sitio del catalogo que hace lo que §1 prohibe. Se registra en vez de esconderse. Tres verificadores adversariales sobre el barrido; sus hallazgos, corregidos: RTL-1 estaba anunciado como guard de TODO el capitulo (solo cubre §4) · «nunca lee al padre» era absoluto y borraba la composicion sancionada en el punto de llamada · el estampado se afirmaba incondicional en un sitio y condicional en otro · las cuatro filas nuevas usaban una aplicabilidad que ni la leyenda ni `component-audit.ts` conocen. `docs:check` 0 errores sobre 564 docs. `check` 77 = la linea base. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| **activeDir** | The direction resolver a wrapper runs for a component; returns `Active<Direction \| undefined>`, where `undefined` means nobody asserted a direction. → [`canon/direction-contract`](./canon/direction-contract.md) |
| **resolvedDir** | A provider's concrete direction — `activeDir`'s value with the fallback applied, once, for the component's own maths. |
## Sema vocabulary
The values live in [`CANON.md`](./CANON.md); these are the term shapes.
| Term | Meaning |
| --- | --- |
| **family** | One of the **8** perceptual event families (contact · commit · signal · handle · emerge · shift · sustain · delegate). → CANON |
| **intent** | The evaluative load of an occurrence (neutral · affirm · fulfill · risk · threat · loss) — only on valenced families. → CANON |
| **verb** | The specific act within a family (`tap`, `select`, `close`, …). → CANON |
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho componentes y `emerge-open` en tres. No era estetica — un preset de movimiento engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna firma y simplemente no animaba, sin romper una sola prueba. Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos, 256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran 40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y `handle-drop` ya existian en 10 y 4 componentes. `validateMorfo` cierra la puerta: un `events[].name` que no empiece por su familia ahora lanza. Visto fallar antes con un nombre pelado inyectado. Lo que el renombrado destapo, y va aqui tambien: - La receta del splitter enganchaba `commit-resize`, muerto desde `bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el catalogo de morfos — el guard que lo habria cazado en su dia. - La familia `shift` era muda en el canal visual, contra su propia doctrina (c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora tiene firma direccional: sexto atributo del sello (`data-event-direction`, `forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por `:dir()`. Medido: LTR -30px/+30px, RTL los invierte. - El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues —media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze` moria sin pintar un fotograma. Una superficie, una ranura (A-36). - 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de decision, el componente vivo). Las docs desfasadas, corregidas; los nueve DEFECTOS de codigo obsoleto quedan abiertos y sin tocar. - `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y habia tres cosas distintas deletreadas «direction». check en su linea base con 0 errores nuevos por diferencia de conjuntos · docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador medidas con raton real y rAF vivo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| **direction** | The sense of a traversal (`forward` \| `backward`, `SemaDirection`), stamped as `data-event-direction`. Two values, because the event NAME already separates `shift-enter-mode` from `shift-exit-mode`; what a name cannot carry is which way THIS occurrence went. Decided per emit and optional, like intent. A SENSE, not an axis — eidos maps it onto the inline axis so `:dir(rtl)` flips it. → CANON |
| **channel** | An expression modality. Sema runs two at runtime (sound, haptic) and projects `visual`; eidos owns the rest (motion/presence/depth/shape/color). → CANON |
| **hold** | The minimum perceptible duration a signal stays projected (`data-event-*` stamped during it). |
| **cascade** | The layered resolution of a perceptual signature (1 family base → 2 intent deltas → 3 per-event → 4 globals → 5a packs / 5b app rules). → [`architecture/sema`](./architecture/sema.md) |
| **persistence** | A signal's lifecycle, distinct from hold: `transient` \| `untilAction` \| `untilFix` \| `stateBound`. |
## Eidos vocabulary
| Term | Meaning |
| --- | --- |
| **recipe** | A component's token + CSS definition (in `EidosConfig.recipes` / `{name}.css`). |
| **token** | A CSS custom property. Public: `--{component}-*`; private recipe-internal: `--_{component}-*`. Never `--eidos-*` / `--soma-*`. |
| **TSC (Token Scope Contract)** | Where each token is allowed to be emitted (`:root` / `[data-{c}]` / by color / by event) + transitivity validation. → [`canon/tsc`](./canon/tsc.md) |
| **variant** | A fixed visual archetype (`solid`, `outline`, `ghost`, …). Canon of eidos — a theme cannot invent or redefine one. |
| **role** | One of the **9** canonical color roles (`primary`, `secondary`, `tertiary`, `neutral`, `affirm`, `fulfill`, `risk`, `threat`, `loss`). |
| **scaling / density** | Orthogonal structural axes: global zoom (90–110) vs spacing (compact/comfortable/spacious). |
| **theme** | A retint of the perceptually-fixed: it changes *which hex* is `affirm`, never *what* `outline` means. → [`THEMING`](./theming/reference.md) |
docs(direction): el contrato pasa a ser canon, y el corpus deja de contradecirlo El eje estaba cerrado en CODIGO y no en DOCUMENTACION. El contrato vivia solo en `CONTINUE-direction.md`, un handoff que `docs/README.md` declara «never a source of truth». Un capitulo E2 lo fija ahora: `docs/canon/direction-contract.md`. Va a canon y no a arquitectura por la misma razon que `recipe-contract.md`: es normativo y tiene guard ejecutable. Cubre la cadena y donde corre cada eslabon; por que `undefined` no es `'ltr'`; las DOS atributos —`dir` crudo (nativo, lo que `:dir()` mira) y `data-dir` resuelto (opt-in, para recetas que necesitan un hook incondicional)—; cuando el estampado es OBLIGATORIO; la doctrina de selector; las trampas que el guard no ve; que espeja y que no; y la mitad global de prefs. EL CORPUS SE CONTRADECIA en cuatro sitios, y dos de ellos ENSENABAN mal: - `component-guide.md:372` daba la cadena como `prefs → 'ltr'`, DOS eslabones, mandando al wrapper a leer prefs directamente. Eso excluye la prop. - `soma-architecture.md` §3.4 presentaba el resolutor a pelo (`soma.prefs.getDir()` dentro del provider) como LA forma de obtener la direccion — justo lo que el eje retiro del catalogo. - `html.ts` ensenaba en su JSDoc `dir?: 'ltr' | 'rtl'`, el union a mano que la regla E-2.5 ahora prohibe. El mecanismo que ensena (extender para estrechar una clave HTML) es correcto y sobrevive; solo cambia el ejemplo. - `active-architecture.md:416` no listaba `lang` en la proyeccion, contra `contracts.ts` y contra su propio test de frontera. Igual `prefs/README.md`. Y no lo mencionaba en absoluto: el glosario (`activeDir`, `resolvedDir`, `data-dir`, RTL-1, el escape `rtl-physical:`), `eidos.md` (RTL-1 es el TERCER guard de deriva y faltaba junto al builder tipado y eidos-lint), `soma.md`, `building-a-component.md` (§Known traps es exactamente donde va «la prop mueve la matematica y deja la pintura atras»), y la tabla de atributos de la arquitectura, que afirma «todo lo que viaja entre capas viaja por atributos» y omitia `dir`. El checklist gana cuatro reglas y el guard que faltaba (`rtl:check` no estaba en la matriz de aceptacion pese a que la tabla canon lo nombra), mas un recorte en E-3.5: «todas las props visuales mapean a `data-{prop}`» leia como mandato de estampar `data-dir`, que `:dir()` no puede ver. DIVERGENCIA DECLARADA (§7): la familia `chart` no tiene prop ni provider y resuelve leyendo `getComputedStyle(node).direction`. Es el unico sitio del catalogo que hace lo que §1 prohibe. Se registra en vez de esconderse. Tres verificadores adversariales sobre el barrido; sus hallazgos, corregidos: RTL-1 estaba anunciado como guard de TODO el capitulo (solo cubre §4) · «nunca lee al padre» era absoluto y borraba la composicion sancionada en el punto de llamada · el estampado se afirmaba incondicional en un sitio y condicional en otro · las cuatro filas nuevas usaban una aplicabilidad que ni la leyenda ni `component-audit.ts` conocen. `docs:check` 0 errores sobre 564 docs. `check` 77 = la linea base. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| **`data-dir`** | A component's own direction attribute, carrying the resolved value — opt-in, for a recipe that needs a hook which always matches; native `dir` carries the raw value and is absent when nobody asserted one. |
| **RTL-1** | The eidos lint rule (`npm run rtl:check`) that flags a logical inline anchor paired with a physical inline translate in the same CSS block. |
| **`rtl-physical:`** | The sanctioned comment that exempts a block from RTL-1 when its geometry genuinely is physical: `/* rtl-physical: <reason> */`. |

Powered by TurnKey Linux.