Appearance
Types de préférences et options
Ce catalogue décrit les champs disponibles pour les applis. Les options se placent dans wuOptions, sauf mention contraire. Les propriétés communes, libellés et modèles sont dans schéma.
Texte, nombres et choix
| Type | Valeur lue au runtime | Options |
|---|---|---|
string | Chaîne, éventuellement vide/null selon le réglage | minLength, maxLength, confidential, password, list, regex, uniqueKey. |
textarea | Texte multiligne | Options de string + rows. |
number | Nombre | min, max, step, unit (texte/localisé), confidential, uniqueKey. Les bornes peuvent référencer un autre champ numérique. |
range | Nombre choisi au curseur | min, max, step, uniqueKey. |
duration | Nombre entier en millisecondes | min, max, dans la même unité. |
dualRange | { start, end } | min, max. |
boolean | Booléen | yes, no : libellés des deux états. |
color | Chaîne de couleur | Aucune option spécifique. |
keywords | Tableau de chaînes | Aucune option spécifique ; la forme stockée est une chaîne séparée par des virgules, normalisée à la lecture. |
regex | { pattern, flags } | Aucune option spécifique. |
choice | Clé du choix, ou valeur vide si facultatif | choices obligatoire, expanded, uniqueKey. |
multipleChoice | Tableau de clés de choix | choices obligatoire ; cartes via appearance.choicesStyle. |
code | Texte du code | language : json, js, javascript, html, css. |
minLength > 0 rend un texte requis. confidential demande une confirmation pour l'afficher ; password masque visuellement le texte. Ces options ne chiffrent pas la donnée et ne l'empêchent pas d'être reçue par l'appli.
uniqueKey est disponible uniquement sur les types indiqués. Les champs qui partagent cette clé arbitraire doivent avoir des valeurs différentes dans le formulaire.
Choix statiques et localisés
Fragment à ajouter dans groupItems :
json
{
"difficulty": {
"type": "choice",
"label": { "fr": "Difficulté", "en": "Difficulty" },
"default": "normal",
"wuOptions": {
"choices": {
"easy": { "fr": "Facile", "en": "Easy" },
"normal": { "fr": "Normale", "en": "Normal" },
"hard": { "fr": "Difficile", "en": "Hard" }
}
}
}
}Le default est une clé (normal), pas son libellé. Pour multipleChoice, c'est une liste de clés. Ces deux types sont requis par défaut ; déclare required: false si l'absence de choix est autorisée.
Choix issus d'une collection
wuOptions.choices peut aussi être un chemin :
"names": collection de chaînes ;"rounds#title": champ scalaire d'une collection de groupes ;"rounds#title->label": même valeur stockée, libellé dynamique du groupe affiché.
Prévois un default cohérent sur la collection source. Une modification de ses valeurs peut rendre un ancien choix invalide : tester la sauvegarde et la migration. Pour des choix dynamiques, garder le rendu select ; le mode cartes est réservé aux choix statiques.
Structure et champs spécialisés
| Type | Valeur / rôle | Référence et contraintes |
|---|---|---|
group | Objet d'enfants nommés | groupItems obligatoire ; groupes et collections. |
collection | Tableau d'éléments | collectionItems obligatoire ; min/max, tri et prototypes dans collections. |
mediaFile | { file, volume, position, timeline } ou null ; file peut être null | allowedTypes, withPosition ; défaut portable de bibliothèque, médias. |
containerArea | Zone { x, y, w, h } | settings au niveau du champ ; placements. |
containerAreas | Objet de zones nommées | settings.areas ; placements. |
announces | Configuration hydratée portant _ref | tags ; annonces. |
trigger | Référence de trigger persistant avec son état | types, arguments ; triggers persistants. |
dynamicTrigger | DynamicTriggerConfig ou null | types ; détail ci-dessous, création à l'exécution. |
runTarget | { type: 'app', slug } / { type: 'widget', id } / null | `targets: 'app' |
viewer | Données JSON overlay du Player sélectionné ou null | Aucun défaut ni option spécifique ; voir ci-dessous. |
channelItem | Objet JSON de l'item du channel ou null | Défaut interdit ; aucun wuOptions spécifique. |
channelVariable | Instantané { id, name, value, _ref } ou null | Sélection réservée au streamer, défaut interdit ; scope variables:read, voir ci-dessous. |
status | { id, name, keyword } ou null | Défaut interdit, jamais requis ; statut supprimé → null. |
role | null (tout le monde), animator, admin, superadmin | Aucun wuOptions spécifique. |
youtubeVideo | Données de la vidéo sélectionnée ou null | dynamicLabel affiche son titre ; défaut interdit. |
keyboardMacro | Données JSON de la macro saisie | Éditeur spécialisé ; aucun wuOptions spécifique. |
customPanel | Panneau d'édition HTML, sans valeur propre | source, height, autoResize ; prefs-panels. |
hiddenUuid | Identifiant technique | Injecté par la plateforme pour les collections ; ne pas gérer soi-même leurs identités. |
Ne déclare pas default / defaults pour les types dont les références dépendent du channel et qui les interdisent. Une valeur hydratée n'est pas automatiquement une instance de classe SDK.
Variable du channel choisie par le streamer
Un item channelVariable propose les variables du channel. Le streamer choisit la variable ; aucun default ni defaults n'est autorisé. preferences.get(path) renvoie un instantané {id, name, value, _ref} ou null. await kapp.variables.getFromPreference(path) relit sa valeur actuelle côté serveur.
Le scope variables:read protège les deux voies : sans le scope requis, l'instantané est null et l'appel dédié est refusé. L'appli ne peut pas modifier la sélection avec preferences.set, même via un groupe ou une collection. Ses méthodes variables.get/set/create sont absentes et les appels directs correspondants sont refusés. Pour ses données internes, utiliser les stockages V2. Le contrat des variables détaille les valeurs supprimées, les exemptions et les autorisations.
Viewer sélectionné
Utilise le sélecteur natif type: 'viewer' pour demander un viewer au streamer. La référence stockée est interne ; la lecture SDK rend du JSON, pas un objet User avec méthodes. Le Twitch ID est value.twitchUser.id, pas un hypothétique Player.id public.
js
const selected = kapp.preferences.get('winner');
const twitchId = selected?.twitchUser?.id;
if (twitchId) console.info('Viewer choisi', twitchId);Prévois null si rien n'est choisi ou si le viewer ne peut plus être résolu. Pour des méthodes SDK, passe ensuite par le service users.
dynamicTrigger : configuration du déclencheur
Un item dynamicTrigger affiche le formulaire d'un trigger à l'exécution et hydrate une valeur DynamicTriggerConfig | null. La valeur est prête à être transmise directement à kapp.dynamicTriggers.createFromConfig() : ne la remodèle pas dans l'appli. La même méthode V2 accepte aussi une DynamicTriggerConfig construite manuellement ; elle n'est pas réservée aux préférences.
Pour recevoir des arguments typés propres au callback, le code de l'app peut enrichir une copie de cette valeur avec arguments : config === null ? null : {...config, arguments: schema}. Le schéma n'appartient ni à la préférence, ni à ses default/wuOptions, ni à infos.json. Il est immuable après création. Voir dynamic-triggers.md.
js
// Fragment à ajouter dans groupItems de preferences.config.js.
viewerAction: {
type: 'dynamicTrigger',
label: { en: 'Viewer action', fr: 'Action viewers' },
required: false,
wuOptions: {
types: ['CHATCMD', 'PLDASHB'],
},
default: {
type: 'CHATCMD',
title: 'Action',
keyword: 'action',
},
},wuOptions.types est optionnel : absent, les neuf types sont disponibles. S'il est présent, il doit être une liste non vide, sans doublon, composée de CHATCMD, KEYWORD, REGEX, BITSCMD, BITS, CHDASHB, PLDASHB, INTERVAL et TWREW. Avec un seul type, le sélecteur est masqué.
required: false permet au streamer de ne rien configurer : la valeur hydratée est alors null. default, defaults localisés, collections, conditions et migrations suivent les conventions habituelles des WorkUnits. Lors d'un changement de type, les champs devenus inapplicables sont retirés de la valeur stockée.
Matrice des champs
Tous les types portent type et title. Les champs supplémentaires sont strictement limités à cette matrice :
| Type | Champs spécifiques |
|---|---|
CHATCMD, KEYWORD, REGEX | keyword, cost, description, cooldown, user_cooldown, max_per_stream, max_per_player_per_stream, authorization_level |
BITSCMD | keyword, cost, description |
BITS | cost, description |
CHDASHB | aucun |
PLDASHB | cost, description, cooldown, user_cooldown, max_per_stream, max_per_player_per_stream |
INTERVAL | interval_duration |
TWREW | cost, prompt, color, needs_input, cooldown, max_per_stream, max_per_player_per_stream |
La forme hydratée est complète et normalisée pour le type choisi :
cost: 0quand le champ existe, saufTWREWà500;description: ''etprompt: '';interval_duration: 300;color: '#546a7b';needs_input: falsepourTWREW;- cooldowns, limites et
authorization_levelànullquand ils ne sont pas limités.
Contraintes produit : keyword est requis pour CHATCMD, KEYWORD, REGEX et BITSCMD ; l'intervalle minimal est 300 secondes ; le coût Twitch minimal est 10 ; le titre est limité à 25 caractères, ou 45 pour TWREW ; les valeurs négatives sont refusées.
Pour CHDASHB et PLDASHB, la présence d'un formulaire dépend uniquement des arguments déclarés par l'appli. L'ancien champ needs_input est accepté puis ignoré pour préserver les applis déjà compilées. Il reste pertinent pour TWREW, car sa valeur configure directement la collecte d'une saisie par Twitch.
Exemple de valeur CHATCMD réellement lue dans l'appli :
js
{
type: 'CHATCMD',
title: 'Action',
keyword: 'action',
cost: 0,
description: '',
cooldown: null,
user_cooldown: null,
max_per_stream: null,
max_per_player_per_stream: null,
authorization_level: null,
}Utilisation dans une fonction async :
js
const trigger = await kapp.dynamicTriggers.createFromConfig(
kapp.preferences.get('viewerAction') ?? null,
async (_trigger, request, resolve) => {
console.info('Action reçue', request.setter.display_name);
await resolve();
return 'ok';
},
);
// `trigger` vaut null si la préférence optionnelle n'a pas été configurée.Déclare le scope triggers:manage dans infos.json. Le type TWREW exige aussi l'accès à la feature Twitch Rewards du channel. Voir dynamic-triggers.md pour la séparation stricte entre cette voie V2 et create() historique.