Skip to content

Kroma Modality Model

kroma specs/kroma/modality-model.kmd

O modelo conceitual de UIObject do Kroma — north star da UI da Koder Stack. Uma UI **não** é um conjunto de "elementos por sentido"; é uma **árvore de intenção** que se **projeta** em canais de modalidade conforme o hardware do device. Duas correções fundam o modelo: (1) organiza-se por **papel × modalidade** (não pelos "5 sentidos"), e o papel inclui **entrada** — que o modelo de sentidos omite; (2) uma modalidade de UI é um canal **transdutor** (sinal codificado → percept fiel e reversível), não **atuação no mundo** (assar um bolo não é renderizar um sabor). Visual/áudio/háptico são v1; olfato/gosto são extension point de pesquisa, não alvo. Emergente (S1 do epic kroma#292); vira normativo quando S2/S3 landarem.

When this spec applies

All triggers

Specification body

Spec — Kroma Modality Model

A reformulação central. "Quais grupos de elementos existem numa UI?" tem uma resposta popular — "um por sentido humano" — que é boa como intuição e ruim como engenharia. Uma UI é uma árvore de intenção (o que o usuário quer fazer e o que o sistema quer comunicar); a modalidade — visão, som, tato — é como essa árvore é projetada no device. Separar as duas é o que torna "UI para vários sentidos" alcançável em vez de aspiracional — e é, não por acaso, a mesma doutrina do headless-first (lógica separada de render) e do KDX (significado é a fonte, superfície é projeção).

1. Dois eixos ortogonais (não "5 grupos")

Um UIObject é classificado por dois eixos independentes:

Eixo A — Papel (o organizador primário)

papelo que fazexemplos
containeragrupa/posiciona outros objetosForm, Panel, Card, Column, Row, ToolBar
outputapresenta um percept ao humanoText, Image, Chart, VideoPlayer, (áudio: Tone, Speech)
inputcaptura ação do humanoButton, Edit, Slider, Checkbox, Select
navigationmove entre destinosMenu, TabStrip, back/ESC, link/intent

Correção ao modelo de sentidos: os exemplos de classe do brainstorm (Button, Edit, Slider) são papéis de entrada/interação — organizados por função, não por sentido. O modelo de sentidos só enxerga saída (percepção humana) e não tem lugar para entrada — que é a metade mais difícil de um framework de UI. Papel é o eixo que organiza; sentido/modalidade é atributo do eixo B.

Eixo B — Modalidade (atributo do canal)

Modalidade é por qual canal o papel se realiza. É ortogonal ao papel: um output pode ser visual ou auditivo; um input pode ser ponteiro ou voz.

  • Saída (transdutor): visual · auditivo · hápticov1. olfativo · gustativoextension point (hardware de pesquisa existe; não é alvo de v1).
  • Entrada: ponteiro · toque · teclado · voz · gaze/câmera · caneta.

Háptico não é um canal, são vários: vibrotátil, força (force-feedback) e térmico são atuadores distintos. Um objeto háptico declara o sub-canal; não existe "o" háptico genérico.

2. Modalidade de UI é transdução, não atuação (o limite honesto do modelo)

Uma modalidade de UI é um canal transdutor: o software escreve um valor num canal endereçável e o hardware reproduz o percept de forma fiel e reversível (o pixel acende e apaga; o alto-falante emite e silencia; o motor vibra e para).

Não é modalidade de UI a atuação no mundo físico. O exemplo do brainstorm — um robô que assa um bolo com sabor de limão — é atuação/robótica, não um display que renderiza o percept "limão": não há canal onde taste = lemon seja escrito, reproduzido fielmente e desfeito. Displays olfativos/gustativos de pesquisa são transdutores (por isso olfato/gosto entram como extension point, não ficção); "fazer um bolo" não é. Regra: a superfície de UIObject cobre transdução; atuação no mundo é outro domínio (robótica/IoT), integrado por API, não por widget.

3. Projeção e headless — por que "todos os sentidos" é alcançável

A árvore de UIObject é modalidade-agnóstica. Quem escolhe o canal é o backend de projeção (paint), plugável. O Kroma é assim: retained-mode com árvore reconciliada + backend único (wgpu/Vello) trocável por plataforma. Consequências:

  • Adicionar uma modalidade = adicionar um backend de projeção + semântica de widget, sem tocar a árvore. É por isso que a ambição "UI para vários sentidos" é viável: a arquitetura já separou árvore de pintura.
  • Headless é uma projeção como qualquer outra — a projeção nula/introspecção (src/introspect.rs + semantics.rs). Isso realiza o headless-first por construção: toda UI tem caminho headless porque headless é só mais um backend.
  • Acessibilidade É reprojeção de modalidade. Um leitor de tela reprojeta a árvore visual em áudio; forced-colors reprojeta a cor. Os perfis a11y (piso WCAG 2.2 AA da Stack) são o mesmo mecanismo deste modelo — não um anexo. Toda output visual SHALL carregar a semântica que permite sua reprojeção (rótulo, papel, estado).

4. Layout é fluxo/constraint, não pixel absoluto

Posição/tamanho SHALL ser expressos por fluxo e constraint referenciando tokens (espaçamento, densidade), nunca por left/top/width/height absolutos em px.

Motivo: pixel absoluto contradiz a própria tese multi-device/multi-modalidade — left: 100 não significa nada num relógio, numa TV a 3 m, ou numa output auditiva. O layout absoluto do esboço do brainstorm é o padrão Delphi/VB-forms e está explicitamente vetado na UI go-forward. (A compose DSL já é uma árvore {component, props, children}, não coordenadas — este modelo confirma essa escolha.)

5. Relação com a compose DSL e com eventos

  • A árvore é a compose DSL (src/compose/): Node = {component, props, children}, props com refs de token {$token}. O component carrega o papel; a modalidade é onde/como ele projeta. Widget não-visual = novo component + novo backend de paint; a forma do documento não muda.
  • Eventos despacham intents nomeadas, não destinos concretos (um onclick não aponta para um arquivo/URL). O mapeamento intent→destino é do router (S2 do epic). Isso mantém o objeto testável, reusável e reprojetável entre modalidades (uma intent "abrir cadastro" vale para clique, toque ou comando de voz).

6. Escopo v1, extension points e não-objetivos

  • v1 (construir): visual + auditivo + háptico (vibrotátil primeiro).
  • Extension point (não construir agora): olfativo, gustativo, háptico térmico/força — a superfície os prevê como modalidade de saída, sem prometer API que nenhum device de consumidor entrega. Sobre-abstrair para "todos os sentidos" hoje é pagar custo de abstração por capacidade inexistente.
  • Não-objetivo: atuação no mundo (robótica/IoT) — §2. Integra-se por API, não por UIObject.
  • Governança: este modelo não introduz formato/linguagem novo (language-and-format-creation): é taxonomia sobre a compose DSL + backends do Kroma que já existem. Vira mandatory (com gatilho em spec-triggers.kmd) quando S2/S3 do epic kroma#292 landarem e houver widget não-visual real consumindo o modelo.

References