Appearance
Exemple — compteur persistant par viewer
Intention : chaque !points incrémente le compteur personnel du viewer, persistant entre les streams. Pas d'UI : l'appli tourne en fond.
Pars du bootstrap courant, conserve index.html, style.css et les configurations, fusionne le manifeste ci-dessous et remplace script.js. Le champ points est initialisé même si le stockage renvoie un objet vide. Cette version minimale suppose des commandes espacées ; des commandes simultanées demandent de sérialiser les écritures par viewer pour éviter une mise à jour perdue.
infos.json (extrait)
jsonc
{
"app-index": "index.html",
"scopes": ["chat:read", "chat:write"]
}config/default_triggers.config.json
Cet exemple propose un processus à l'installation pour écouter les commandes. Le streamer pourra ensuite le modifier ou le retirer ; voir les déclencheurs d'installation.
json
[{"type":"PROCESSUS"}]script.js
js
(async function () {
kapp.chat.onCommand('points', async (user, ev) => {
const data = await kapp.userDataStorageV2.get(user.id); // état PAR viewer
data.points = Number(data.points ?? 0) + 1;
await kapp.userDataStorageV2.set(user.id, data);
await ev.respond(`${user.display_name}, tu as ${data.points} points.`);
});
// Sans display() ni finish() ici : l’appli écoute tant que le streamer la garde ouverte.
})();Pourquoi
- Aucun visuel dans cet exemple :
display()est inutile. L’appli reste ouverte pour écouter ; elle pourrait appelerfinish()pour se terminer. kapp.userDataStorageV2.get/set= persistance par viewer (appli-only). Les anciensUser.getAppData/setAppDatarestent sur V1 et sont dépréciés.- Lis l'état, mute, réécris : pas de merge automatique côté serveur.