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/process/PLAN-scene-ambient-pack.md

151 lines
22 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# PLAN — Motor de escenas + pack Ambient + vía de promoción agéntica
> **Tipo**: plan de ejecución por fases (process — efímero, no fuente de verdad).
> **Fecha**: 2026-07-11 · **Estado**: D1–D9 RESUELTAS · **F0 ✅ + F1 ✅ + F2 ✅ + F3 ✅ + F4 ✅ + F4b ✅ (2026-07-12)** — los 45 fondos aprobados (32 en el pack) migrados; queda F5 texto (plan separado, D9) y el visual píxel en pestaña visible.
> F4b: **Tier B completo (16/16, D6)** — galaxy · eter · hyperspeed · particles · pixel-blast · grid · prismatic · pillar · dither · blinds · balastro · iridiscence · liquid-metal · line-waves · floating-lines · letters. Mismo mecanismo que F4 (port verbatim + registro + chip); custom-pipeline reutilizado por 6 (particles gl.POINTS · dither 2-pases FBO · grid 2-pases+composite · eter fluidos 8-programas/7-FBOs half-float · pixel-blast cadena dither→liquid→noise · hyperspeed instancing+depth-FBO+bloom). **Contrato completado con consumidores reales**: `glContext.dprCap` (dither exige DPR 1 — look chunky del seed; engine toma el mín) · hooks P-5 simétricos `onPointerLeave` (floating-lines/galaxy/eter) y `onPointerUp` (hyperspeed press) · **bug F1 cazado**: el leave del engine recentraba `nx/ny` pero NO `x/y` (el hover de orb jamás decaía). Recortes declarados: gyro+snapBackDelay (grid, plataforma/chrome) · quality por navigator (pillar → high fijo; adaptación por dispositivo = futura opción del engine) · resolutionScale (veil, ya en F4) · mixBlendMode/paused/callbacks onSpeedUp (chrome del host/handle) · presets hyperspeed no exportados. Gates: packs:check 0/36 · engine 9/9 · scene+eidos 323/323 · check 0 propios · docs:check 0/0 · **navegador: 32/32 efectos montan+compilan+linkan** (prueba estructural canvas+data-scene; la escena interna de hyperspeed compila en su primer frame — cubierta por el pendiente visual).
> F4: **Tier A completo (13/13, D6)** — agénticos primero (silk · radar · threads · orb · waves · lumen) y después fog · grainient · veil · dots · beam · ray · snow-pixels. Cada efecto: port limpio a `$scene/effects/{name}.ts` (shader/física verbatim; `iTime`/`iResolution`→`uTime`/`uResolution` estándar; colores `[0,1]`→hex por P-4; booleans de interacción colapsados en hooks opt-in / `mouseInfluence:0`; `reduce: 'static-frame'` los 13) + módulo de registro en el pack + chip en el catálogo. Adaptaciones de ciudadanía declaradas: waves/dots pierden overlays de chrome del seed (cursor-dot / SVG-glow→dibujado en canvas) · dots cambia `setInterval(20ms)`→acumulador sobre `api.time` (P-3) · veil pierde `resolutionScale` (el buffer es del driver; si hace falta, opción de engine) · orb deriva el hover del puntero suavizado del engine (decae al salir sin hook de leave). **Extensión de contrato justificada por beam** (geometría 3D real, primera del tier): `WebglSceneEffect.vertexShader?()` + `glContext.depth?` + `draw?()` — el driver conserva contexto/loop/resize/uniforms/teardown y solo cede geometría+draw; Tier B (particles/hyperspeed/galaxy) la reutilizará. Fix F3 arrastrado: `eidos.getMode()` NO existía en `ActiveEidos` (error de check) → `getThemeContext()` (vía pública reactiva). Gates: `packs:check` 0/20 · engine 9/9 · check 0 errores en scene/packs · **verificado en navegador: los 16 efectos (3 pilotos + 13 Tier A) montan/compilan/linkan y el remount en cascada no deja errores** (canvas presente + `data-scene` correcto; un fallo de build habría hecho `canvas.remove()`) · README del pack lista el catálogo completo (cierre D6). El look visual píxel-a-píxel sigue pendiente de pestaña visible (limitación de entorno documentada).
> F3: `src/packs/ambient` (`<Ambient effect>` genérico con registro declaration-merging `AmbientEffects` · `resolve-params.ts` P-4 token→hex con drop-a-default · un engine por superficie DOM vía WeakMap para presupuesto global · re-tintado enganchado a `eidos.getMode()`) · módulos `effects/{mesh,aurora,dot-grid}` (import = opt-in) · README con el contrato P · `scripts/packs-check.ts` + npm `packs:check` (P-3 APIs crudas · S-1 sin `<style>` · R-1 registro+augment) **0/7 verde** · alias `$packs` (vite+svelte+CLAUDE.md) · demo catálogo `web/routes/uix/packs/ambient` · encapsulación probada (0 imports de `$packs` fuera de web/). Verificado en navegador: SSR+hidratación limpias, host/canvas/attrs correctos; **bug real cazado en la pasada**: prop `effect` + rune `$effect` = store_invalid_shape (renombrado local `effectName`). El PINTADO no fue verificable (pane oculto suspende rAF/RO — limitación de entorno documentada; la ruta RO→draw la cubren los 9 tests del engine): **pendiente un vistazo visual en pestaña visible al retomar F4**.
> F2: `resolveToken` extendido a slots semánticos `--color-{role}-{slot}` (parser con union `slot`, `getEidosColorRoleSlotOverride` en config.ts, `DEFAULT_COLOR_ROLE_SLOT_STEPS` exportado — misma fuente que el CSS emitido; EXCLUIDOS `contrast` (pick APCA) y familia `surface` (translúcida); 20/20 tests, incl. equivalencia slot↔primitive y override por rol) · 3 pilotos limpios en `$scene/effects` (mesh webgl1 · aurora webgl2 · dot-grid canvas2d + util color local; colores = hex concretos, la resolución de tokens es del CONSUMIDOR por P-4 — la capa arts no importa uix) · re-resolución al cambiar modo: `getMode()` confirmado; el cableado reactivo fino va con el componente del pack (F3).
> F0: motion-guide §8 revertido · `docs/architecture/packs.md` (tier + regla + contrato P + vía Aura) · fila E1 en README + glosario · docs:check 0 err.
> F1: `src/arts/scene/` (types con puerto `SceneDom` + contrato `SceneEffect` con `reduce` obligatoria · engine con pausa-fuera-de-vista/DPR/presupuesto/context-loss · drivers webgl(+2)/canvas2d · README) · alias `$scene` (vite+svelte+CLAUDE.md) · fila en arts/README · **9/9 tests verdes · check 0 errores en scene · arts:check 0/0 en 23 arts**.
> **Origen**: estudio de `web/routes/demos/animations` (45 efectos: 39 fondos + 6 texto,
> ~16.100 líneas, auto-contenidos) + decisión de arquitectura conversada:
> **canon = superficie de contrato · pack = hoja decorativa**; el indicador de
> agente (futuro `Aura`) SÍ es canon (materializa `delegate`+`sustain`), las
> landings son pack. Este plan prepara la fase de dirección agéntica sin
> construirla.
---
## Reglas de gobierno de este plan (cumplimiento total)
Las cinco del usuario (2026-07-11), literales:
1. **NO INVENTES.**
2. **Ante duda o falta de datos, re-analiza el problema desde todos los ángulos.**
3. **Toda pregunta al usuario llega con todas las opciones analizadas en profundidad.**
4. **Ninguna decisión que viole o cree inconsistencia en el ecosistema.**
5. **Buscar siempre la solución que suponga un upgrade del ecosistema respetando su filosofía.**
Y las del propio ecosistema que aplican aquí:
- **Docs-first**: una decisión que contradiga doctrina vigente actualiza el doc canónico ANTES del código (aplica a motion-guide §8).
- **Guard con cada sistema nuevo**: el contrato de pack nace con guard mecánico el día uno.
- **Nunca borrar sin instrucción explícita** ("borra/elimina"): los borrados de F0 quedan gateados en D5.
- **Verificación por fase**: cada fase declara su criterio verify y no se cierra sin él.
- **Pista independiente**: este plan NO se entrelaza con la cola clean-room-fixes (F1+ de `continue-cleanroom-fixes-2026-07.md`); prioridad relativa la decide el usuario.
---
## Datos verificados que anclan el plan (no inventados)
| Dato | Evidencia |
| --- | --- |
| 45 efectos auto-contenidos (0 imports externos; solo `svelte` + relativos) | grep de imports 2026-07-11 |
| Sustratos: 11 WebGL2 · 16 WebGL1 standalone · 8 sobre base `WebGLBackground` · 4 canvas-2D (dot-grid, dots, letters, waves) · 6 texto DOM/CSS/WAAPI | grep `getContext` por fichero |
| Ciudadanía: reduced-motion **9/45** · pausa-fuera-de-vista 26/45 · context-loss **0/45** · APIs crudas (rAF/RO/IO/matchMedia) 45/45 | censo grep 2026-07-11 |
| Las 4 copias de la base (fog≡glass-blocks≡glass-window≡liquid-image≡mesh; nebula/plasma/lumen divergidas) comparten **firma idéntica** (`fragmentShader/setupUniforms/updateUniforms(t,dt)/onPointerMove/loc/uploadTexture`, mismas líneas 158–186) → consolidación de bajo riesgo | diff + grep de firmas |
| Contrato por-efecto embrionario ya existe | `background/mesh/Mesh.ts` (params tipados + 3 métodos) |
| El mejor ciudadano actual (patrón a heredar) | `aurora.svelte`: reduce (frame estático), IO-pause, RO, DPR cap 2, teardown con `loseContext` |
| `ActiveDom` ya expone todo lo que el motor necesita: `requestFrame/cancelFrame`, `observeResize`, `observeIntersection`, `prefersReducedMotion`, `listen` | superficie confirmada (stub `disabledDom` en `active-uix.svelte.ts:242-329` refleja la interfaz) |
| ⚠️ `eidos.resolveToken` HOY solo resuelve `--scale-{n}-{step}` y `--primitive-{role}-{step}`; **devuelve `null` para slots semánticos** (`--color-primary-solid`) | `active-eidos.svelte.ts:485-517` |
| Alias: const único `aliases` en `vite.config.ts:11` (espejado a svelte.config.js); `$scene` libre | grep |
| Precedente de factory: `service-factories/motion.ts` (`defineEngineMotion`) | ls |
| `ogl` en `package.json:60` con **0 imports** en src+web | auditoría 2026-07-10 |
| Restos: `bends copy.svelte` + 4 `test-*.html` | inventario |
| Doctrina a revertir conscientemente: motion-guide §8 declara los fondos WebGL **no-goal** ("a separate axis") | `docs/theming/motion-guide.md` §8 |
---
## Decisiones de usuario (gate de F0) — cada una con recomendación analizada
| ID | Decisión | Opciones analizadas | Recomendación |
| --- | --- | --- | --- |
| **D1** | Nombre del art del motor | `scene` (genérico, sirve a fondos/agente/charts futuros) · `scenic` · `ambient` (se confunde con el pack) | **`arts/scene`**, `EngineScene`/`createEngineScene`, alias `$scene` — espejo exacto del precedente motion |
| **D2** | Ubicación del tier pack | (a) `src/packs/ambient/` (estrato nuevo, sobre uix, documentado) · (b) `src/uix/packs/` (dentro de uix — mancha la pureza de capas: el pack consume uix, no es capa) · (c) dentro de web (no es site-code) | **(a) `src/packs/`** + fila nueva en el mapa de estratos (`docs/README.md`) y en `authoring.md` |
| **D3** | Nombres de componentes | Pack: `<Ambient effect="…">`. Futuro canónico: `Aura` (evita colisión con la capa soma `Presence`) | **Ambient / Aura** — Aura queda solo como nombre RESERVADO documentado; no se construye en este plan |
| **D4** | Acceso al motor | (a) `uix.scene` ya (toca superficie ActiveUix + contracts.ts + docs — invasivo antes de tener consumidor canónico) · (b) factory standalone ahora, promoción a `uix.scene` cuando llegue Aura | **(b)** — mínima invasión = coherencia; la promoción queda declarada en la vía Aura |
| **D5** | Borrados F0 (requieren tu "borra" explícito) | `bends copy.svelte` · 4 `test-*.html` · dep `ogl` de package.json | **Borrar los 3 grupos** (la dep muerta contradice zero-dependence; los restos contaminan greps) |
| **D6** | Alcance Tier A del pack v1 (tras pilotos) | Lista propuesta (sobrios/marca/agénticos): silk · fog · grainient · veil · threads · waves · dots · beam · ray · snow-pixels · radar · orb · lumen | Aprobar lista o recortarla; Tier B (galaxy, hyperspeed, eter, pixel-blast, grid, particles, pillar, prismatic, balastro, blinds, dither, floating-lines, iridiscence, line-waves, liquid-metal, letters) queda para F4b sin fecha |
| **D7** | Destino de `web/routes/demos/animations` | (a) conservar hasta paridad del pack y decidir entonces · (b) migrar la ruta a catálogo del pack ya | **(a)** — nada se borra; la demo nueva del pack nace aparte y la vieja se retira cuando tú lo digas |
| **D8** | Efectos de imagen (distorsion, liquid-image, glass-blocks, glass-window) | Son tratamientos de imagen (reciben `src`), no fondos | **FUERA de este plan** — familia futura de efectos de `Image`, decisión aparte |
| **D9** | Los 6 de texto | (a) fase F5 de este plan · (b) plan separado | **(b) plan separado** — destinos heterogéneos (count→compone `format`; blur→dominio content de motion; gradient→eidos CSS+tokens; circular/focus/scrambled→eidos decorativos con endurecimiento SR). Mezclarlos aquí infla el alcance |
---
## Resoluciones del usuario (2026-07-12)
- **D1–D4 — ACEPTADAS las cuatro** (`arts/scene` · `src/packs/ambient` · `Ambient`/`Aura` · factory standalone). Aclaración pedida y respondida: **las animaciones de texto NO entran al pack Ambient** — el pack es solo fondos decorativos (`aria-hidden`, sin contenido); las de texto envuelven contenido real (superficie a11y = superficie de contrato) y van a su plan separado (D9).
- **D5 — CAMBIADA: NO se borra nada.** Literal del usuario: *"debes de crearlos sano, lo que hay no debe de contaminar lo nuevo, de hecho se queda a modo presencial y comparativo, nada más"*. Consecuencias: la colección original (`web/routes/demos/animations`, incl. `bends copy` y `test-*.html`) queda intacta como **referencia presencial/comparativa**; la dependencia `ogl` también se queda por ahora; lo nuevo se construye LIMPIO en `arts/scene` + `src/packs/ambient` sin heredar los patrones contaminados (APIs crudas, base duplicada, hex sueltos). El punto F0.4 (higiene) queda **anulado**.
- **D6 — Tier A APROBADA** tal cual (13 efectos; agénticos primero).
- **D7–D9 — CONFIRMADOS** (demos intactas hasta paridad · imagen fuera · texto en plan separado).
## Fases
### F0 — Doctrina + higiene (gate: D1–D9 respondidas)
1. **Revertir el no-goal**: editar `docs/theming/motion-guide.md` §8 — los fondos ambient dejan de ser no-goal y pasan a "pack Ambient sobre `arts/scene`" (docs-first).
2. **Escribir el tier pack** donde corresponde: fila "packs" en la tabla de estratos de `docs/README.md` + `docs/authoring.md`; la regla de admisión queda escrita: *canon = superficie de contrato consumida por otros (eventos/ARIA/comportamiento/tokens); pack = hoja decorativa parametrizada; dependencia SOLO pack→framework; borrar el pack no rompe nada*.
3. **Declarar la vía de promoción agéntica** (una sección en el mismo doc del tier): los efectos son recursos compartidos en `$scene/effects`; el consumo semántico llegará con la familia `delegate`+`sustain` (componente reservado `Aura`); mapeo orientativo estados→efectos (idle: mesh/fog/grainient · listening: orb/lumen · thinking: aurora/silk · acting/streaming: threads/waves · searching: radar · error puntual: ray como firma de evento).
4. ~~Higiene~~ — **ANULADO por D5 (2026-07-12)**: nada se borra; la colección original queda como referencia presencial/comparativa y `ogl` permanece en package.json. El mandato es construir lo nuevo limpio, no sanear lo viejo.
- **Verify**: docs editados enlazan y `npm run docs:check` sin errores nuevos; `npm run check` intacto; `git status` solo con lo previsto.
- **No se hace**: ningún código del motor; ningún borrado sin D5.
### F1 — `arts/scene` (el motor)
1. Crear `src/arts/scene/` con:
- `types.ts` — puerto estructural **`SceneDom`** (subconjunto: `requestFrame/cancelFrame`, `observeResize`, `observeIntersection`, `prefersReducedMotion`, `listen`; `adom` lo satisface — mismo patrón `MotionDom`) + contrato **`SceneEffect`** derivado del de `Mesh.ts` y del patrón aurora: `{ name, driver: 'webgl' | 'webgl2' | 'canvas2d', params tipados, reduce: 'static-frame' | 'hide' (OBLIGATORIA, sin default silencioso), pointer?: opt-in }`; para webgl: `fragmentShader/setupUniforms/updateUniforms(t,dt)`; para canvas2d: `setup/draw(t,dt)`.
- `engine-scene.ts` — `createEngineScene({ dom, logger? })`: `mount(node, effect, params) → SceneHandle { setParams, pause, resume, dispose }`. Responsabilidades únicas: bucle en `dom.requestFrame` con delta capado; pausa por `observeIntersection` + pestaña oculta; resize por `observeResize` + DPR cap configurable (default 2); **reduced-motion** vía `dom.prefersReducedMotion` aplicando la policy del efecto (frame estático = dibujar 1 vez, como aurora); **`webglcontextlost/restored`** (0/45 lo manejan hoy — upgrade real); presupuesto de escenas concurrentes con `logger.warn` al superarlo (los navegadores capan contextos GL); teardown completo (programa, buffers, observers, `loseContext`).
- `drivers/webgl.ts` — consolidación de la base: partir de la copia idéntica ×5 (`fog/WebGLBackground.ts`), **diff completo contra nebula/plasma/lumen** para incorporar lo que sus variantes corrigieron (firmas idénticas ya verificadas; la divergencia es interna) + el patrón WebGL2 de aurora como capacidad del driver (el efecto declara `driver`).
- `drivers/canvas2d.ts` — extraído de dot-grid/dots/letters/waves (mismo ciclo de vida, sin GL).
- `index.ts` barrel + `README.md` (contrato, policy reduce, presupuesto, la vía Aura).
2. Alias `$scene` en el const de `vite.config.ts:11` + espejo en `svelte.config.js`.
3. Fila en el mapa de `src/arts/README.md`.
4. Tests (proyecto server): ciclo de vida con dom fake (mount→pause por IO→resume→dispose), policy reduce, context-loss, presupuesto.
5. NO se crea `defineEngineScene` en service-factories todavía (D4b) — se anota en el README como parte de la promoción Aura.
- **Verify**: `npm run check` 0 nuevos + `npx vitest run src/arts/scene` verde + `npm run arts:check` verde. Ningún efecto portado aún.
### F2 — Recursos piloto + costura de tokens
1. **Extender `eidos.resolveToken` a slots semánticos** (`--color-{role}-{slot}`): resolver rol+slot→step vía la misma fuente que el generador (`DEFAULT_COLOR_ROLE_SLOT_STEPS`, `render-css.ts`) respetando overrides de `applyColorScheme` (precedencia ya implementada para primitives). Es un upgrade coherente con su diseño (config + `$color`, cero DOM) y cierra la limitación verificada. Test en `active-eidos.test.ts`.
2. **Helper de color del motor**: los `params` de color aceptan `token CSS custom-property | color CSS crudo`; resolución vía `eidos.resolveToken` cuando hay contexto eidos, passthrough si no (el pack funciona sin eidos, degradando a hex — encapsulación real).
3. **Re-resolución al cambiar modo/tema**: verificar la superficie reactiva de `ActiveEidos` (el mecanismo con que `applyColorScheme` "sigue light/dark") y engancharse al MISMO; si no hay superficie pública, exponerla como parte de este trabajo (decisión técnica documentada en el momento, no inventada ahora).
4. **Portar los 3 pilotos** que cubren los 3 sustratos, a `src/arts/scene/effects/`: `mesh` (webgl base, params ya tipados), `aurora` (webgl2, hereda su propia ciudadanía), `dot-grid` (canvas2d interactivo con pointer opt-in). Colores por defecto derivados de roles del tema (mesh: primary/secondary/tertiary/neutral).
- **Verify**: test de resolveToken semántico; los 3 efectos montan/desmontan en un harness de test; reduce policy ejercitada; `npm run check` + suite eidos verdes (306/306 — el canario THM-3 ya volteado según memoria F0 clean-room).
### F3 — Pack `Ambient` v1
1. `src/packs/ambient/` (D2): componente de montaje **`<Ambient effect="…" params={…}>`** — registro tipado por declaration-merging (`interface AmbientEffects`, patrón exacto `EidosMotionPresets`), tree-shaking por import de efecto; canvas `aria-hidden="true"`; `pointer-events: none` salvo efectos pointer opt-in; sin `<style>` scoped — clase/estilo passthrough estándar.
2. Instancia el motor con el dom del contexto (`ActiveEidos.require().dom` cuando existe; puerto explícito por prop para uso fuera del árbol uix).
3. **Contrato P de una página** (README del pack): reduce obligatoria · teardown por handle · DOM solo por puerto · colores token-aware · `aria-hidden` · presupuesto. **Mini-guard** `scripts/packs-check.ts` (+ npm script `packs:check`): efecto registrado sin `reduce` = error; grep de rAF/RO/IO crudos en `src/packs/` = error.
4. Demo catálogo única (una ruta nueva bajo `web/routes`, selector de efecto + params en vivo + toggle reduce/modo) — las demos viejas intactas (D7a).
- **Verify**: `packs:check` verde; demo carga los 3 pilotos; cambio de modo re-tinta un efecto token-aware en vivo (verificación en navegador); borrar `src/packs/` deja `npm run check` verde (prueba de encapsulación — en working tree, sin commitear).
### F4 — Migración Tier A (D6)
Por cada efecto aprobado: extraer shader/lógica al contrato `SceneEffect` (queda ~⅓ del fichero original), declarar `reduce`, params color token-aware donde tenga sentido, registrar en `AmbientEffects`, añadir al catálogo demo. Orden sugerido: los agénticos primero (orb, lumen, radar, silk, threads, waves) — son los recursos que la fase Aura consumirá.
- **Verify por efecto**: monta/pausa/reduce/teardown en el catálogo + `packs:check` verde. Cierre de fase: Tier A completo listado en el README del pack.
### F4b — Tier B (sin fecha, mismo mecanismo). F5 — texto (plan separado, D9).
### F6 — Cierre
1. Actualizar memoria de proyecto + `docs/process/` con el estado real.
2. Verificación global: `npm run check` · `npx vitest run src/arts/scene src/uix/eidos` · `packs:check` · `docs:check`.
3. Dejar escrito el arranque de la fase agéntica: `Aura` = componente canónico por la ruta de 9 fases, morfo con estados de ciclo de agente + eventos `delegate`/`sustain` + intent, pack sema con modulación por intent (velocidad/amplitud/hue = el análogo visual de pitch/gain/contour), consumo de `$scene/effects`, promoción del motor a `uix.scene` (D4). **Nada de esto se construye en este plan.**
---
## Qué NO hace este plan (anti-scope-creep)
- No construye `Aura` ni toca sema/morfo/soma.
- No toca la cola clean-room-fixes ni la matriz de componentes (el pack no entra en `component:audit`).
- No borra las demos actuales ni ningún fichero sin D5/D7.
- No añade `uix.scene` a ActiveUix (D4).
- No porta efectos de imagen (D8) ni texto (D9).

Powered by TurnKey Linux.