GenUI — Spécification de sortie UI générative
Langue : Adopte la langue demandée par l'utilisateur (sinon celle de son message), dans le texte environnant et dans tout le texte visible de l'UI : titres, étiquettes, contenu, options et explications. Les exemples en chinois ci-dessous illustrent uniquement le schéma ; ne bascule pas la conversation en chinois après avoir chargé cette compétence. Conserve les clés JSON, les types de composants, les ID et les actions inchangés. Une requête en anglais génère un texte anglais ; une requête en chinois génère un texte chinois. Les jetons <user-language ...> ne sont que des méta-placeholders. Remplace chacun d'eux par du contenu réel dans la langue de la conversation ; n'émet jamais ces placeholders littéralement.
Tu peux insérer des composants d'interface utilisateur interactifs au milieu de ta réponse : écris un bloc dsh-ui (bloc de code avec le tag dsh-ui), contenant une spécification JSON. Le moteur de rendu transformera ce bloc en composants réels, et le texte s'écoulera normalement autour. Le composant fait partie intégrante de la réponse, ce n'est pas un appel d'outil.
{"title":"<texte dans la langue de l'utilisateur>","gap":14,"items":[...]}
Règles absolues pour l'écriture du bloc (à lire en premier)
Le tag de langue sur la première ligne du bloc doit toujours être dsh-ui. N'ajoute pas de ponctuation, de guillemets ou de commentaires. Le moteur tolère la casse, les espaces de début/fin et une partie de la ponctuation de fin ; tout autre tag ne sera pas interprété comme une UI GenUI et l'utilisateur verra un bloc de code normal.
| Écriture | Résultat |
|---|---|
`` dsh-ui | ✅ Rendu |
`` dsh-ui> | ✅ Rendu (toléré) ; à l'écriture, retire le > |
`` dsh-ui avec espaces en fin de ligne | ✅ Rendu (trim automatique) |
`` DSH-UI | ✅ Rendu (insensible à la casse) |
`dshui` / ds-ui | ❌ Tag invalide |
Auparavant, un même modèle dans une même session a écrit 182 blocs `dsh-ui>` qui ont échoué silencieusement ; une tolérance universelle pour cette ponctuation de fin a maintenant été ajoutée. En écrivant un bloc, **écris uniquement les six caractères `dsh-ui`**, sans aucun signe de ponctuation, guillemet ou commentaire ; la fermeture doit être un isolé sur sa propre ligne.
Emplacement du bloc : Écris-le uniquement dans le corps de la réponse. Écrire dans le bloc reasoning/thinking ne sera pas rendu et l'utilisateur ne le verra pas.
Formules : $...$ / \(...\) pour les formules en ligne, $$...$$ / \[...\] pour les formules autonomes ; prend en charge les matrices, les fonctions par morceaux, les dérivations alignées sur plusieurs lignes, ainsi que les formules dans le texte en gras/surbrillance. Cette capacité est partagée par le corps du texte, les listes, les paires clé-valeur, les en-têtes/cellules de tableau, les titres de cartes/étapes/chronologies/onglets, les questions et explications, les étiquettes de boutons et de formulaires, les indicateurs, les légendes de médias et les titres de graphiques. Les barres obliques inverses dans les chaînes JSON doivent être doublées, ex. "content": "\(\frac{a}{b}\)". Le code source, les valeurs d'entrée/placeholders, les options natives des listes déroulantes et le texte de dessin interne du moteur de graphiques suivent toujours leur format natif et ne sont pas analysés pour le texte enrichi. La syntaxe mathématique est basée sur KaTeX ; n'exécute pas de HTML, de ressources externes ou de scripts ; ne prend pas en charge la compilation de documents LaTeX ou le chargement de packages arbitraires.
Vocabulaire des composants (seuls ces types sont autorisés)
Disposition : text row col grid card carousel divider spacer arrow hero
Affichage : stat badge progress list table keyvalue avatar image image-group audio video timeline file-tree breadcrumb diff json code callout steps icon blocks
Graphiques : chart (bars/line/donut, multi-séries) plot (graphique de fonction mathématique) echart (graphique ECharts complet)
Interaction : button input select checkbox radio switch slider textarea tabs accordion copy link submit
Avancé : svg mermaid diagram scene3d quiz
Disposition
- text :
{"type":"text","size":"display|h1|h2|h3|body|muted|caption","content":"...","align":"left|center|right"?}(tone:"danger|success|warning|info|muted"donne une couleur sémantique à la ligne entière, sans utiliser badge ;mono:trueutilise une police à chasse fixe pour les hexadécimaux/binaires/identifiants, sans fond de code en ligne). (size:"display"est un cran au-dessus du titre, pour une phrase d'introduction/accroche ; ≤1 par réponse ;center:trueest l'ancienne écriture, équivalente àalign:"center", utilise toujoursaligndans les nouvelles écritures) - row / col :
{"type":"row"|"col","items":[...],"wrap":true?,"spacer":true?,"gap":n?};row.justify:"center"pour centrer sur l'axe principal (comme l'en-tête icône+titre) ;col.width:n(1-100) donne à cette colonne un pourcentage de la largeur de la ligne, sinon la largeur est basée sur le contenu. - grid :
{"type":"grid","cols":n,"items":[...]} - carousel :
{"type":"carousel","title":"<titre dans la langue de l'utilisateur>","items":[{"type":"card","title":"...","items":[...]}],"itemWidth":240?,"gap":3?}— Défilement horizontal des nœuds natifs ; jusqu'à 24 éléments, largeur de 80 à 640 px et ne dépassant pas 85 % de la largeur de la piste ; largeur par défaut 240 px. La valeurgapest multipliée par 4 px, si omise la valeur est de 12 px, les valeurs négatives sont traitées comme 0. Le bouton de navigation fait défiler 85 % de la largeur de la piste à chaque fois, ne s'affiche que lorsque le contenu déborde ; les appareils tactiles font défiler la piste directement. Pas de lecture automatique. Lorsque la piste est ciblée, les touches fléchées gauche/droite, Home/End sont actives ; les formulaires à l'intérieur des cartes suivent les règles de soumission d'origine. La navigation et le défilement n'envoient pas d'action ; les actions déclarées par les composants enfants sont déclenchées selon les règles d'interaction existantes. En sortie streaming, les cartes sont ajoutées uniquement à la fin pour préserver les chemins de saisie existants. - hero :
{"type":"hero","title":"<titre dans la langue de l'utilisateur>","subtitle":"<texte dans la langue de l'utilisateur>","value":"99.96%","label":"<indicateur dans la langue de l'utilisateur>","delta":"+0.02%","spark":[...],"tone":"accent|success|warning|danger"}— Bloc de couverture : sourcil + très grand nombre (52 px, avec compteur d'entrée) + titre + sous-titre + fond dégradé de tonalité. Maximum un par réponse, à placer tout en haut comme point d'ancrage visuel. - span : N'importe quel nœud peut ajouter
"span":2(nombre de colonnes qu'un nœud enfant de grid occupe) — Le seul primitive pour la mise en page en bento : une large carte enspan:2associée à une carte étroite, bien plus esthétique qu'une pile de carrés. - card :
{"type":"card","title":"...","items":[...]};"tone":"info|success|warning|danger"donne un fond sémantique (pour les cartes de conclusion/risque) ;"accent":"#f59e0b"spécifie une couleur d'accent (bordure + titre + fond très pâle) ;"flat":truesupprime l'ombre, remplacée par un fond neutre très pâle — les panneaux dans les figures doivent utiliser flat, sinon chaque couche ressemble à une carte flottante, et deux couches deviennent sales ;"eyebrow":"<petit titre introductif dans la langue de l'utilisateur>"ajoute une petite ligne meta au-dessus du titre (à utiliser pour séparer des chapitres entre cartes — ne pas ajouter à chaque carte d'un même chapitre, ≤3 par réponse). - palette :
chart/echartsupportent tous"palette":["#ff8800","#3ecf8e"]pour remplacer la palette de couleurs par défaut (suit le thème de l'hôte par défaut). Écris-la uniquement lorsque la couleur est sémantiquement nécessaire (coût=rouge, profit=vert), sinon il est plus sûr de suivre le thème. - divider :
{"type":"divider"}; avec nom de section{"type":"divider","label":"<nom de section dans la langue de l'utilisateur>"}(ligne + petite étiquette centrée, pour les changements de section : rapports passant du résumé aux données, ouverture d'un nouveau chapitre dans un album de graphiques — ne pas utiliser à l'intérieur des cartes/listes ou entre des contenus thématiques continus, ≤3 par réponse). spacer :{"type":"spacer"}
Affichage
- stat :
{"type":"stat","label":"...","value":"...","delta":"+12.4%|-3%"}(-au début = rouge automatique,+= vert) ; optionnel"spark":[3,5,4,8,6]pour une micro-courbe de tendance (2 à 60 valeurs numériques finies) ;"size":"hero"rend un très grand nombre (à utiliser une fois maximum par réponse, comme point d'ancrage visuel). - badge :
{"type":"badge","label":"...","tone":"success|warn|danger|accent","icon":"emoji?"} - progress :
{"type":"progress","label":"...","value":0-100,"valueLabel":"70%"};"variant":"ring"pour une jauge circulaire,"target":70pour marquer un repère sur la barre. - avatar :
{"type":"avatar","name":"...","color":"#hex?"} - image :
{"type":"image","src":"/mmx-files/result.png","alt":"<description dans la langue de l'utilisateur>"}— Affiche une image http(s) accessible par le navigateur ou une adresse relative de même origine ; chargement différé ; ne supporte pas les protocolesfile:/data:locaux ou actifs ;"caption":"<légende dans la langue de l'utilisateur>"ajoute une ligne d'explication en dessous de l'image (source/interprétation/credit ;altest l'étiquette au-dessus de l'image, les deux ont des rôles différents). - image-group :
{"type":"image-group","title":"<titre dans la langue de l'utilisateur>","items":[{"src":"/mmx-files/a.png","alt":"<description>","caption":"<caption>"},{"src":"/mmx-files/b.png","alt":"<description>"}]}— Jusqu'à 24 images disposées automatiquement en fonction du rapport hauteur/largeur ; clic pour ouvrir dans une lightbox native, touches fléchées gauche/droite / Home / End pour naviguer, Esc / bouton de fermeture pour revenir et restaurer le focus. Reprend les limitations d'URL http(s)/relatives d'image; n'accepte pas les protocoles file/data/javascript. Uniquement pour la navigation locale, n'envoie pas d'action ; pour des actions nécessitant le modèle, place un bouton indépendant à côté. L'ajout / la réorganisation conserve lesrcactuel ; le retrait de l'image actuelle ferme la visionneuse ; lessrcidentiques sont différenciés par leur ordre d'apparition. Les listes vides et les échecs de chargement d'image ont des états clairs. L'export HTML n'intègre pas les octets de l'image, celle-ci dépend toujours de son adresse d'origine. Utilisation complète et recette. - audio :
{"type":"audio","src":"/mmx-files/result.mp3","alt":"<description dans la langue de l'utilisateur>","loop":true?}— Contrôle natif ; lecture déclenchée par l'utilisateur, pas automatique ; uniquement http(s) ou adresse relative de même origine. - video :
{"type":"video","src":"/mmx-files/result.mp4","alt":"<description dans la langue de l'utilisateur>","poster":"/mmx-files/poster.jpg"?,"loop":true?,"muted":true?,"aspectRatio":"16:9|4:3|1:1|9:16"?}— Contrôle natif de lecture/volume/plein écran ; pas de lecture automatique. - list :
{"type":"list","items":["..."]ou[{"title":"...","desc":"..."}]ou nœuds imbriqués (ex.{"type":"badge","label":"TS"})} — Les nœuds peuvent être imbriqués en ligne (comptés dans le budget des nœuds) ;label/namedans les enregistrements sont normalisés entitle,description/content/text/body/detailsont normalisés endesc; si seul le corps du texte est présent, il est utilisé comme titre ; les champs inconnus déclencheront un avertissement. - table :
{"type":"table","columns":["..."],"rows":[["...","..."]],"types":["text|num|delta|bar|badge"]?,"details":[[...]]?,"total":true?}— Tri local par clic sur l'en-tête (ascendant/descendant/réinitialisation, zéro aller-retour) ; perception numérique : les séparateurs de milliers (1 234),k/m/b,万/亿,%, les symboles monétaires sont tous comparés en tant que valeurs numériques réelles, les colonnes purement numériques sont automatiquement alignées à droite ; les cellules avec signe sont automatiquement colorées (+12,4%vert,-3rouge, sans champ supplémentaire) ;typespeut spécifier par colonne :bar(barre de progression en ligne 0-100),ring(petit cercle 0-100),spark(la cellule contient"3,5,4,8"pour une micro-courbe),badge(étiquette capsule),delta(couleur forcée hausse/baisse),num(alignement forcé à droite),index(numéro de ligne),group(première colonne comme titre de groupe : si seule la première cellule de la ligne a du contenu, elle est rendue comme un sous-titre s'étendant sur toutes les colonnes) ;"total":trueajoute une ligne de total (somme automatique des colonnes numériques) ;"export":true: deux petits boutons « Copier en Markdown / Copier en CSV » apparaissent au-dessus du tableau (presse-papiers local uniquement, pas de requête) ;"filter":"id_de_champ_de_saisie": lie le tableau à un champ input/select, le lecteur peut filtrer instantanément en tapant (filterColumnpeut limiter la colonne) — quand il y a beaucoup de données, il faut par défaut en mettre un ;"sortField":"id_de_liste_deroulante"utilise la valeur (nom de colonne) de la liste déroulante pour trier ;"details"est dans le même ordre querows, le i-ème élément est le contenu développé pour cette ligne (peut contenir n'importe quel composant,null= la ligne ne peut pas être développée) — un chevron apparaît dans la première colonne, un clic affiche les détails en dessous de la ligne entière, parfait pour « tableau principal + détails ». - keyvalue :
{"type":"keyvalue","pairs":[{"key":"...","value":"..."}]} - timeline :
{"type":"timeline","items":[{"title":"...","desc":"...","time":"..."}]} - file-tree :
{"type":"file-tree","items":[{"name":"...","type":"file|dir","children":[...]?}]}— Les lignes de répertoire peuvent être cliquées pour se replier/développer (local, zéro aller-retour). - breadcrumb :
{"type":"breadcrumb","items":["<texte dans la langue de l'utilisateur>","<texte dans la langue de l'utilisateur>","<texte dans la langue de l'utilisateur>"]} - diff :
{"type":"diff","diffs":[{"path":"...","oldText":"..."|null,"newText":"..."}]} - json :
{"type":"json","value":...}(visualiseur d'arbre JSON) - code :
{"type":"code","lang":"ts","code":"..."} - callout :
{"type":"callout","tone":"info|success|warning|error","title":"...","content":"..."}— Pour une seule mise en valeur, un rappel ou un résumé de risque ;contentest une chaîne de texte, utilise"\n"en JSON pour les sauts de ligne. Pour plusieurs éléments indépendants, utiliselistavec{title,desc}pour conserver la hiérarchie. - steps :
{"type":"steps","current":n,"steps":[{"title":"...","desc":"..."}]} - arrow :
{"type":"arrow","dir":"down|right","length":16-96,"label":"..."}— Connecteur fin entre deux blocs dans une figure (ligne de 1,4 px + flèche en V, longueur fixe). Dans les diagrammes de flux verticaux, utilise toujours celui-ci ; ne pas utiliser de « ↓ » en texte : la flèche caractère suit la ligne de base du texte et ne crée pas d'espacement. - icon :
{"type":"icon","name":"Nodes","tone":"info|success|warning|danger|muted|default","size":16|20|24|32,"tile":true,"label":"<nom accessible dans la langue de l'utilisateur>"}— Ensemble d'icônes intégrées (749 rendues fidèlement ; 64 en ligne, rendues instantanément, les autres chargées à la première utilisation, liste complète dans ICON-NAMES.md).tile:truele rend comme un fond carré arrondi pâle, pour les cartes d'étape/marqueurs sémantiques ; sanstile, c'est une icône en ligne de la couleur du texte.labelpeut être omis (purement décoratif), lorsqu'ils apparaissent par paire, un seul doit avoir un label. - blocks :
{"type":"blocks","title":"...","rows":[{"label":"initial","cells":["0","1","2"],"color":"#64748b"}],"columns":n?,"caption":"..."}— Diagramme en blocs colorés : cellules regroupées par lignes. Trois formes avec la même structure : ① Diagramme en escalier (chaque ligne a un nombre différent de cellules, chaque ligne divise sa largeur également, ex. 8→4→2→1) ② Blocs égaux (4 blocs par ligne) ③ Diagramme en couloir (columnsfixe le nombre de colonnes, écris"—"ou laisse vide danscells). Sicolorest omis, utilise un fond pâle de la couleur d'accent ; la couleur du texte est inversée automatiquement en fonction de la luminosité (texte blanc sur fond sombre / texte noir sur fond clair). Utilise-le pour toute structure qui doit « être divisée en plusieurs parties, progresser par tours, ou être comparée en groupes », n'écris pas de coordonnées SVG à la main.captionest obligatoire : une phrase expliquant ce que chaque cellule représente.- Au niveau de la ligne :
"variant":"outline": bordure fine sans remplissage, pour les matrices (chaque cellule est un cadre) ;"variant":"plain": pas de cadre du tout, pour les chaînes de bits (1 0 1 0 0 0 0 0se lit comme un nombre, pas un tableau) — seules les cellules avectone/colorauront un fond. - Les cellules peuvent être écrites sous forme d'objet :
{"text":"1","tone":"danger","sub":"SF"}—tone(accent/success/warning/danger/muted) donne une couleur sémantique à une seule cellule,subajoute une petite ligne de texte en dessous de la cellule (nom de bit, numéro, rôle).colorpeut spécifier explicitement un hexadécimal, prioritaire surtone. - Exemple :
{"columns":8,"rows":[{"variant":"outline","cells":[{"text":"1","tone":"danger","sub":"SF"},"0","1","1","0","0","1","0","0"]}],"caption":"Le bit de poids fort est 1, donc SF=1."}
- Au niveau de la ligne :
Noms d'icônes intégrés : les 64 suivants sont intégrés dans le paquet, rendus immédiatement, choisis de préférence parmi ceux-ci :
Check CheckCircle Info InfoCircle Warning Error X Plus Minus Circle ArrowDown ArrowUp ArrowRight ArrowLeft ArrowCurvedRight Function Functions Operator Atom Nodes Connect Share Branch Grid GridAlt Stack Cube Storage Chart Trending Pulse Speed Timer Clock TableFilled Code SquareCode Terminal File FileCode Folder Link Paperclip Lightbulb Book BookOpen GraduationCap Flask Lab Brain Robot Sparkles ShieldCheck Lock Globe WebsiteNetwork Search MagnifyingGlassSearch PluginPuzzle Settings Bolt Compass
Les 685 autres sont chargés à la demande (environ 1 Mo téléchargé à la première utilisation, puis toute cette page est disponible). La liste complète se trouve dans ICON-NAMES.md dans le même répertoire que cette compétence — lis-le ou grep-le si tu as besoin de deviner un nom, ne fais pas d'énumération dans la conversation.
Graphiques
- chart :
{"type":"chart","kind":"bars|line|donut","data":[{"label":"...","value":n,"color":"#hex?"}],"series":[{"label":"...","data":[...]}]?,"horizontal":true?}—barspar défaut ;linepour les tendances ;donutpour les proportions ;series:barspour les barres groupées,linepour les lignes multi-séries ; chaqueseries[].datautilise un tableau d'objets[{"label":"Q1","value":30},{"label":"Q2","value":45}], pas un tableau de nombres purs[30,45];horizontal:truepour des barres horizontales (idéal pour les classements/étiquettes longues) ;stacked:truepour empiler les séries (composant/part dans le temps) ; lorsque les segments empilés sont suffisamment hauts, les valeurs sont imprimées directement à l'intérieur du segment, le survol de n'importe quelle barre/segment/point/secteur fait apparaître une info-bulle instantanée (affichant la valeur du segment + le total). Rendu v3 : largeur adaptative, 1/2/5 graduations sur l'axe Y, les valeurs négatives en série unique sont dessinées réellement sous la ligne zéro,lineavec dégradé de surface et étiquettes X espacées, légendedonutavec valeurs et pourcentages. Utilisechartpour une comparaison rapide de ≤8 points ; pour les séries multiples, le zoom/l'interaction ou les grands volumes de données, utiliseechart. - plot :
{"type":"plot","series":[{"expr":"a*sin(b*x)","label":"...","color":"#hex?","params":[{"name":"a","value":1,"min":0,"max":5,"animateTo":3,"durationMs":4000,"loop":true},{"name":"b","value":1,"min":0.5,"max":5}]}],"xMin":-6.28,"xMax":6.28,"title":"..."}— Graphique de fonction SVG ;seriespeut avoir"kind":"line|area|scatter"(linepar défaut ;arearemplit jusqu'à la ligne de base ;scatterpour les points) ;paramsest rendu sous forme de curseurs en temps réel (le glissement redessine instantanément, l'axe Y est verrouillé = seule la courbe change, pas l'axe) ; les paramètresanimateToaffichent un bouton de lecture (démonstration animée automatique) ; le SVG peut être glissé/déplacé, zoomé avec la molette ; les expressions prennent en charge sin/cos/tan/asin/acos/atan/sqrt/cbrt/exp/log/ln/abs/floor/ceil/round/min/max/pow, les constantes pi/e/tau, la variable x (les autres lettres sont des paramètres). - echart :
{"type":"echart","title":"...","height":300,"preset":"bar|line|area|pie|scatter","data":[{"label":"...","value":n}],"series":[...]?}— Graphique ECharts complet, avec un rendu visuel bien supérieur àchart(dégradés, info-bulles, animations, interactions de légende) ; modepreset: utilise les mêmes formatsdata/seriesquechart, construit automatiquement une configuration ECharts thématisée (couleurs suivant le thème de l'hôte) ; Aperçu despresets(écris uniquementpreset+data/series/links, le thème suit automatiquement) :bar·line·area·pie·scatter·radar(un polygone par série, les indicateurs proviennent des labels de la première série) ·gauge(une jauge par datum, idéal pour un seul KPI) ·funnel(entonnoir/conversion) ·treemap(volume/hiérarchie) ·sankey(flux, utiliselinks:[{from,to,value}]) ·graph(graphe relationnel, piloté parlinks, taille des nœuds proportionnelle au nombre de connexions) ·heatmap(seriescomme lignes, les labels de la première série comme colonnes) ·bigline(longue série + zoom intégré) ·wordCloud(nuage de mots,data:[{label,value}]oùvalueest le poids ; les couleurs suivent lapaletteou la palette de couleurs du thème). Mode option complète : passe"option":{...}pour écrire directement la configuration native ECharts (supporte les graphiques intégrés ECharts et l'extensionwordCloudenregistrée ; les autres extensions tierces ne sont pas garanties). Les fonctions dansoptionsont filtrées (seules les données sont acceptées). Principe de sélection :chartest léger (pas de téléchargement supplémentaire) idéal pour une comparaison rapide ≤8 points ;echartest plus riche visuellement (dégradés, info-bulles, interactions de légende,dataZoom), mais télécharge environ 1 Mo de moteur à la demande, prioritaire pour les scénarios multi-séries, grands écrans et interactifs.
Interaction
Local d'abord (v2.6) : Les changements d'état que l'UI peut gérer par elle-même — correction, notation, réinitialisation, développement, sélection — sont tous effectués localement et immédiatement, zéro aller-retour vers le modèle. L'action est utilisée uniquement pour les choses qui nécessitent l'intervention du modèle (générer du nouveau contenu, exécuter un outil, suggérer la prochaine étape). Les composants interactifs doivent avoir une action : un bouton sans action est rendu dans un état désactivé, l'utilisateur ne peut pas cliquer ; un bouton avec action donne un retour local « déclenché » après le clic.
- button :
{"type":"button","label":"...","tone":"primary|danger|success|ghost","full":true?,"small":true?,"icon":"emoji?","action":"refresh"?} - Interdiction absolue : Ne demande ni ne génère de mots de passe, clés API, jetons d'accès, codes de récupération ou autres entrées secrètes ; face à une telle demande, refuse directement et explique.
- input :
{"type":"input","label":"...","placeholder":"...","inputType":"text|email|color|number","value":"...","action":"name"?,"id":"field-id"?}—colorutilise le sélecteur de couleur natif du navigateur, la valeur utilise#RRGGBB;numberpeut être utilisé comme champ de saisie numériqueComputed; l'actionest déclenchée au flou ET à l'appui sur Entrée (l'appui sur Entrée inclutsubmit:true) ; le flou n'est envoyé que si la valeur a changé (le fait de se concentrer et de quitter sans changer ne génère pas d'aller-retour vide) ; le payload inclutidpour aider le modèle à localiser le champ ; les valeurs avecidsont conservées après un rafraîchissement et collectées parsubmitdansfields. - select :
{"type":"select","label":"...","options":["...","..."],"selected":indice?,"action":"pick"?,"id":"field-id"?}—selectedpré-sélectionne une option (par défaut, affiche « Veuillez sélectionner... » comme espace réservé, ne présélectionne pas silencieusement la première option) ; les sélections avecidsont conservées entre les rafraîchissements et incluses dans lesfieldsdesubmit. - checkbox :
{"type":"checkbox","label":"<option dans la langue de l'utilisateur>","checked":true?,"action":"toggle"?,"group":"group-id"?}— Le comportement par défaut est de déclencher une action à chaque changement ; l'ajout degroupactive le mode d'agrégation multi-sélection : les cases à cocher du même groupe peuvent être cochées/décochées à plusieurs reprises, les changements sont enregistrés localement sans action individuelle, unsubmitfrère envoie en une seule fois les labels cochés de ce groupe sous forme de tableau de chaînes dansanswers(ex.{"styles":["<option>","<option>"]}). - slider :
{"type":"slider","label":"...","min":0,"max":100,"step":1,"value":n?,"action":"name"?,"id":"field-id"?}— Curseur de formulaire numérique : affiche la valeur en temps réel ; les curseurs avecidsont conservés entre les rafraîchissements et inclus dans lesfieldsdesubmit(le glissement est anti-rebond et fusionné en une seule action). - radio :
{"type":"radio","label":"<label dans la langue de l'utilisateur>","options":["<option dans la langue de l'utilisateur>","<option dans la langue de l'utilisateur>"],"selected":n?,"action":"pick"?}— Sélection unique ; l'ajout de"group":"group-id"active le mode d'agrégation : la sélection est uniquement enregistrée localement, sans aller-retour ; on peut définir"answer":indice ou label correctet"explanation":"<explication dans la langue de l'utilisateur>", pour une correction locale en mode radio pur sans autre état de formulaire en attente d'envoi. - link :
{"type":"link","label":"...","href":"https://..."?}— Seuls les protocoles http(s)/mailto sont acceptés ; sanshref, il est rendu comme du texte simple (ne fait pas semblant d'être cliquable). - submit :
{"type":"submit","label":"<action dans la langue de l'utilisateur>","action":"grade","groups":["q1","styles"],"resetAction":"redo"?}— Bouton d'agrégation :groupsréférence les clés membres de soumission dans le bloc actuel, les sources sontradio.group,checkbox.group,input.id,textarea.id,select.id,slider.id; pour lesradio, une option doit être sélectionnée ; pour les groupescheckbox, au moins un élément doit être coché ; pour les champs normaux, la valeur doit être non vide après trim.groupscontrôle les membres requis pour la soumission et la progression ; s'il n'est pas défini, au moins un membre complété suffit pour soumettre. Pour lesradiopurs avecansweret sans payload externe, une correction locale peut être effectuée ; dans les autres cas, un[genui-action]est envoyé, le payload collecte l'état du formulaire actuellement rempli dans le bloc.