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/src/uix
dev b096237d3e
soma/dialog: dismissWith(action) public API + tinted demo section
5 months ago
..
adom adom + sema: dom.apply + semantic.emit contract skeleton 6 months ago
air morfo: cross-layer contract + 14 new WAI-ARIA components + Dialog wired 6 months ago
eidos eidos/dialog: add [data-dialog-trigger] envelope (button-style) 5 months ago
lib adom + lib/dom: foundation for morfo runtime 6 months ago
morfo sema + morfo: per-event hold override (declarative in morfo) 5 months ago
sema sema + morfo: per-event hold override (declarative in morfo) 5 months ago
soma soma/dialog: dismissWith(action) public API + tinted demo section 5 months ago
terra soma: tier 1/2 components, Field/NumberField integration, codex_audit fixes 6 months ago
CONTINUITY_2026-04-24.md Refactor sema and add shared dom runtime 6 months ago
README.md docs: align cross-layer docs with channel-based Sema 5 months ago
active_architecture.md docs: align cross-layer docs with channel-based Sema 5 months ago

README.md

UIX

Documento corto de posicionamiento arquitectonico para src/uix.

Vision de conjunto: para entender las cuatro capas (morfo, soma, sema, eidos) en una sola lectura, motivaciones y articulación incluidas, ir a src/uix/active_architecture.md. Este README mantiene la introducción más narrativa.

Nota de continuidad más reciente: src/uix/CONTINUITY_2026-04-24.md

UIX no intenta ser "otra libreria de componentes". La apuesta es mas ambiciosa y mas estructural: separar capas que casi todos los frameworks actuales mantienen mezcladas.

En la mayoria de sistemas de UI, estas cosas viven pegadas:

  • contrato publico del DOM
  • comportamiento headless
  • accesibilidad
  • semantica del evento
  • capa visual
  • motores modales (sound, vibra, motion)
  • integracion con servicios de app

UIX intenta partir ese bloque en piezas con fronteras fuertes.


1. La idea central

UIX modela la interfaz como varias capas cooperando, no como un unico componente gigante que hace todo a la vez.

App
├─ servicios transversales
│  └─ ADom
└─ componentes
   └─ capa estructural / semantica / comportamental / visual

La intuicion es esta:

  • la estructura publica del componente no es lo mismo que su comportamiento
  • la semantica de un evento no es lo mismo que su materializacion
  • el DOM activo no es lo mismo que utilidades DOM puras
  • la app no deberia acoplar motores modales entre si

UIX pone nombres y contratos explicitos a esas separaciones.


2. Las capas de UIX

Morfo

Contrato estructural cross-layer del componente.

Define:

  • partes
  • data-*
  • ARIA
  • foco
  • teclado
  • eventos

No es prose ni runtime. Es la forma canonica publica del componente.

Ver: src/uix/morfo/README.md

Sema

Vocabulario semantico y canalizador de senales perceptivas.

Su trabajo:

  • definir las familias canonicas (contact | commit | alert | handle | emerge | sustain)
  • definir los intents canonicos (neutral | affirm | fulfill | risk | threat)
  • exponer SemanticEngine.emit(signal) para que el provider publique ocurrencias
  • mantener un registry de canales perceptivos (VisualChannel, SoundChannel, VibraChannel, ...) y despachar la senal a cada uno
  • semantica secuencial estricta: el VisualChannel (built-in) materializa la senal data-event* en el DOM, la mantiene durante el hold configurado y la limpia ANTES de que la Promise resuelva

Sema no decide que ocurrio (eso lo decide el provider). Solo orquesta la ocurrencia que recibe y la despacha a los canales registrados.

Ver: src/uix/sema/README.md

Soma

Capa headless de comportamiento.

Gestiona:

  • estado
  • contexto
  • a11y
  • keyboard / pointer / focus
  • emision de eventos hacia ADom

Soma no deberia conocer la implementacion concreta de los engines modales. Su trabajo es emitir hechos del componente, no materializarlos.

Ver: src/uix/soma/SOMA_ARCHITECTURE.md

Eidos

Capa visual.

Reacciona a contratos DOM y a senales reflejadas, pero no implementa la logica headless del componente. Su responsabilidad es apariencia, no comportamiento.

ADom

Runtime DOM activo de aplicacion.

No es semantic engine. No conoce Morfo, ni Sema, ni Soma, ni Eidos. Su unica funcion es coordinar y sincronizar mutaciones DOM.

API publica (mutaciones):

  • app.dom.apply(change) — aplica un paquete de attrs sobre un target
  • app.dom.remove(target, names) — quita attrs

API publica (servicios reactivos pre-existentes):

  • viewport, breakpoints, currentBreakpoint, resolve, isAtLeast, matches
  • BodyScrollLock, DOMContext, RovingFocusGroup

ADom recibe instrucciones ya resueltas. No las interpreta.

Ver: src/uix/adom/README.md

uix/lib/dom

Utilidades DOM puras o casi puras.

Aqui viven:

  • contains
  • getDocument
  • getWindow
  • foco
  • traversal
  • wrappers base de observers

No contiene el runtime activo. Ese papel pertenece a ADom.


2.bis Como se ejecuta un componente

La arquitectura cerrada (post-2026-04-25) define seis piezas con responsabilidades disjuntas. Ninguna invade a la siguiente.

Morfo          declara
MorfoRuntime   transcribe
Provider       aporta sources, targets y handlers
Effects        sincronizan attrs derivados
SemanticEngine despacha senales a canales perceptivos
VisualChannel  materializa la senal en el DOM (data-event*, hold, cleanup)
ADom           aplica mutaciones DOM (commit estructural)

El reparto operativo

Morfo es DNA: un fichero por componente que declara parts, data-*, aria-*, role, keyboard, focus, events. No ejecuta nada.

MorfoRuntime (en soma/) interpreta el morfo. Una instancia por componente recibe del provider las fuentes de estado, los targets DOM y los handlers de eventos. Expone:

  • partProps(part) — devuelve solo identidad estatica del nodo (id, marker, ref attachment). Nada mutable.
  • attachPart(part, target) — el provider registra el nodo DOM real cuando monta.
  • keydown(part, event) — dispatch de teclas declaradas en morfo.keyboard.
  • trigger(eventName) — orquesta la secuencia perceptiva + state.

Provider aporta lo que el morfo no puede inferir:

  • getters reactivos para states y props
  • getters reactivos para los parts (ids dinamicos)
  • handlers sincronos para los events
  • glue de layers ortogonales (Presence, Dismissal, ScrollLock — no son morfo)

Effects (registrados por el runtime al montar) escuchan cambios en los sources y aplican los attrs derivados via dom.apply.

SemanticEngine recibe la ocurrencia desde runtime.trigger. Genera el id, despacha la senal a TODOS los canales registrados. El VisualChannel (built-in) escribe la senal data-event* en el DOM directamente, mantiene los attrs durante el hold configurado, los limpia y solo entonces resuelve la Promise (semantica secuencial estricta). Los canales no-visuales (sound, vibra) son fire-and-forget.

ADom solo aplica el commit estructural posterior. No interpreta. Sema y ADom son capas hermanas: el engine ya no depende de ADom.

La secuencia de runtime.trigger(eventName)

1. prewrite imperativo (transient markers como data-last-action)
2. await semantic.emit(event)
3. handler sincrono del provider muta state
4. effects derivan y aplican attrs estructurales (data-state, aria-*)

El handler muta state. Los effects ven el cambio y reescriben el DOM. ADom es el unico escritor de attrs mutables.

Tres escenarios de Soma

// Cambio estructural sin senal
provider.commitState(change)
// internamente: dom.apply(change)

// Cambio estructural con senal
provider.commitState(change, event)
// internamente: await semantic.emit(event); dom.apply(change)

// Senal sin cambio estructural
provider.emitEvent(event)
// internamente: void semantic.emit(event)

Reglas operativas

  • Lo que dom.apply escribe, Svelte no lo renderiza. partProps solo emite identidad estatica (id, marker, ref).
  • Los handlers de events son sincronos. Async va fuera del trigger.
  • Los guards (if (disabled) return) van en el call-site, no dentro del handler — si entran al handler, ya emitieron senal perceptiva.
  • Semantic puede usar Dom (dependencia hacia abajo). Dom no conoce Semantic.
  • morfo.events.commits es descriptivo: documenta lo observable, no lo ejecuta. La cadena causal real es handler -> state -> effect.

3. Que hace distinto a UIX

3.1 El contrato estructural es una capa propia

En la mayoria de librerias, la estructura publica del componente esta dispersa:

  • atributos en el provider
  • roles en el render
  • partes en CSS
  • selector names en docs
  • contratos en tests

UIX intenta concentrar eso en Morfo.

Eso no es una comodidad menor; cambia el tipo de sistema que puedes construir:

  • docs derivadas del contrato
  • validacion cross-layer
  • menos drift entre headless y visual
  • tooling mas fiable

3.2 La semantica no se mezcla con la ejecucion

UIX separa el nombre de la ocurrencia de su materializacion modal.

Eso permite que:

  • sonido
  • vibracion
  • CSS
  • motores futuros

usen el mismo vocabulario sin quedar pegados entre si.

3.3 El comportamiento headless no carga con toda la modalidad

Soma no deberia ser un mega-engine que sabe de todo:

  • no sabe reproducir WAVs
  • no sabe vibrar
  • no sabe decidir la fisica perceptiva de cada canal

Soma emite. Los engines ejecutan.

3.4 El DOM activo es infraestructura de app, no detalle incidental

Muchos sistemas tratan el DOM como detalle local del componente.

UIX da un paso mas: reconoce que hay hechos transversales del DOM que varios consumidores quieren escuchar, y por eso introduce ADom.

Eso permite:

  • un solo punto de publicacion
  • listeners tipados
  • reflection uniforme en atributos
  • menos MutationObserver duplicados
  • mejor tooling y debug

3.5 La app compone servicios, no "super componentes"

UIX se apoya en un modelo donde la app compone servicios transversales y los componentes los consumen. langs, presentation, logger y ADom viven mejor como servicios de app que como dependencias ocultas dentro de cada componente.


4. Lo que UIX no es

UIX no es:

  • una coleccion plana de componentes visuales
  • un simple wrapper opinionated sobre primitives existentes
  • un design system clasico donde visual, comportamiento y contratos viven juntos
  • un semantic engine centralizado que ejecuta todas las modalidades
  • un EventEmitter global disfrazado de arquitectura

Tampoco busca novedad gratuita.

La originalidad de UIX no esta en inventar nombres exoticos, sino en separar problemas reales que otros sistemas suelen aceptar como un unico bloque.


5. Comparacion honesta con otros enfoques

Frente a headless libraries clasicas

Librerias como Radix, Ariakit o React Aria resuelven muy bien comportamiento y accesibilidad. Pero normalmente no separan:

  • contrato estructural declarativo
  • vocabulario semantico independiente
  • runtime transversal de DOM activo

UIX quiere cubrir ese espacio.

Frente a design systems clasicos

Muchos design systems tienen tokens, componentes y guidelines, pero la frontera entre:

  • estructura
  • comportamiento
  • visualidad
  • semantica

queda difusa.

UIX intenta que cada una tenga una capa reconocible.

Frente a engines modales aislados

Es relativamente comun encontrar sistemas de motion o sound por separado.

Lo raro es tener:

  • headless primitives
  • contrato estructural machine-readable
  • vocabulario comun
  • servicio de DOM activo
  • engines modales desacoplados

trabajando juntos sin colapsar en un runtime monolitico.


6. Por que esto puede ser valioso

Si sale bien, UIX ofrece algo poco comun:

  • mejor explicabilidad arquitectonica
  • menos drift entre capas
  • mas capacidad de validacion automatica
  • mejor testabilidad
  • mas libertad para introducir nuevos engines
  • mas honestidad sobre que pertenece al framework y que pertenece al integrador

Especialmente importante:

la coherencia cross-modal puede tratarse como responsabilidad del integrador, no como una falsa promesa de un runtime centralizado que pretende saberlo todo.

El framework puede proveer:

  • vocabulario
  • contratos
  • transporte
  • puntos de extension

Pero no debe fingir que puede decidir por todas las modalidades de todas las apps.


7. Los riesgos reales

UIX tambien tiene riesgos claros, y conviene decirlos sin adornos.

7.1 Exceso de capas

Si las fronteras no estan clarisimas, el sistema puede sentirse mas complejo de lo que realmente resuelve.

7.2 Nombres sin disciplina

Si Morfo, Sema, Soma, Eidos, ADom no mantienen contratos nitidos, los nombres se convierten en decoracion y no en arquitectura.

7.3 Invasion de responsabilidades

El peligro constante es que una capa intente hacer el trabajo de otra:

  • Sema convirtiendose en runtime
  • Soma convirtiendose en engine modal
  • ADom convirtiendose en semantic engine
  • Eidos acoplandose a detalles incidentales

UIX solo funciona si cada capa acepta sus limites.

7.4 Falta de precedentes

No hay demasiados sistemas con esta composicion exacta. Eso significa mas libertad, pero tambien menos patrones externos que copiar. Hay que inventar con disciplina.


8. Reglas de dependencia

UIX preserva una direccion clara de acoplamiento.

Morfo          -> declara contratos
MorfoRuntime   -> interpreta morfo dentro de Soma
Provider       -> aporta sources, targets, handlers
Effects        -> sincronizan state -> attrs
SemanticEngine -> registry + dispatch de senales a canales
VisualChannel  -> materializa la senal en el DOM (data-event*, hold, cleanup)
ADom           -> aplica mutaciones DOM (commit estructural)
Eidos          -> materializa visualmente leyendo DOM
App            -> compone servicios

Reglas duras:

  • Morfo no conoce Soma, ni codigo de runtime
  • MorfoRuntime lee Morfo y depende de Sema
  • Provider no escribe attrs mutables al DOM directamente; los aporta como sources al runtime
  • SemanticEngine no conoce DOM. Solo registry + dispatch
  • VisualChannel accede al DOM directamente (no via ADom); el commit estructural posterior va por ADom
  • Sema y ADom son capas hermanas: ninguna depende de la otra
  • ADom no conoce Morfo, ni Sema, ni Soma, ni Eidos
  • Eidos consume DOM y data-*, no internals de Soma ni Sema
  • Lo que dom.apply escribe, Svelte no lo renderiza

Regla 2-de-3 para extender Morfo

Una extension a Morfo solo se justifica si al menos dos de las tres capas (soma, sema, eidos) la consumen. Si solo soma se beneficia, el patron es virtual prop en provider — no extender el contrato.

Bajo esa regla:

Extension Soma Sema Eidos En morfo
parts[].archetype ✅ emit ✅ verbs por rol ✅ selectores transversales ✅
events[].semantic ✅ payload ✅ vocabulario ✅ tinta ✅
events[].prewrite ✅ ejecuta ✅ secuencia ✅ tinta exit ✅
firstOf value source ✅ only — — ❌
prop-not-nullish cond ✅ only — — ❌
Field-context OR — virtual prop — — ❌

Vocabularios canonicos cross-layer

  • Archetypes (24): clasificacion de partes cross-component. Definida en src/uix/morfo/types.ts:ARCHETYPE_VOCABULARY. Emitida como data-archetype="..." por runtime.partProps.
  • Verbs (24): action verbs canonicos para morfo.events[].name. Definida en src/uix/sema/verbs.ts:SEMA_VERBS. Convencion para composite names: {verb}-{variant} (e.g. commit-save, dismiss-outside).

9. La diferencia en una frase

Si hubiera que resumir UIX en una sola idea, seria esta:

Morfo declara, MorfoRuntime transcribe, Provider aporta, Effects sincronizan, Semantic emite, Dom aplica.

Seis piezas, seis responsabilidades, ninguna invade a la siguiente.


10. Orden de lectura sugerido

Para entender el sistema en su estado actual:

  1. src/uix/morfo/README.md — declaracion, archetypes, regla 2-de-3
  2. src/uix/sema/README.md — emit contract, verbs canonicos
  3. src/uix/eidos/README.md — qué consume eidos del DOM (capa por construir)
  4. src/uix/soma/SOMA_ARCHITECTURE.md — runtime que transcribe morfo
  5. src/uix/adom/README.md — dom.apply
  6. src/uix/lib/dom/README.md — primitives DOM puras
  7. src/uix/terra/README.md — capa anterior, dead branch (referencia)
  8. src/uix/air/README.md — capa visual anterior, dead branch (referencia)

La arquitectura final seguira cambiando, pero esta es la idea fundacional que explica por que UIX no se parece demasiado a otros frameworks de UI.

Powered by TurnKey Linux.