← Papiers
Lexique AGPL-3.0

XUI — le xer comme renderer

Spec v0 du contrat entre le sens (ploxions) et les surfaces (desktop, montre, ESP32…)

Résumé

Le xerboxion doit tourner N'IMPORTE OÙ : desktop, téléphone, montre, cube à 6 faces, écran rond, OLED 1-bit, LCD caractères, ESP32, STM32. Ça n'est possible que si on sépare ce que le xerboxion EST (bions, ploxions, tsoins — le sens) de comment on le dessine (le xer — un renderer). Ce document gèle le contrat entre les deux : un ploxion décrit son état par priorité, une surface révèle ce que ses capacités permettent, une action passe par le bus — jamais par un callback. Directive RS-7 : « un TYPE d'UI complètement différent, pas un thème ».

J0bot · Août 20...

Ce que ce document gèle

Quatre choses, et rien d'autre :

  1. La séparation être/dessiner : le xerboxion = le sens ; le xer = un renderer d'une SURFACE. Un nouveau facteur de forme = un nouveau renderer, zéro modification des ploxions (§1).
  2. Le vocabulaire des capacités d'une surface : résolution, profondeur, forme, entrée, compute (§2).
  3. Le contrat XUI v0 : la fonction describe() pure d'un ploxion, ses items typés et priorisés 1..5, sa variante compacte XUIC pour micro-écrans (§3).
  4. Deux mécaniques transverses : la révélation progressive (trier par p, couper où la surface s'arrête, §4) et les actions par le bus (un act = un topic jOSPorts, §6).

Ce qui n'est PAS gelé : le layout riche (grilles, mise en page), les images et glyphes sur micro-écran, les kinds au-delà des cinq de base. Ouvert en §7.

§1Être et dessiner

[POSÉ] Le péché originel des UI classiques : l'état vit dans le dessin. Un ploxion qui stocke sa vérité dans son DOM ne peut exister que là où ce DOM existe — il est prisonnier de son écran. La règle Core/UI du repo (l'état-vérité ne vit jamais dans un UI) était déjà la moitié du chemin ; XUI en est la seconde moitié, côté sortie :

  • Le xerboxion, c'est le sens : les bions (capacités), les ploxions (compositions), les tsoins (l'histoire), le bus jOSPorts (les événements). Tout ça existe indépendamment de tout pixel.
  • Le xer, c'est un renderer : un programme qui connaît les capacités d'UNE surface et qui dessine dessus une description abstraite. Le xer desktop dessine en HTML. Le xer montre dessine 12 caractères. Le xer ESP32 pousse des segments sur un OLED. Le xer cube répartit sur 6 faces. Même description, N dessins.

Conséquence structurelle : un ploxion n'a plus « une UI ». Il a un état et une fonction qui le décrit (§3). L'UI web riche existante (les app.blade.php) reste ce qu'elle est — le rendu de luxe de la surface navigateur — mais elle devient UN rendu parmi d'autres, plus LE ploxion. C'est la règle « ploxion = son bion, pas son UI », poussée jusqu'au bout.

§2Les capacités d'une surface

[POSÉ] Une surface se déclare par cinq axes. C'est le profil que le renderer connaît et que le ploxion ignore (le ploxion décrit, il ne s'adapte pas — c'est le renderer qui coupe) :

{
  "resolution": { "w": 128, "h": 64 },
  "profondeur": "1bit",
  "forme": "rect",
  "entree": ["2-boutons"],
  "compute": "micro"
}
  • resolution : pixels utiles (w,h) — ou colonnes×lignes pour un LCD caractères.
  • profondeur : couleur · gris · 1bit. Un renderer 1-bit n'a ni dégradé ni couleur d'état : il rend une gauge en barre pleine/vide, un booléen en glyphe plein/creux.
  • forme : rect · rond (montre, hublot) · bande (ticker, barre LED) · cube-6-faces (ledion : six surfaces rect solidaires — le renderer décide quoi mettre sur quelle face).
  • entree : tactile · molette · d-pad · 2-boutons · voix · aucune. Une surface aucune est un pur afficheur : elle montre, les actions se déclenchent d'ailleurs (§6).
  • compute : navigateur (JS complet, appel direct de describe()) · micro (ESP32/STM32 : pas de JS — il reçoit du XUIC déjà sérialisé, §5).

§3Le contrat XUI v0

[POSÉ] — c'est la clé de voûte, identique pour tous. Un ploxion peut exposer :

window.jOSApps[id].describe = function(){ return XUI; }

où :

XUI  = { v:1, id, title, icon, items:[ ITEM… ] }

ITEM = { p:      <1..5 priorité : 1 = l'essentiel absolu (la montre ne montre que p1),
                  5 = détail desktop>,
         kind:   'stat'|'gauge'|'action'|'list'|'text',
         label:  <string court>,
         value?: <string|number>, unit?: <string>,
         min?/max?: <pour gauge>,
         items?: [{label, value?, act?}]   (pour kind list, max ~7),
         act?:   { port:<topic jOSPorts à émettre>, payload?:{} }
                  (pour kind action — l'exécution passe par le bus, JAMAIS par un
                   callback : un ESP32 doit pouvoir déclencher pareil) }

RÈGLES gelées :

  • describe() est PUR (pas d'effet de bord), rapide (<5 ms), et retourne l'état COURANT — on peut l'appeler à chaque frame ou une fois par minute, même réponse pour le même état.
  • Tout texte court : une montre = ~12 caractères utiles. Le label est un télégramme, pas une phrase.
  • La révélation progressive = trier par p, couper où la surface s'arrête (§4). Pas de logique par-device dans le ploxion.
  • Le registre window.jOSApps existe déjà (resources/views/ploxions/_manifest.blade.php) : describe s'y greffe, on n'invente pas un deuxième annuaire.

Version compacte pour micro-écrans (MQTT/série) — arrays, pas d'objets, parse trivial sur ESP32 :

XUIC = [id, title, [[p,kind,label,value,unit]…]]

Exemple 1 — un ploxion météo :

{ "v": 1, "id": "meteo", "title": "Météo", "icon": "⛅",
  "items": [
    { "p": 1, "kind": "stat",  "label": "Ext",      "value": 21.4, "unit": "°C" },
    { "p": 2, "kind": "stat",  "label": "Humidité", "value": 62,   "unit": "%" },
    { "p": 2, "kind": "gauge", "label": "Pluie 24h", "value": 3, "min": 0, "max": 40, "unit": "mm" },
    { "p": 3, "kind": "list",  "label": "Prévision",
      "items": [ { "label": "Mar", "value": "☀ 24°" },
                 { "label": "Mer", "value": "🌧 17°" },
                 { "label": "Jeu", "value": "⛅ 20°" } ] },
    { "p": 4, "kind": "text",  "label": "Tendance",
      "value": "Front froid vendredi, bise samedi." },
    { "p": 5, "kind": "action", "label": "Rafraîchir",
      "act": { "port": "ploxion.meteo.refresh" } }
  ] }

et son XUIC (ce que reçoit l'OLED — p1-2 seulement, déjà coupé) :

["meteo", "Météo", [
  [1, "stat",  "Ext",       21.4, "°C"],
  [2, "stat",  "Humidité",  62,   "%"],
  [2, "gauge", "Pluie 24h", 3,    "mm"]
]]

Exemple 2 — le ploxion xerbot (les act collent au contrat xerbot v1, resources/data/xerbot-contract.json) :

{ "v": 1, "id": "xerbot", "title": "Xerbot", "icon": "🤖",
  "items": [
    { "p": 1, "kind": "stat",  "label": "Rover",    "value": "en ligne" },
    { "p": 1, "kind": "gauge", "label": "Batterie", "value": 87, "min": 0, "max": 100, "unit": "%" },
    { "p": 2, "kind": "action", "label": "Stop",
      "act": { "port": "ploxion.xerbot.rover-1.cmd",
               "payload": { "cmd": "stop", "src": "xui" } } },
    { "p": 3, "kind": "action", "label": "Avance 10m",
      "act": { "port": "ploxion.xerbot.rover-1.cmd",
               "payload": { "cmd": "avance", "args": { "d": 10 }, "src": "xui" } } },
    { "p": 3, "kind": "stat",  "label": "Cap", "value": 142, "unit": "°" },
    { "p": 4, "kind": "list",  "label": "Flotte",
      "items": [
        { "label": "rover-1", "value": "87%" },
        { "label": "drone-1", "value": "au sol",
          "act": { "port": "ploxion.xerbot.drone-1.cmd",
                   "payload": { "cmd": "takeoff", "args": { "alt": 10 }, "src": "xui" } } } ] },
    { "p": 5, "kind": "text", "label": "Dernier ack", "value": "stop ok 14:02:11" }
  ] }

La montre du xerbot montre donc exactement : Rover en ligne + la barre de batterie. Et son bouton unique déclenche le premier action visible — le Stop. C'est déjà une télécommande d'urgence complète.

§4La révélation progressive

[POSÉ] L'algorithme du renderer, en entier : trier les items par p croissant, dessiner dans l'ordre, s'arrêter quand la surface est pleine. C'est tout. Pas de media queries, pas de breakpoints, pas de version « mobile » du ploxion — une seule description, N coupes.

Surface Capacités typiques Révèle
Montre ~64px rond, 1 molette p1 seulement
OLED 128×64 1-bit, 2 boutons p1–2
E-ink gris, lent, souvent sans entrée p1–3
Téléphone couleur, tactile p1–4
Desktop couleur, clavier/souris tout (p1–5)

Écrire un ploxion XUI, c'est donc répondre à une seule question honnête : « si l'être n'a qu'un coup d'œil, que doit-il voir ? » → c'est le p1. Le reste est de l'enrichissement progressif. Un ploxion dont tous les items sont p1 a raté l'exercice (la montre coupera arbitrairement) ; la bonne pyramide est pointue : 1–2 items p1, le gros du contenu en p3–4.

Cas des formes non-rect : le rond rogne les coins (le renderer centre et raccourcit les labels) ; la bande ne montre qu'un item à la fois et défile dans l'ordre des p ; le cube-6-faces distribue — p1 sur la face avant, la suite sur les autres faces.

§5Le transport

Cadrage RS-7 (13.08) : v0 = tout en web, et le XUI est une affaire de XER — il n'est PAS couplé au bus xerbot. Le xer est le renderer ; le canal qui l'alimente lui appartient.

  • Web (RÉEL, le seul chemin gelé en v0) : le renderer tourne dans la même page que le ploxion → appel direct de window.jOSApps[id].describe(). Zéro sérialisation, zéro latence. Le xer facteur-de-forme (⌚ montre, 📺 tv, 🖲 borne) et le simulateur de surfaces consomment XUI comme ça, aujourd'hui.

  • Micro-écrans (TURFU, non gelé) : quand un xer devra vivre sur une puce (ESP32, STM32, e-ink autonome), le format compact XUIC[id, title, [[p,kind,label,value,unit]…]], arrays plats, un parseur de ~50 lignes suffit — voyagera sur le canal PROPRE de ce xer (MQTT, série, peu importe). Ce canal n'est volontairement pas spécifié ici, et il est DÉCOUPLÉ du contrat xerbot (le xerbot pilote des devices ; le xer dessine des surfaces — deux affaires). Une esquisse de firmware de référence existe hors repo, jamais flashée ; elle attend que RS-7 ouvre le chantier matériel.

  • Rappel kiosk (RÉEL) : un onglet ouvert en plein écran verrouillé (le xer 🖲 borne) est déjà « un écran dédié » — en pur web, sans transport.

§6Les actions par le bus

[POSÉ] Un act n'est jamais un callback. C'est { port, payload? } : le renderer qui déclenche l'action émet payload sur le topic port via jOSPorts (resources/views/partials/_ploxion_ports.blade.php) — et c'est tout ce qu'il sait faire.

Pourquoi c'est non négociable : un callback JS n'existe que dans la page qui l'a créé. Un topic, lui, est déclenchable depuis n'importe quelle surface — le desktop, la montre, un ESP32 à 2 boutons qui publie sur MQTT (le pont retraduit xerbot/... en ploxion.xerbot..., contrat v1), même une entrée voix qui mappe un mot sur un act. La surface la plus pauvre (2-boutons, ou aucune + un bouton physique ailleurs) a exactement le même pouvoir que le desktop : émettre un message. L'égalité des surfaces, c'est ça.

Convention de mapping entrée→act (renderer) : 2-boutons = bouton A cycle les items, bouton B déclenche l'act de l'item courant ; molette = tourner cycle, presser déclenche ; d-pad pareil avec navigation 2D dans les list. Le ploxion n'en sait rien — il a juste posé des act triés par priorité.

Sécurité, dit tel quel : XUI v0 ne définit pas d'auth par item. Ce qui protège, c'est ce qui protège déjà le bus (SSO devant les ploxions, token-gating de l'ingress côté MQTT). Un act destructif ne doit pas exister en p1–2 sur une surface publique — règle d'auteur, pas de mécanisme, assumé en v0 (voir §7).

§7Régimes honnêtes, et ce qui reste ouvert

  • RÉEL (cette vague) : le contrat de ce document ; describe() sur les ploxions web ; le xer facteur-de-forme + le simulateur de surfaces (rendre le même XUI en montre / OLED / e-ink / téléphone / desktop dans le navigateur, avec les vraies coupes §4) ; la chaîne XUIC → MQTT en mode mock jOSMqtt.
  • PRÉSENT (à câbler, non testable ici) : le firmware ESP32 qui s'abonne à xerbot/<screen>/show, parse XUIC, dessine sur OLED/LCD, publie ses act sur 2 boutons. Le protocole est prêt et gelé ; le métal manque sur ce boxion — on le dit tel quel, pas de démo simulée déguisée en matériel.
  • TURFU (lane RS-3, pas cette nuit) : le renderer bare-metal — xerboxion-os qui dessine du XUI sans navigateur du tout. Le contrat est conçu pour : XUIC se parse sans allocateur sophistiqué, les actions sont des messages, rien ne suppose un DOM.

Ouvert (explicitement PAS gelé en v0) :

  1. Layout riche : XUI v0 est une liste priorisée, pas une mise en page. Grilles, zones, compositions multi-ploxions sur un même écran → v1, seulement quand des usages réels l'exigeront.
  2. Images et glyphes sur micro : un micro-écran 1-bit pourrait recevoir mieux que du texte. La piste sérieuse : le codec glyphes AST⟷SVG (resources/views/partials/_glyph_codec.blade.php) — un glyphe est déjà une forme compacte, vectorielle et sémantique, exactement ce qu'un OLED peut tramer. Non spécifié ici : il faudra un format raster/vecteur minimal dans XUIC ([p,'glyph',label,ast] ?).
  3. Auth par item : marquer un act comme demandant un grade xion. V0 s'en remet aux murailles existantes du bus (§6).
  4. Kinds supplémentaires (chart, map, …) : interdits en v0 — un renderer qui reçoit un kind inconnu l'ignore silencieusement (règle de forward-compat, elle, gelée).

Statut : v0 · Licence : AGPL-3.0 · 13.08.2026 · xui

NEURAL LOAD: 87%
THOUGHT CRIMES: 13
OVERSEER: XERBOXION
REALITY STATUS: LOADING...
j0bot.ch
Spotify
Spotify · clic pour lancer
📞 Appel
⏺ records
00:00
mes records (locaux, persistants)
aucun record
⏸ PAUSE
LE XERBOXION EST EN PAUSE
Échap ou « Reprendre » pour continuer · ↑↓ + Entrée
maintiens Tab pour plonger dans le portion ▾
◎ percevoir
🧠 Braindump / extrapoler — xerboxion
écris par rapport à ce ploxion → nexus + braindumps/log-date.md dans le repo
🚪 Porte
ce lien sort du xerboxion — choisis comment le traverser.
Échap
↑↓ naviguer⏎ ouvrir⇥ xerbion (widget)⇧⇧ rappeler
🎨 ploxion-theme ×