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/architecture/packs.md

90 lines
4.9 KiB

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
---
title: Packs — encapsulated opt-in collections
type: reference
audience: human + agent
authority: E1 architecture — the pack tier: what it is, the canon-vs-pack admission rule, the P contract, the promotion path
status: current
---
# Packs
A **pack** is an encapsulated, opt-in collection that sits ABOVE the UIX
layers and OUTSIDE the component canon. It consumes the framework; the
framework never references it. The live inventory is the `src/packs/` tree —
never a list in a doc.
Packs exist so that **decorative surface area does not dilute the canon**:
the catalog's value is contract density (events, ARIA, keyboard, tokens other
layers consume); a pack's value is parameterized leaf decoration. Mixing the
two would put fashion-velocity artifacts inside the doctrine that must age
slowly.
## The admission rule (canon vs pack)
> **Canon** = anything with contract surface that others consume — semantic
> events, ARIA/keyboard behavior, state machines, tokens targeted by other
> recipes. It enters through the 9-phase route and the acceptance matrix.
>
> **Pack** = a decorative leaf with parameters — nothing else in the system
> selects against it, listens to it, or inherits from it. It enters through
> the P contract below, and stays out of `component:audit`.
If a pack piece grows contract surface (a real event, an a11y obligation, a
token another recipe wants), that is the signal to **promote it to the
canon** through the full route — never to grow the pack's privileges.
## Hard boundaries
1. **Dependency direction is one-way**: `src/packs/*` may import `$uix/*`,
`$scene`, `$adom` and the other arts; nothing under `src/{arts,libs,uix}`
may import from `src/packs/`. Deleting a pack directory must leave
`npm run check` green — that is the encapsulation proof.
2. **No morfo, no matrix**: pack pieces declare no morfo and take no row in
the acceptance matrix. Their DOM is decorative (`aria-hidden` where it
paints, `pointer-events: none` unless an effect opts into pointer input).
3. **Packs are removable by construction** — an app that never imports a
pack pays zero bytes for it (per-module registration, tree-shaken).
## The P contract (the pack quality floor)
A pack is exempt from the acceptance matrix, NOT from discipline. Every pack
ships with these six obligations, guarded mechanically (`packs-check`):
| P | Obligation |
| --- | --- |
| P-1 | Every animated piece declares a `reduce` policy (`'static-frame'` \| `'hide'`) — no silent default; reduced motion is honored via the injected DOM port, never a raw `matchMedia`. |
| P-2 | Full teardown: every mount returns a handle whose `dispose()` releases frames, observers, GL resources and listeners. |
| P-3 | DOM only through the injected port (`dom.requestFrame` / `observeResize` / `observeIntersection` / `listen`) — raw `requestAnimationFrame` / `ResizeObserver` / `IntersectionObserver` / `addEventListener` in `src/packs/` is an error. |
| P-4 | Color parameters are token-aware: they accept an eidos custom-property name (resolved via `eidos.resolveToken`, re-resolved on mode change) or a raw CSS color as fallback; hardcoded palettes without a token path are an error for theme-facing params. |
| P-5 | Decorative DOM is `aria-hidden="true"`; pointer interactivity is opt-in per piece and never traps focus. |
| P-6 | Off-screen and hidden-tab work is paused; a scene budget guards against unbounded concurrent GL contexts (warn via logger). |
fix(uix): la auditoría del sistema — lo que los guards no veían Auditoría clean-room de todo ActiveUIX (excluido `web/`), componente a componente. Lo que sale de aquí no es una lista de bugs: es un patrón. El framework validaba que lo escrito fuese VÁLIDO, no que lo declarado se CUMPLIESE — y sus guards fallaban ABIERTOS. ## El colapso de las uniones de props (95 → 0) Un `Props` de eidos es `{ …props propias… } & <atributos nativos>`. Cuando el elemento declara un atributo homónimo, la intersección funde ambos y una unión estrecha contra el `string` nativo COLAPSA a `string`. Causa: `Without<T, U> = Omit<T, keyof U>` invocado como `Without<T, {}>` — `Omit<T, never>`, un no-op — 433 veces en soma; sólo 3 con argumento real. Invisible para `svelte-check`: ensanchar un tipo no es un error, es una garantía perdida. Medido: 95 props en 72 componentes. `<Avatar color="nonsense">` compilaba. `ComboboxInput.size` chocaba con el `<input size>` numérico y era inusable. Migrado con codemod sobre AST (nunca regex) a `Own & Omit<Nativos, keyof Own>`: 92 tipos en 73 ficheros + carousel a mano. `check` no se movió. Garantía nueva: `eidos/prop-surface.test.ts` (PROP-1) compara los literales de la anotación del autor contra los de la propiedad pública. Verificado que falla reintroduciendo el defecto. ## Los cuatro guards que fallaban abiertos - `translations:check` crasheaba en CADA ejecución de su historia — un stripper de comentarios borraba `//` dentro de strings. Sustituido por import dinámico. Al arrancar destapó 8 slots `texts` sin traducción. - `soma-attr-audit` agotaba el timeout de 5 s: sin veredicto, verde por omisión. - `component-audit` D-7.4 hacía `continue` mudo cuando el tipo no resolvía. Ahora resuelve con el checker de TypeScript (`scripts/prop-unions.ts`): puntos ciegos de 124 → 3. - `component-audit` R-1.1: el regex casaba `[data-motion='reduce']` y daba PASS por el motivo equivocado. Regla adoptada: un guard que no puede evaluar TIENE que decirlo. El informe lleva ahora bloque «Not verified» y recuento en el resumen. ## D-1 · tooltip y D-2 · card, cableados `tooltip` declaraba 3 eventos `emerge` que nadie emitía. Ahora emiten; `present` pasa a `sequence: 'post'` — con `'pre'` el hold de ~240 ms gateaba el montaje del propio overlay. `card` declaraba `commit-select` sin emisor posible (scope sin soma). Puente headless en `soma/components/card/` con la forma ya establecida por `menu-dial` / `onion-menu`: eidos posee estado y render, soma posee sólo el `SomaRuntime` que emite. ## Documentación: 22 mentiras corregidas `docs/` afirmaba guards inexistentes (`NO_MISSING_PROVIDER_TESTS`), APIs con firma equivocada y un modelo de Motion que el código no implementa. Corregido en CANON, arquitectura, glosario, theming/motion, checklist y los README de `motion` / `callout` / `arts/motion`. ## Además - CardGroup: la descripción se metía en la primera celda del grid. - Motion: `data-state` siempre estampado, salida real en `leave()`, token fantasma `--motion-stagger-each-default` eliminado. - `engine-motion`: `handoffState` Map → WeakMap (fuga por nodo). - `mockup`: primitivo crudo → token de rol (R-4.6). - 5 catálogos de traducción que faltaban. Handoff: `docs/process/CONTINUE-audit-2026-07-29.md`. Batería: check 0 errores en src · vitest server 3701/3701 · docs:check 0/0 · component:audit 161 PASS / 2 NEEDS-WORK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## The promotion path (walked)
The first pack (`ambient`, animated backgrounds) was built ahead of its
canonical consumer: the **agent-presence component** `Aura`, which materializes
the `delegate` + `sustain` families — the visual channel is the ONLY channel
`delegate` activates (see `decisions/book-deviations.md` D.8).
That promotion has since happened, and it validated the design: because the
**effects are shared resources, not pack internals** — they live with the
runtime (`$scene/effects`) — the pack mounts them decoratively and `Aura`
mounts the same resources semantically (states from the agent lifecycle;
intent modulating speed / amplitude / hue — the visual analog of sound's
pitch / gain / contour). Orientative state → effect mapping: idle →
mesh/fog/grainient · listening → orb/lumen · thinking → aurora/silk ·
acting/streaming → threads/waves · searching → radar · error (event, not
state) → ray.
With `Aura` landed, the scene runtime **is** promoted: `uix.scene` is part of
`ActiveUix`'s surface (`createActiveUix` builds it from the available `dom`;
attach reads `app.scene`, falling back to its own). `createEngineScene` remains
the standalone factory for use outside a UIX tree.
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
## Provenance note
The seed collection (`web/routes/demos/animations`, 45 effects) is kept
intact as **comparative reference material** — it is NOT the pack. The pack
implementations are built clean against the P contract; the originals stay to
compare against and are excluded from the framework's guards.

Powered by TurnKey Linux.