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/theming/channels.md

150 lines
7.0 KiB

---
title: The channels as one system — synthesis
type: notes
audience: human + agent
authority: E3 — the capstone tying the per-channel RFCs to the book's thesis
status: current
source: migrated from src/uix/eidos/CHANNELS_SYNTHESIS.md (2026-07-02, docs-book F7.3)
---
# The channels as one system — synthesis ("Diseñando lo que ocurre")
> The **capstone** of the per-channel RFCs. The thesis of the book *Diseñando
> lo que ocurre*: an interaction **is not** color, or movement, or sound — it
> is **one perceptual occurrence spread across N channels**, under the
> **two-moment** model. This ties together [`rfc-color-engine`](../rfcs/rfc-color-engine.md) ·
> [`rfc-typography`](../rfcs/rfc-typography.md) · [`rfc-depth`](../rfcs/rfc-depth.md) ·
> [`rfc-shape`](../rfcs/rfc-shape.md) ·
> [`rfc-structure`](../rfcs/rfc-structure.md). Live demo: **`/temas/orquesta`** (the mixer).
## 1. Two moments, joined by a token: sema emits, eidos reads
An occurrence flows through **two moments**, connected by the **token**:
- **Sema's moment (emission)** — sema evaluates the occurrence and **emits**
it. Sound + haptics it **executes right there** (runtime channels); for the
visual, it **stamps it as tokens** `data-event-*` (family · intent ·
phase). Sema **knows no DOM/CSS**.
- **Eidos's moment (materialization)** — eidos **reads** those tokens
(+ `data-state`) and **materializes** them in CSS (the visual channel). It
is the **sole visual owner**.
The **token is the contract**: sema writes, eidos reads — which is why the
layers decouple (sema DOM-agnostic, eidos free of semantic logic).
Over that producer → consumer axis runs the **temporal** axis (motion F1) —
*which* token:
| Token | Nature | Who writes it | Eidos reads it as |
|---|---|---|---|
| `data-state` | persistent — what the element **is** | soma / morfo | `presets` |
| `data-event-*` | transient — what **occurs** (during the `hold`) | sema (emits) | `signatures` |
`sequence` (`pre` / `coincident` / `post`) orders the two.
## 2. Expression channels (the book) vs sema channels (runtime)
The book has **8 expression channels** (perceptual dimensions). The framework
docs(sema): la doctrina deja de mentir — deriva propia, copias podridas y dos leyes muertas Pasada de saneamiento documental tras los tres commits de sonido, con el informe de AUDIT-sema-2026-08-05 como mapa. Tres clases de defecto. 1) DERIVA QUE YO MISMO DEJE (lo mas urgente) El 05 renombre las claves silenciadoras a `commit.silent` / `emerge.silent` y el 06 las elimine del catalogo — dejando media docena de docs citando claves que ya no existen, y afirmando ademas comportamientos que ya no ocurren: - switch / toggle / toggle-group README: decian «silent-by-default (`commit.silent`)». Hoy es `commit.medium` (gain 0.1) y suenan. Corregidos con el nivel real y su razon (un tercio de una pulsacion de boton). - tooltip README + docblock del pack: decian que el tuning «resta el gain de la familia, asi que neutral emite a 0» y que «threat / fulfill siguen aflorando». Ambas cosas son falsas desde el 06: es `SILENT`, el resolver retira el canal y NADA aflora, porque no queda ganancia que subir. - toggle-group apuntaba a `LIBRO_VARIACIONES_Y_EXTENSIONES.md`, que es un stub movido; ahora apunta a book-deviations. - La nota del renombrado en D.5 decia «hoy es `commit.silent`»: una clave que vivio UN DIA. Marcada como tal, con la lista de las que siguen vivas. 2) COPIAS PODRIDAS — la ley del corpus es enlazar, no copiar, y estas dos entradas la incumplian - D.9 transcribia `SEMA_HOLDS_BY_INTENT` entera y se habia quedado atras: D.12 corrigio DOS valores el 2026-07-06 (`commit.fulfill` noticed→settled, `signal.loss` noticed→brief, ambos contra el texto del libro) y la copia siguio afirmando los viejos un mes. Sustituida por el puntero a holds.ts + el enumerado generado, con la leccion escrita en el sitio. - sema.md transcribia `SEMA_VERBS` y le faltaban DOS verbos vivos: `commit.unselect` y `handle.zoom`. Retirada; queda el puntero a verbs.ts y a vocabularies.md, que si se genera y tiene guard de frescura. 3) LEYES QUE LA PRACTICA YA HABIA DEROGADO, Y NADIE REGISTRO - El contrato `emit` publicaba `Promise<void>`; devuelve `Promise<string>` desde D.9. Corregido, y explicado que ese string es el id de la ocurrencia — el unico asidero para cerrar una senal persistente con `clear`. - channels.md fijaba «3 canales runtime» y D.8 cerraba la puerta a Announce («hoy no»). El `AnnounceChannel` existe desde el 2026-07-04: built-in, opt-in y exportado. channels.md pasa a 4 con la distincion que importa (visual/sound/haptic EXPRESAN; announce SUSTITUYE) y D.8 queda marcada PARCIALMENTE SUPERSEDED. - sema.md prescribia `{ announce: uix.announce }` — y eso NO COMPILA: las dos firmas no casan (bolsa de opciones vs posicional). Ahora ensena el adaptador de una linea que si compila, y declara que ninguna raiz cablea el canal hoy, asi que activarlo cae en el fallback que anade un SEGUNDO par de live regions. El arreglo de codigo queda sin tomar: es decision de diseno. - La cabecera de engine-sound.ts y la fila de arts/README seguian afirmando como MECANISMO que «`prefs.sound` mapea al bus ui», que la auditoria AU-4 ya habia corregido en el README del propio arte: lo garantizado por construccion es el NEGATIVO (ninguna politica de UI escribe el bus content). AMBIGUEDADES QUE NO RESUELVO PORQUE SON TUYAS, pero que dejan de estar escondidas: D.7 prohibe canonizar samples fuera de `signal` y `proof-of-human` los usa en dos eventos `commit`, aplastando la modulacion por intent que esa misma entrada existe para proteger —y el comentario del pack afirma literalmente lo contrario de lo que hace—; y D.8 declara que los packs deben respetar el `activeChannels` de la familia mientras sema.md prescribe lo contrario y el pack de dialog deja dos reglas inertes. Ambas quedan marcadas con su estado real y los dos caminos excluyentes, pendientes de tu firma. VERIFICADO: docs:check 0/616 · sonido + sema 244/244 · cero referencias vivas a las tres claves muertas (las que quedan en book-deviations son historia declarada como tal, y las de cronica no se reescriben) · prettier: los 6 docs con avisos ya estaban sucios en HEAD, no los toco. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
implements them with sema's **runtime channels**, which are **4** — and here
is the key that avoids the classic confusion:
| Sema channel (runtime) | Covers (the book's expression) | Who materializes it |
|---|---|---|
| **visual** (sema projects `data-event-*`) | movement · presence · depth · shape · color | **eidos** — CSS over `data-event-*` + `data-state` |
| **sound** | sound | sema (`chans/sound`) |
| **haptic** | haptics | sema (`chans/haptic`) |
docs(sema): la doctrina deja de mentir — deriva propia, copias podridas y dos leyes muertas Pasada de saneamiento documental tras los tres commits de sonido, con el informe de AUDIT-sema-2026-08-05 como mapa. Tres clases de defecto. 1) DERIVA QUE YO MISMO DEJE (lo mas urgente) El 05 renombre las claves silenciadoras a `commit.silent` / `emerge.silent` y el 06 las elimine del catalogo — dejando media docena de docs citando claves que ya no existen, y afirmando ademas comportamientos que ya no ocurren: - switch / toggle / toggle-group README: decian «silent-by-default (`commit.silent`)». Hoy es `commit.medium` (gain 0.1) y suenan. Corregidos con el nivel real y su razon (un tercio de una pulsacion de boton). - tooltip README + docblock del pack: decian que el tuning «resta el gain de la familia, asi que neutral emite a 0» y que «threat / fulfill siguen aflorando». Ambas cosas son falsas desde el 06: es `SILENT`, el resolver retira el canal y NADA aflora, porque no queda ganancia que subir. - toggle-group apuntaba a `LIBRO_VARIACIONES_Y_EXTENSIONES.md`, que es un stub movido; ahora apunta a book-deviations. - La nota del renombrado en D.5 decia «hoy es `commit.silent`»: una clave que vivio UN DIA. Marcada como tal, con la lista de las que siguen vivas. 2) COPIAS PODRIDAS — la ley del corpus es enlazar, no copiar, y estas dos entradas la incumplian - D.9 transcribia `SEMA_HOLDS_BY_INTENT` entera y se habia quedado atras: D.12 corrigio DOS valores el 2026-07-06 (`commit.fulfill` noticed→settled, `signal.loss` noticed→brief, ambos contra el texto del libro) y la copia siguio afirmando los viejos un mes. Sustituida por el puntero a holds.ts + el enumerado generado, con la leccion escrita en el sitio. - sema.md transcribia `SEMA_VERBS` y le faltaban DOS verbos vivos: `commit.unselect` y `handle.zoom`. Retirada; queda el puntero a verbs.ts y a vocabularies.md, que si se genera y tiene guard de frescura. 3) LEYES QUE LA PRACTICA YA HABIA DEROGADO, Y NADIE REGISTRO - El contrato `emit` publicaba `Promise<void>`; devuelve `Promise<string>` desde D.9. Corregido, y explicado que ese string es el id de la ocurrencia — el unico asidero para cerrar una senal persistente con `clear`. - channels.md fijaba «3 canales runtime» y D.8 cerraba la puerta a Announce («hoy no»). El `AnnounceChannel` existe desde el 2026-07-04: built-in, opt-in y exportado. channels.md pasa a 4 con la distincion que importa (visual/sound/haptic EXPRESAN; announce SUSTITUYE) y D.8 queda marcada PARCIALMENTE SUPERSEDED. - sema.md prescribia `{ announce: uix.announce }` — y eso NO COMPILA: las dos firmas no casan (bolsa de opciones vs posicional). Ahora ensena el adaptador de una linea que si compila, y declara que ninguna raiz cablea el canal hoy, asi que activarlo cae en el fallback que anade un SEGUNDO par de live regions. El arreglo de codigo queda sin tomar: es decision de diseno. - La cabecera de engine-sound.ts y la fila de arts/README seguian afirmando como MECANISMO que «`prefs.sound` mapea al bus ui», que la auditoria AU-4 ya habia corregido en el README del propio arte: lo garantizado por construccion es el NEGATIVO (ninguna politica de UI escribe el bus content). AMBIGUEDADES QUE NO RESUELVO PORQUE SON TUYAS, pero que dejan de estar escondidas: D.7 prohibe canonizar samples fuera de `signal` y `proof-of-human` los usa en dos eventos `commit`, aplastando la modulacion por intent que esa misma entrada existe para proteger —y el comentario del pack afirma literalmente lo contrario de lo que hace—; y D.8 declara que los packs deben respetar el `activeChannels` de la familia mientras sema.md prescribe lo contrario y el pack de dialog deja dos reglas inertes. Ambas quedan marcadas con su estado real y los dos caminos excluyentes, pendientes de tu firma. VERIFICADO: docs:check 0/616 · sonido + sema 244/244 · cero referencias vivas a las tres claves muertas (las que quedan en book-deviations son historia declarada como tal, y las de cronica no se reescriben) · prettier: los 6 docs con avisos ya estaban sucios en HEAD, no los toco. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
| **announce** | — (accessible substitute, not a book channel) | sema (`chans/announce`) |
`announce` joined on 2026-07-04 as a built-in opt-in channel: it is the
accessible counterpart the book demands when a modality is unavailable
(`BK-SIGNAL-A11Y`), not a ninth perceptual dimension. `visual`, `sound` and
`haptic` are the three that express; `announce` is the one that substitutes.
> **Don't get confused**: **motion · depth · shape · color are NOT "eidos
> channels"** — they are sema's **`visual` channel**, which sema projects and
> **eidos materializes**. Eidos is the visual channel's *materializer*, not
> the owner of channels of its own. The eidos RFCs (`COLOR/DEPTH/SHAPE_ENGINE`)
> describe *how* eidos materializes each visual facet — not independent
> channels.
Plus **space** ([`rfc-structure.md`](../rfcs/rfc-structure.md)) — **structural,
not expressive**: it doesn't "occur", it is the stage (state-only).
## 3. The layer chain (each with its role)
An occurrence **crosses the layers** — it is not "all sema", and eidos is not
a shim:
1. **morfo** — **declares** the event and its semantics (family · intent ·
verb). The contract / DNA; pure TypeScript, no runtime.
2. **soma** — **fires** it (`runtime.trigger`): the sequence `prewrite →
sema.emit → handler →` state attrs. It writes `data-state` (the
state-moment).
3. **sema** — **emits** it: dispatches the signal to its channels —
**executes** `sound` + `haptic`; **projects** the visual channel by
stamping `data-event-*`. It knows no DOM/CSS.
4. **eidos** — **materializes** it: reads `data-state` (`presets`) +
`data-event-*` (`signatures`) and renders them with its **token engines**
(color · motion · depth · shape · space — the RFCs). It is the **complete
visual system** and the sole owner of the visual.
> Eidos does **not "make sema visible"**: sema contributes the **what**
> (family / semantic intent), eidos contributes the **how** (the visual
> vocabulary and its materialization). Co-layers, not one subordinate.
(The full canonical narrative lives in `CLAUDE.md` → "Sema: open channel
registry".)
## 4. The composition — one event, N channels
The **signature** (`BUILTIN_SIGNATURES` + `BUILTIN_KEYFRAMES`) is
**cross-modal**: a single keyframe carries several modalities. A real example
(`press-squeeze`, family `contact`):
```
contact · press → scale 0.96 (motion)
+ box-shadow → flat (depth recede)
+ --shape-smoothing 2→3 (shape: the corner firms up)
+ tick (sema sound)
+ vibration (sema haptic)
```
One `engine.emit(...)` stamps `data-event-*` (the **visual** channel reacts —
eidos materializes it as color/motion/depth/shape) **and** fires sound +
haptic — from the **same** event. There are no systems coordinating by hand;
there is one occurrence expressing itself through sema's channels.
## 5. Runtime builders — the sextet (an open cage)
Every axis retunable at runtime, same pattern (seed → managed block), opt-in
over the authored scale:
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO F2 — lote mecánico (13 ítems): - DEP-2 ogl eliminado (0 imports) · DEP-1 clsx inlineado como toClassString propio + suite de contrato (props.test.ts; soma.md §12 cerrado). - THM-7: los 5 selectores manuales de sema.md reescritos con semaSelector (los ejemplos [data-toast-root] apuntaban a un part INEXISTENTE — la deriva que el builder previene, demostrada en el propio doc). - MOR-1 escape isomorfo + validación de attr-names en semaSelector + 9 tests (selectors.test.ts, matches() real con comillas/corchetes) · MOR-2 partMarkerAttr = única fuente compilador↔builder + test de paridad · MOR-3 _resetCompileCache borrado (0 usos). - SOM-2 keydown continue en match sin handler + keyboardFixtureMorfo · SOM-1 no-await de handlers (censo async = 0; contrato V1 cumplido) + pin. - SEM-2 trigger pre-attacha catch con logger (void trigger sin unhandled rejection; throw intacto para awaiters) + pin · SEM-3 fallback muerto de applyDominance → skip defensivo + timer tope de awaitExpression cancelado · SEC-1 adjudicado YA implementado (assertCssVariableValue desde 2026-05-11) + pin del path de VALOR. - accordion → outline (§32; su outline:none dejaba CERO anillo en HCM) — verificado en vivo · THM-6 radius-full 9999px · EID-4 recuentos 33. F3 — censos con guard: - SOM-3 cerrado: announcer + image-provider migrados a scheduler-preferred (consumidores cableados: date/time-field vía soma.uix.timers; avatar/image vía eidos.timers — verificado en vivo); guard de timers ENSANCHADO de soma/components a TODO soma y pasado a EVIDENCIA (setTimeout exige .schedule( en el fichero — layers/ y datetime/ escapaban del ámbito viejo). - THM-5: R-4.7 nueva (válvula same-line /* important: <razón> */, escaneo comment-blanked) + las 15 declaraciones anotadas con su razón + canon recipe-contract §3/§4. - SOM-4 adjudicado: el censo/guard YA existían (49 pins); knob/mask-field/ timeline pinneados (overrides documentados en call-site); media-player Batch-4 (35 hits, cero renderProps) = único batch restante, registrado. - THM-4 doctrinado en eidos.md §unused (comportamiento/composición = legítimo; deuda = eje visual sin consumidor; hotspots por lotes). F4-C — corpus documental (decisiones de usuario aplicadas): - DOC-3: los 15 enlaces muertos resueltos (repoint a la edición FINAL trackeada / des-link históricos) · docs:check I6-links WARN→ERROR. - DOC-1: tabla «Build contract» MIGRADA a component-guide con estados modernizados (A3–A5 → LIVE + guards de hoy); banners reapuntados; citas de CANON/sema.md historificadas; lápida-redirect en el §13 del fósil. - DOC-4: hold chain → holds.ts · FAQ event:* SUPERSEDED por signatures · gradient añadido a los DOS capstones (sextet real) · nota de paleta de demo-authoring corregida (universalPaletteDecls + decisión THM-2 = mecanismo universal como sucesor del tracker borrado). - DOC-5/6: recuentos anti-frágiles datados · §4.11 dup → §4.12 · Known gaps historificado · N-6/N-7 recuperadas de git (d68d2c45^) y canonizadas en eidos.md §pickers · authoring E2 → canon/tsc.md · air-old des-linkado · EID-3 (placement) en la fila RTL · AUX-2 disabledDom documentado. SEM-4 sesión 1 — el close polimórfico de los pickers, VIVO (D.11): - Reconciliación: los morfos ya no declaran close (delegated al Popover, de-dialoged 06-27); el agujero real era el cierre programático bypaseando dismissWith → save/cancel/select eran perceptualmente SILENCIOSOS. - Fix: PickerShellHandle.setPopoverDismiss + closeWith(cause) en los 5 providers (14 sitios; select/commit → 'save' = commit.save+fulfill, cancel → 'cancel' = emerge; fallback raw para headless) + UN inyector en el eidos PickerShell root (norma N-8). Picker genérico fuera a propósito (ya suena commit-set/cancel por diseño S9). - Verificado en vivo (date-picker): Done → close·commit·fulfill·active · Cancel → close·emerge · cierre real. Gates: matriz 141/141 (los 6 morfos nuevos de la pista de texto paralela también PASS) · contracts 38/38 · eidos 314 · sema 178 · morfo 94 · docs:check 0/0 con I6 en error · baseline propio 57. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
`applyColorScheme` · `applyTypeScale` · `applyDepth` · `applyShape` ·
`applySpacing` · `applyGradients`
And the **capstone composing them**: **`applyTheme(seed)`** — a single seed
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO F2 — lote mecánico (13 ítems): - DEP-2 ogl eliminado (0 imports) · DEP-1 clsx inlineado como toClassString propio + suite de contrato (props.test.ts; soma.md §12 cerrado). - THM-7: los 5 selectores manuales de sema.md reescritos con semaSelector (los ejemplos [data-toast-root] apuntaban a un part INEXISTENTE — la deriva que el builder previene, demostrada en el propio doc). - MOR-1 escape isomorfo + validación de attr-names en semaSelector + 9 tests (selectors.test.ts, matches() real con comillas/corchetes) · MOR-2 partMarkerAttr = única fuente compilador↔builder + test de paridad · MOR-3 _resetCompileCache borrado (0 usos). - SOM-2 keydown continue en match sin handler + keyboardFixtureMorfo · SOM-1 no-await de handlers (censo async = 0; contrato V1 cumplido) + pin. - SEM-2 trigger pre-attacha catch con logger (void trigger sin unhandled rejection; throw intacto para awaiters) + pin · SEM-3 fallback muerto de applyDominance → skip defensivo + timer tope de awaitExpression cancelado · SEC-1 adjudicado YA implementado (assertCssVariableValue desde 2026-05-11) + pin del path de VALOR. - accordion → outline (§32; su outline:none dejaba CERO anillo en HCM) — verificado en vivo · THM-6 radius-full 9999px · EID-4 recuentos 33. F3 — censos con guard: - SOM-3 cerrado: announcer + image-provider migrados a scheduler-preferred (consumidores cableados: date/time-field vía soma.uix.timers; avatar/image vía eidos.timers — verificado en vivo); guard de timers ENSANCHADO de soma/components a TODO soma y pasado a EVIDENCIA (setTimeout exige .schedule( en el fichero — layers/ y datetime/ escapaban del ámbito viejo). - THM-5: R-4.7 nueva (válvula same-line /* important: <razón> */, escaneo comment-blanked) + las 15 declaraciones anotadas con su razón + canon recipe-contract §3/§4. - SOM-4 adjudicado: el censo/guard YA existían (49 pins); knob/mask-field/ timeline pinneados (overrides documentados en call-site); media-player Batch-4 (35 hits, cero renderProps) = único batch restante, registrado. - THM-4 doctrinado en eidos.md §unused (comportamiento/composición = legítimo; deuda = eje visual sin consumidor; hotspots por lotes). F4-C — corpus documental (decisiones de usuario aplicadas): - DOC-3: los 15 enlaces muertos resueltos (repoint a la edición FINAL trackeada / des-link históricos) · docs:check I6-links WARN→ERROR. - DOC-1: tabla «Build contract» MIGRADA a component-guide con estados modernizados (A3–A5 → LIVE + guards de hoy); banners reapuntados; citas de CANON/sema.md historificadas; lápida-redirect en el §13 del fósil. - DOC-4: hold chain → holds.ts · FAQ event:* SUPERSEDED por signatures · gradient añadido a los DOS capstones (sextet real) · nota de paleta de demo-authoring corregida (universalPaletteDecls + decisión THM-2 = mecanismo universal como sucesor del tracker borrado). - DOC-5/6: recuentos anti-frágiles datados · §4.11 dup → §4.12 · Known gaps historificado · N-6/N-7 recuperadas de git (d68d2c45^) y canonizadas en eidos.md §pickers · authoring E2 → canon/tsc.md · air-old des-linkado · EID-3 (placement) en la fila RTL · AUX-2 disabledDom documentado. SEM-4 sesión 1 — el close polimórfico de los pickers, VIVO (D.11): - Reconciliación: los morfos ya no declaran close (delegated al Popover, de-dialoged 06-27); el agujero real era el cierre programático bypaseando dismissWith → save/cancel/select eran perceptualmente SILENCIOSOS. - Fix: PickerShellHandle.setPopoverDismiss + closeWith(cause) en los 5 providers (14 sitios; select/commit → 'save' = commit.save+fulfill, cancel → 'cancel' = emerge; fallback raw para headless) + UN inyector en el eidos PickerShell root (norma N-8). Picker genérico fuera a propósito (ya suena commit-set/cancel por diseño S9). - Verificado en vivo (date-picker): Done → close·commit·fulfill·active · Cancel → close·emerge · cierre real. Gates: matriz 141/141 (los 6 morfos nuevos de la pista de texto paralela también PASS) · contracts 38/38 · eidos 314 · sema 178 · morfo 94 · docs:check 0/0 con I6 en error · baseline propio 57. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
(`{ color?, type?, depth?, shape?, space?, gradient? }`) composes the six
axes in **one managed write** (vs six loose `apply*`), **atomically**: the
axes you pass are applied, the ones you omit revert to the authored
foundation. `clearTheme()` reverts everything. For surgical per-axis tweaks,
the individual `apply*` remain. No reference system gathers the six
perceptual axes under a single runtime theme builder.
## 6. Position vs the references
No reference system gathers the channels under **one semantic model**.
Material has shape morph + motion (ad-hoc, without integrated
sound/haptics); Apple, continuity + materials (platform-bound); everyone,
color. **UIX gathers them** — the visual channel (sema → eidos) + sound +
haptic (sema) — over the two-moment model, fired from one event, with
runtime builders and an open registry. That is the framework, not the sum of
its parts.
## 7. Demo
`/temas/orquesta` — the mixer: press a control and mute each facet to hear
its part. The **visual channel's** 4 facets materialize with eidos tokens
(toggleable so each can be muted one by one); **sound + haptic** are fired by
the real sema engine (`EngineSemantic.emit`, filtered channels). One event,
sema's channels.

Powered by TurnKey Linux.