Appearance
Modes de lancement & manifeste (infos.json)
infos.json est le manifeste de l'appli : il décrit comment elle se lance, ses permissions, ses pages et ses ressources.
launch-mode
oneshot— l'appli est lancée, fait son travail, puis se termine (kapp.finish()). Ex. mini-jeu instantané, tirage au sort.backtask— tourne en arrière-plan, sans UI obligatoire. Ex. bot de modération, compteur, agrégateur d'événements.external— doit obligatoirement s'ouvrir dans une fenêtre popout interactive dédiée (séparée de l'overlay OBS). Elle ne peut pas être lancée en mode overlay classique. Ex. tableau de bord, interface debug.
externable: true ajoute le mode popout interactif en plus du mode classique. Par exemple, launch-mode: oneshot + externable: true peut être lancé soit sur l'overlay OBS, soit dans la popout. Le flag est redondant et ignoré avec launch-mode: external, puisque la popout y est déjà obligatoire.
| Manifeste | Overlay OBS | Popout interactive |
|---|---|---|
launch-mode: oneshot, externable: false | oui | non |
launch-mode: oneshot, externable: true | oui | oui |
launch-mode: backtask, externable: false | oui | non |
launch-mode: backtask, externable: true | oui | oui |
launch-mode: external | non | oui, obligatoire |
Savoir dans quel contexte l'exécution tourne
Le manifeste indique les contextes autorisés. Pour connaître le contexte réel de l'exécution courante, utilise :
js
if (kapp.overlay.isExternal()) {
// UI interactive de la popout
} else {
// rendu destiné à l'overlay OBS
}kapp.overlay.isExternal() est l'API recommandée. La propriété brute kapp.overlay.displayMode vaut toujours overlay ou external. overlay correspond au rendu OBS non cliquable ; external à la popout qui reçoit les interactions souris/clavier. Ne déduis pas ce contexte de kapp.overlay.type.
Attention aux deux « oneshot » :
launch-mode: oneshotdécrit le cycle de vie de l'appli (elle finit aveckapp.finish()). La valeur historiquekapp.overlay.type === 'oneshot'désigne le runtime de la page popup qui héberge l'exécution. Ces notions sont indépendantes : une app oneshot peut tourner sur l'overlay OBS, et une applaunch-mode: externalest actuellement hébergée par le runtime overlay oneshot.
Champs clés
jsonc
{
"textset": "textset.js",
"launch-mode": "oneshot", // oneshot | backtask | external
"externable": false,
"app-index": "index.html",
"scopes": ["chat:read", "chat:write"], // permissions Twitch requises
"services": [], // services exposés par l'appli (cf. common/reference/services.md)
"run-output": null, // format de sortie pour apps.run (cf. reference/app-to-app.md)
"kind": null, // contrat standard apps.run, ex. "pick-string"
"overlay-formats": ["16:9"],
"viewers-plugin": null, // page viewers (cf. reference/plugins.md)
"streamer-plugin": null, // page streamer
"viewers-readme": null,
"viewers-optout": false, // le viewer peut se retirer lui-même de l'appli
"streamer-readme": null,
"public-assets": null,
"required": []
}overlay-formats n'ajoute aucun format implicitement lorsqu'il est déclaré ; ["9:16"] seul est valide. L'iframe occupe tout le cadre du format choisi ; l'app place son contenu à l'intérieur, éventuellement via une préférence containerArea. window est accepté mais ignoré. La popout démarre dans le premier format déclaré. Voir reference/vertical.md pour les valeurs par défaut et la recette.
viewers-optout
À passer à true si ton appli peut cibler un viewer sans qu'il l'ait demandé (tirage au sort d'un adversaire, désignation d'une victime, etc.). Le viewer voit alors, sur sa page d'appli (/v/{channel}/{slug}), un bouton « ne plus me faire participer ».
Un viewer retiré devient invisible pour ton appli : kapp.users.get() ne le trouve plus, il n'apparaît plus dans kapp.chat.getActiveUsers(), tu ne reçois plus ses messages ni ses events (follow, sub, raid…), il ne peut plus lancer l'appli et ne peut plus être passé en argument de trigger. Écris donc ton code comme si ce viewer n'existait pas — c'est déjà le cas pour toi.
Le flag ne gouverne que le droit du viewer : le streamer, lui, peut interdire n'importe quelle appli à n'importe quel viewer depuis son dashboard, que le flag soit présent ou non.
Pièges
- Choisis le
launch-modeselon l'usage : une applibacktaskn'appelle pas forcémentdisplay(), uneoneshotdoit penser àfinish(). - N'utilise jamais
kapp.overlay.type === 'oneshot'pour détecter une popout interactive ; utilisekapp.overlay.isExternal(). scopesdoit couvrir les actions Twitch utilisées (ex.chat:writepourkapp.chat.say).- Déclare dans
servicesuniquement si d'autres briques doivent piloter ton appli (voircommon/reference/services.md). viewers-optout: une liste de viewers peut revenir plus courte que demandée (kapp.users.get([...])) ou ungetActiveUsers()vide — gère le cas au lieu de supposer que la cible existe.