# Écrire un pack Hou.la Connect : guide pour une IA

Ce fichier décrit le format JSON d'un pack interactif Hou.la Connect (schéma 3). Il est fait pour être donné à une IA avec la liste des sons (« Exporter la liste des sons » dans Connect), pour qu'elle écrive un pack que le Lab de Connect accepte tel quel.

## Comment s'en servir

1. Donne ce guide à ton IA, et la liste des sons si ton pack doit en jouer. Décris-lui ton pack : ce que les spectateurs déclenchent, et ce qui se passe.
2. Elle rend UN fichier JSON, écrit comme l'exemple complet plus bas.
3. Dans Connect : Lab, ouvre ou crée ton pack, onglet « Écouteurs », bouton « JSON », puis « Importer un fichier… » (ou colle le texte). « Vérifier mon pack » dit ce que Hou.la refuserait, avant d'enregistrer.
4. Ce qu'une IA ne peut pas deviner se règle ensuite dans le Lab : l'icône d'un cadeau personnalisé, les overlays du streamer, les connexions (OBS, serveur de jeu).

## Le pack

```json
{ "schema": 3, "rules": [ … ], "chatbot": [ … ], "profiles": [ … ], "maxPlayers": 2 }
```

- `schema` : 3.
- `rules` : les interactions (300 au plus). Chacune : un ou plusieurs déclencheurs (`on`), une chaîne de blocs (`do`).
- `chatbot`, `profiles`, `maxPlayers` : facultatifs (réponses automatiques du chat, configurations clavier ou manette, joueurs simultanés d'un pack manette). Laisse-les de côté si tu n'en as pas besoin.
- `slug` : facultatif, le Lab met celui du pack. Aucune autre clé n'est admise : une clé inconnue fait refuser le pack entier.

## Une interaction (`rules[i]`)

| Clé | Ce que c'est |
|---|---|
| `id` | Identifiant unique dans le pack, 60 caractères au plus. Garde-le d'une version à l'autre : les réglages des streamers y sont attachés. |
| `label` | Le NOM de l'interaction, 120 caractères au plus. Pour un cadeau personnalisé (`ix_slot_NN`), c'est AUSSI le nom du cadeau que les spectateurs voient sur sa tuile. Sans nom, Connect affiche ce qui la déclenche. |
| `on` | Un déclencheur (objet), ou une liste de 8 au plus : l'un OU l'autre lance la chaîne. |
| `do` | La chaîne de blocs, jouée dans l'ordre. |
| `followersOnly`, `moderatorsOnly` | `true` : réservé aux abonnés, ou aux modérateurs. |
| `enchainement` | Si l'interaction repart pendant qu'elle tourne : `suite` (défaut, les demandes attendent leur tour), `ensemble` (en même temps), `ignorer`. |
| `profile` | L'identifiant d'une configuration de `profiles` (clavier, manette). Absent : toutes. |

## Les déclencheurs (`on`)

| type | Réglages | Variables disponibles |
|---|---|---|
| `gift` | Un cadeau Hou.la. `giftSlug` : un cadeau du catalogue, ou un CADEAU PERSONNALISÉ `ix_slot_01`, `ix_slot_02`… (sa tuile porte le `label` de la règle, `coinCost` = son prix dans l'échelle ci-dessous, `group` = son rayon, 24 caractères, `iconUrl` et `accentColor` se règlent dans le Lab). Ou `minCoins: N` : n'importe quel cadeau d'au moins N pièces. `perSend: true` : une fois par envoi au lieu d'une fois par cadeau. | {sender.name} {sender.id} {sender.avatar} {gift.name} {gift.slug} {gift.quantity} {gift.coins} {gift.unitCoins} {random} |
| `follow` | Un nouvel abonné. Aucun champ. | {sender.name} {sender.id} {sender.avatar} {followers.total} {random} |
| `comment` | Un message du chat. UN des trois : `startsWith` (une commande, « /dis », 40 caractères), `contains` (un mot, 80 caractères) ou `every: N` (tous les N messages). `platforms` : les chats écoutés parmi `houla`, `twitch`, `kick`, `youtube`, `tiktok` (absent = Hou.la seul). | {sender.name} {sender.id} {sender.avatar} {sender.slug} {message.text} {message.suite} {random} {platform.name} {platform.id} |
| `command` | Une COMMANDE de chat déclarée par le pack, montrée aux spectateurs. `name` (2 à 20 caractères a-z, 0-9, _ ; sans la barre), `description` (une ligne, 120 caractères), `coinCost` (0 ou absent = gratuite, sinon un prix de l'échelle), `args` : `aucun`, `texte`, `nombre` ou `pseudo`, `who` : `tous`, `abonnes` ou `moderateurs`, `aliases` (3 au plus), `perViewerMs` (0 à 3 600 000). Des noms sont réservés par Hou.la (le Lab les refuse, par exemple `score`). | {sender.name} {sender.id} {sender.avatar} {sender.slug} {message.text} {random} {commande.nom} {commande.texte} {commande.coins} |
| `priority` | Un message prioritaire payé. `minCoins` facultatif. | {sender.name} {sender.id} {sender.avatar} {sender.slug} {message.text} {random} {message.coins} |
| `hearts` | Les likes du live. `milestone: N` (un palier), `milestones: [N1, N2…]` (strictement croissants) ou `every: N`. | {hearts.total} {hearts.palier} {random} |
| `share` | Un partage du live. `every: N` facultatif, `perViewerMs` facultatif. | {sender.name} {sender.id} {sender.avatar} {random} |
| `share_total` | Le total des partages du live : `milestone`, `milestones` ou `every`, comme `hearts`. | {sender.name} {sender.id} {sender.avatar} {shares.total} {shares.palier} {random} |
| `viewer` | Tous les N nouveaux spectateurs : `every: N`. | {viewers.count} {random} |
| `join` | Un spectateur Hou.la arrive dans le live (une fois par spectateur et par live). | {sender.name} {sender.id} {sender.avatar} {sender.slug} {viewers.count} {random} |
| `poll` | Un sondage. `phase` : `started`, `tally` ou `closed` (défaut). | {poll.question} {random} |
| `goal` | Un objectif de cadeaux. `onlyCompleted` (défaut vrai). | {goal.label} {random} |
| `hotkey` | Le streamer appuie sur son raccourci : `name` (la touche se règle sur son PC). | {hotkey.name} {random} |
| `wheel` | La roue du streamer tombe sur un lot : `segment` facultatif. | {sender.name} {sender.id} {sender.avatar} {random} {wheel.segment} {wheel.label} {wheel.numero} {wheel.action} {wheel.points} {wheel.rang} |
| `platform` | Un événement d'une AUTRE plateforme : `platform` (`tiktok`, `twitch`, `kick`, `youtube`) et `event` (liste plus bas). `min` : un seuil dans l'unité de la plateforme. `giftId` : UN cadeau TikTok précis (des chiffres, 5655 = Rose). Sur `like_total` et `share_total` : `milestone`, `milestones` ou `every`. | {sender.name} {message.text} {hearts.total} {hearts.palier} {shares.total} {shares.palier} {random} {platform.name} {platform.id} {platform.amount} {platform.label} {platform.count} {platform.gift.id} {platform.gift.name} |
| `chrono` | Un chrono d'overlay arrive à zéro : `overlayId` facultatif (un overlay du streamer). | {random} {chrono.nom} {chrono.secondes} |
| `match` | Un match d'overlay se termine : `overlayId` facultatif. | {random} {gagnant} {gagnant.pieces} {deuxieme} {troisieme} {match.nom} {match.participants} {match.pieces} |
| `objectif` | Un objectif d'overlay est atteint : `overlayId` facultatif. | {random} {objectif.nom} {objectif.palier} {objectif.cible} {objectif.valeur} {objectif.cadeau} |
| `product` | Un produit est épinglé sur le live. | {random} {product.name} {product.price} {product.image} |
| `auction` | Une enchère se termine : `outcome` `sold` ou `unsold` (absent = les deux). | {sender.name} {sender.id} {sender.avatar} {random} {product.name} {auction.result} {auction.price} {auction.bids} |
| `purchase` | Un achat est payé dans la boutique pendant le live. | {sender.name} {sender.id} {sender.avatar} {sender.slug} {random} {product.name} {purchase.items} |
| `promo` | Un code promo est ajouté au live. | {random} {promo.code} {promo.discount} {promo.seconds} |

### Les prix (`coinCost`)

Un prix se choisit dans cette échelle fermée, en pièces Hou.la (1 700 pièces valent environ 20 €) : 5, 10, 15, 20, 30, 45, 60, 80, 100, 125, 155, 190, 230, 280, 340, 410, 490, 580, 680, 790, 900, 1010, 1120, 1230, 1340, 1440, 1530, 1600, 1660, 1700, 2000, 2500, 3000, 3500, 4000, 4500, 5000. Toute autre valeur fait refuser le pack.

### Les événements des autres plateformes (`"type": "platform"`)

| platform | event | Ce que c'est | Réglages | Variables |
|---|---|---|---|---|
| `twitch` | `bits` | des bits | `min` en bits | {sender.name} {platform.amount} {message.text} {platform.label} {platform.name} {platform.id} |
| `twitch` | `sub` | un abonnement ou un réabonnement | `min` en mois d'abonnement cumulés | {sender.name} {platform.amount} {message.text} {platform.label} {platform.name} {platform.id} |
| `twitch` | `giftsub` | des abonnements offerts | `min` en abonnements offerts | {sender.name} {platform.amount} {platform.label} {platform.name} {platform.id} |
| `twitch` | `raid` | un raid | `min` en spectateurs du raid | {sender.name} {platform.amount} {platform.label} {platform.name} {platform.id} |
| `twitch` | `follow` | un nouveau follow (chaîne connectée par ton compte) | - | {sender.name} {platform.label} {platform.name} {platform.id} |
| `twitch` | `reward` | une récompense de points de chaîne (chaîne connectée par ton compte) | `min` en points de chaîne | {sender.name} {platform.amount} {message.text} {platform.label} {platform.name} {platform.id} |
| `kick` | `follow` | un nouveau follow | - | {sender.name} {platform.label} {platform.name} {platform.id} |
| `kick` | `sub` | un abonnement ou un réabonnement | `min` en mois d'abonnement | {sender.name} {platform.amount} {platform.label} {platform.name} {platform.id} |
| `kick` | `giftsub` | des abonnements offerts | `min` en abonnements offerts | {sender.name} {platform.amount} {platform.label} {platform.name} {platform.id} |
| `kick` | `kicks` | des KICKs offerts | `min` en KICKs | {sender.name} {platform.amount} {message.text} {platform.label} {platform.name} {platform.id} |
| `kick` | `reward` | une récompense de points de chaîne | `min` en points de chaîne | {sender.name} {platform.amount} {message.text} {platform.label} {platform.name} {platform.id} |
| `kick` | `host` | un hébergement (host), ancienne liaison par pseudo seulement | `min` en spectateurs | {sender.name} {platform.amount} {message.text} {platform.label} {platform.name} {platform.id} |
| `youtube` | `superchat` | un Super Chat ou un Super Sticker | - | {sender.name} {platform.label} {message.text} {platform.name} {platform.id} |
| `youtube` | `member` | un nouveau membre ou un palier de membre | `min` en mois de membre | {sender.name} {platform.amount} {message.text} {platform.label} {platform.name} {platform.id} |
| `youtube` | `giftmember` | des abonnements membres offerts | `min` en abonnements offerts | {sender.name} {platform.amount} {platform.label} {platform.name} {platform.id} |
| `tiktok` | `gift` | un cadeau TikTok | `min` en diamants, `giftId` | {sender.name} {platform.gift.name} {platform.count} {platform.amount} {platform.gift.id} {platform.label} {platform.name} {platform.id} |
| `tiktok` | `like` | des likes, message par message | `min` en likes | {sender.name} {platform.amount} {hearts.total} {platform.label} {platform.count} {platform.name} {platform.id} |
| `tiktok` | `like_total` | des likes, total du live | `milestone`, `milestones` ou `every` (obligatoire) | {hearts.palier} {hearts.total} {sender.name} {platform.amount} {platform.count} {platform.label} {platform.name} {platform.id} |
| `tiktok` | `follow` | un nouveau follow | - | {sender.name} {platform.label} {platform.name} {platform.id} |
| `tiktok` | `share` | un partage du live | - | {sender.name} {platform.label} {platform.name} {platform.id} |
| `tiktok` | `share_total` | des partages, total du live | `milestone`, `milestones` ou `every` (obligatoire) | {shares.palier} {shares.total} {sender.name} {platform.label} {platform.name} {platform.id} |
| `tiktok` | `sub` | un abonnement ou un Super Fan | `min` en mois d'abonnement | {sender.name} {platform.amount} {platform.label} {platform.name} {platform.id} |
| `tiktok` | `join` | arrivée dans le live | - | {sender.name} {platform.label} {platform.name} {platform.id} |

## Les blocs d'une chaîne (`do`)

Chaque bloc a un `kind` et un `id` unique dans son interaction (lettres, chiffres, `-`, `_`, 24 caractères, commence par une lettre ou un chiffre). Un bloc peut porter la suite dans `do` ; le plus simple est d'écrire les blocs à la suite dans la même liste.

| kind | Champs |
|---|---|
| `action` | `effect` (une action, voir plus bas). `holdMs` facultatif : le temps que la chaîne attend après elle (0 à 10000). `do` facultatif : la suite. |
| `delay` | `ms` : l'attente en millisecondes (0 à 10000). `do` facultatif. |
| `if` | `when` : une condition. `do` si elle est vraie, `else` sinon. |
| `switch` | `conditions` (1 à 9) et `branches` : une branche NON VIDE par condition, dans le même ordre. La PREMIÈRE condition vraie part, une seule. `else` OBLIGATOIRE et non vide. |
| `random` | `branches` (2 à 10) : UNE seule part, tirée au sort. `weights` facultatif : un entier 1 à 1000 par branche (des proportions ; le Lab écrit des pourcentages dont la somme fait 100). |
| `parallel` | `branches` (2 à 4) : TOUTES partent en même temps. Pas de `parallel` dans un `parallel`. |
| `repeat` | `times` (1 à 50) et `branches` : EXACTEMENT une branche, le corps répété. `gapMs` facultatif : la pause entre deux tours. `cases` facultatif : `[{ "when": condition, "times": N }]`, la première vraie donne le nombre de tours. Pas de `repeat` dans un `repeat`. |
| `counter` | Un compteur de la session : `name` (a-z, 0-9, _, commence par une lettre, 24 caractères), `op` : `inc`, `dec` ou `set` (`value` avec `set`). Se lit dans une condition : `"left": "counter:<name>"`. 8 compteurs par pack. |
| `var` | Pose `{var.<name>}` pour la SUITE de la chaîne (les blocs qui suivent, et leurs branches ; jamais avant). `name` comme un compteur, `value` : un texte d'une ligne (300 caractères) avec des variables. Pas de `do`. 8 par interaction. Se lit aussi dans une condition : `"left": "var:<name>"`. |

### Les conditions (`when`, `conditions`, `cases`)

`{ "all": [clauses] }` (toutes vraies) ou `{ "any": [clauses] }` (une suffit), 3 clauses au plus. Une clause : `{ "left": "coins", "op": ">=", "right": 100 }`. `op` : `==`, `!=`, `<`, `<=`, `>`, `>=`, `contains`. `right` est toujours une valeur écrite (texte, nombre, vrai ou faux), jamais une variable. `random` est un tirage de 0 à 99.

| left | Ce que c'est | Déclencheurs |
|---|---|---|
| `message` | le message | comment, platform |
| `message.suite` | la suite du message (après la commande) | comment |
| `sender` | pseudo | tous |
| `isFollower` | est abonné | tous |
| `isModerator` | est modérateur | tous |
| `quantity` | quantité | tous |
| `coins` | coins | tous |
| `name` | nom du cadeau | tous |
| `random` | tirage aléatoire | tous |
| `platform` | la plateforme | comment, platform |
| `platform.amount` | le montant (plateforme) | platform |
| `platform.gift.id` | identifiant du cadeau (plateforme) | platform |
| `platform.gift.name` | nom du cadeau (plateforme) | platform |
| `platform.count` | le nombre (plateforme) | platform |
| `hearts.palier` | le palier de likes franchi | hearts, platform |
| `counter:<nom>` | la valeur d'un compteur (bloc `counter`) | tous |
| `var:<nom>` | une variable posée plus haut (bloc `var`) | tous |

## Les actions (`effect`)

| type | Champs |
|---|---|
| `sound` | Jouer un son de la bibliothèque Hou.la : `soundId` (l'`id` d'un son de la liste exportée par Connect). `volume` 0 à 1, `interrupt: true` (coupe le son précédent du pack), `maxMs` (coupe le son au bout de N ms). Ou `localFile` : un NOM de rôle (« klaxon ») que chaque streamer relie à un fichier de SON PC, jamais un chemin. Exactement un des deux. |
| `chat` | Écrire dans le chat du live : `text` (une ligne, 300 caractères, variables admises) et `cooldownMs` OBLIGATOIRE, 2000 au moins. |
| `tts` | Lire un texte à voix haute : `text` (une ligne, 300 caractères, variables admises). `lang` (fr-FR par défaut), `voice` (nom d'une voix du système), `rate` 0,5 à 2, `volume` 0 à 100. |
| `overlay` | Piloter un overlay du streamer : `overlayId` (un overlay de SA bibliothèque : une IA ne peut pas le deviner, laisse le créateur le choisir dans le Lab), `commande` : `afficher`, `masquer`, `ajouter`, `retirer`, `fixer`, `demarrer`, `arreter`. `valeur` (entier) OBLIGATOIRE pour ajouter, retirer, fixer. `texte` avec afficher. |
| `jeu` | Agir dans un jeu par son plugin Hou.la : `jeu` (l'identifiant du plugin), `action` et `params`, pris dans la liste des plugins en fin de guide. Des valeurs écrites en clair : pas de variable. |
| `keyboard` | Appuyer sur des touches du PC : `keys`, par exemple `space`, `shift+c` (ensemble), `up,up,down` (à la suite), `space:400` (tenue 400 ms). `gapMs` facultatif. |
| `gamepad` | Une manette virtuelle Xbox : `button` (A B X Y LB RB LT RT UP DOWN LEFT RIGHT START BACK LS RS), ou `buttons` (ensemble), `sequence` (à la suite), `randomFrom` (un au hasard), `steps` (`[{ "buttons": [...], "holdMs": N, "waitMs": N }]`), `analog` (`lx`, `ly`, `rx`, `ry` de -1 à 1, `lt`, `rt` de 0 à 1). `holdMs`, `repeat` (1 à 20), `repeatGapMs` facultatifs. |
| `rcon` | Une commande au serveur de jeu : `command` (variables `{sender}`, `{quantity}`…). La connexion (`connector`, rôle `rcon` par défaut) est réglée par le streamer. |
| `obs` | Une requête à OBS : `request` (ex. `SetCurrentProgramScene`) et `params`. |
| `streamlabs` | Streamlabs Desktop : `command` (liste fermée, voir le Lab), `scene`, `source`. |
| `voicemod` | Voicemod : `command`, `voice` ou `sound` (identifiants Voicemod), `label`, `durationMs`. Aucune variable. |
| `http` | Un appel web : `method` (`GET`, `POST`, `PUT`), `url` (https) ou `path` avec un `connector`, `json` (le corps). |
| `ws` | Un message WebSocket : `message`, `url` (ws:// ou wss://) ou un `connector`. |
| `mqtt` | Un message MQTT : `topic`, `payload`, `qos`, `retain`, `connector`. |
| `osc` | Un message OSC (VRChat…) : `address`, `args`, `host`, `port`. |
| `python` | Ne pas utiliser : gardé pour d'anciens packs, absent du Lab. |

## Les variables

Dans un texte (`chat.text`, `tts.text`, `var.value`, `overlay.texte`, `rcon.command`…), `{sender.name}`, `{gift.name}`… sont remplacées au moment de jouer. Seules celles du tableau des déclencheurs ont une valeur : une variable qu'aucun déclencheur de l'interaction ne remplit reste VIDE au moment de jouer, et une variable inconnue fait refuser le pack. En plus : `{var.<nom>}` (bloc `var` plus haut), `{random}`, `{arg.1}`… (une commande à syntaxe, voir le Lab). Jamais de variable dans un identifiant (`soundId`, `overlayId`, les `params` d'un jeu, Voicemod, une scène).

## Les bornes

| Borne | Valeur |
|---|---|
| `MAX_NODE_DEPTH` | 6 |
| `MAX_PARALLEL_BRANCHES` | 4 |
| `MAX_RANDOM_BRANCHES` | 10 |
| `MAX_SWITCH_CONDITIONS` | 9 |
| `MAX_NODES_PER_RULE` | 32 |
| `MAX_NODES_PER_MANIFEST` | 1200 |
| `MAX_VAR_NODES_PER_RULE` | 8 |
| `MAX_VAR_VALUE` | 300 |
| `MAX_STARTS_WITH` | 40 |
| `MAX_CLAUSES` | 3 |
| `MAX_COUNTERS_PER_MANIFEST` | 8 |
| `MAX_DELAY_MS` | 10000 |
| `MAX_HOLD_MS` | 10000 |
| `MAX_GRAPH_BUDGET_MS` | 30000 |
| `MAX_CONTAINS` | 80 |
| `MAX_PALIER_LIKES` | 1000000000 |
| `MAX_PALIERS_LIKES` | 20 |
| `MAX_REPEAT` | 50 |
| `MAX_REPEAT_CASES` | 9 |
| `MAX_CADEAUX_PAR_ENVOI` | 20 |
| `LIKES_PAR_MESSAGE_TIKTOK` | 15 |

- La durée d'une chaîne se calcule avant de jouer (attentes, `holdMs`, tours d'un `repeat`) : 30000 ms au plus.
- Au plus 6 niveaux de blocs imbriqués, 32 blocs par interaction, 1200 dans le pack.

## Exemple complet

Un pack valide, vérifié par le validateur de Hou.la : un cadeau personnalisé « Fanfare » à 30 pièces relié aussi à la Rose de TikTok, une commande payante `/klaxon` qui tire un son au hasard, des paliers de likes, et un nouvel abonné accueilli à voix haute.

```json
{
  "schema": 3,
  "rules": [
    {
      "id": "cadeau-fanfare",
      "label": "Fanfare",
      "on": [
        {
          "type": "gift",
          "giftSlug": "ix_slot_01",
          "coinCost": 30,
          "group": "Ambiance"
        },
        {
          "type": "platform",
          "platform": "tiktok",
          "event": "gift",
          "giftId": "5655"
        }
      ],
      "do": [
        {
          "kind": "action",
          "id": "fanfare",
          "effect": {
            "type": "sound",
            "soundId": "34f7bfb4-b51f-11f1-a1b0-920007989f15",
            "volume": 0.8
          }
        },
        {
          "kind": "action",
          "id": "merci",
          "effect": {
            "type": "chat",
            "text": "Merci {sender.name} pour la fanfare !",
            "cooldownMs": 5000
          }
        }
      ]
    },
    {
      "id": "commande-klaxon",
      "label": "Klaxon",
      "on": {
        "type": "command",
        "name": "klaxon",
        "description": "Joue un klaxon au hasard",
        "coinCost": 10
      },
      "enchainement": "ignorer",
      "do": [
        {
          "kind": "random",
          "id": "tirage",
          "weights": [
            70,
            30
          ],
          "branches": [
            [
              {
                "kind": "action",
                "id": "police",
                "effect": {
                  "type": "sound",
                  "soundId": "051db1d2-b523-11f1-a1b0-920007989f15",
                  "maxMs": 3000
                }
              }
            ],
            [
              {
                "kind": "action",
                "id": "dj",
                "effect": {
                  "type": "sound",
                  "soundId": "301b847c-b529-11f1-a1b0-920007989f15"
                }
              }
            ]
          ]
        }
      ]
    },
    {
      "id": "paliers-likes",
      "label": "Paliers de likes",
      "on": {
        "type": "hearts",
        "milestones": [
          1000,
          5000,
          10000
        ]
      },
      "do": [
        {
          "kind": "var",
          "id": "retenir",
          "name": "palier",
          "value": "{hearts.palier}"
        },
        {
          "kind": "switch",
          "id": "selon-palier",
          "conditions": [
            {
              "all": [
                {
                  "left": "hearts.palier",
                  "op": ">=",
                  "right": 10000
                }
              ]
            }
          ],
          "branches": [
            [
              {
                "kind": "repeat",
                "id": "trois-wow",
                "times": 3,
                "gapMs": 800,
                "branches": [
                  [
                    {
                      "kind": "action",
                      "id": "wow",
                      "effect": {
                        "type": "sound",
                        "soundId": "2ebf44c5-b51a-11f1-a1b0-920007989f15"
                      }
                    }
                  ]
                ]
              }
            ]
          ],
          "else": [
            {
              "kind": "action",
              "id": "wow-seul",
              "effect": {
                "type": "sound",
                "soundId": "2ebf44c5-b51a-11f1-a1b0-920007989f15"
              }
            }
          ]
        },
        {
          "kind": "delay",
          "id": "pause",
          "ms": 1000
        },
        {
          "kind": "action",
          "id": "annonce",
          "effect": {
            "type": "chat",
            "text": "{var.palier} likes, merci à tous !",
            "cooldownMs": 10000
          }
        }
      ]
    },
    {
      "id": "nouvel-abonne",
      "label": "Nouvel abonné",
      "on": {
        "type": "follow"
      },
      "do": [
        {
          "kind": "counter",
          "id": "compter",
          "name": "abonnes",
          "op": "inc"
        },
        {
          "kind": "parallel",
          "id": "ensemble",
          "branches": [
            [
              {
                "kind": "action",
                "id": "voix",
                "effect": {
                  "type": "tts",
                  "text": "Bienvenue {sender.name} !"
                }
              }
            ],
            [
              {
                "kind": "action",
                "id": "roulement",
                "effect": {
                  "type": "sound",
                  "soundId": "5703a3d3-b522-11f1-a1b0-920007989f15",
                  "volume": 0.5
                }
              }
            ]
          ]
        },
        {
          "kind": "if",
          "id": "dixieme",
          "when": {
            "all": [
              {
                "left": "counter:abonnes",
                "op": "==",
                "right": 10
              }
            ]
          },
          "do": [
            {
              "kind": "action",
              "id": "dix",
              "effect": {
                "type": "chat",
                "text": "Dix nouveaux abonnés pendant ce live !",
                "cooldownMs": 5000
              }
            }
          ]
        }
      ]
    }
  ]
}
```

## Les plugins de jeu (`"type": "jeu"`)

Un pack qui pilote un jeu utilise ces actions, avec exactement ces `params`. Le streamer installe le plugin et règle la connexion dans Connect.

### Pratfall (`"jeu": "pratfall"`)

- `bombes` : Pluie de bombes. Fait apparaître des bombes devant un joueur. Params : `nombre` entier 1 à 5 (défaut 3) ; `cible` parmi `moi`, `hasard` (défaut `moi`).
- `mine` : Mine foreuse. Pose une mine qui creuse et explose devant un joueur. Params : `cible` parmi `moi`, `hasard` (défaut `moi`).
- `chauves_souris` : Nuée de chauves-souris. Lâche trois chauves-souris devant toi. Params : `espece` parmi `explosives`, `cogneuses`, `voraces` (défaut `explosives`).
- `ver` : Ver géant. Réveille le ver géant : la grotte tremble.
- `sol` : Sol piégé. Change le sol autour de toi. Params : `matiere` parmi `glace`, `lave`, `fromage`, `mousse`, `nuage` (défaut `glace`).
- `trou` : Trou sous les pieds. Creuse le sol sous un joueur. Params : `cible` parmi `moi`, `hasard` (défaut `moi`).
- `assommer` : Assommer. Le joueur s'effondre et ne contrôle plus rien pendant quelques secondes. Params : `secondes` entier 2 à 10 (défaut 4) ; `cible` parmi `moi`, `hasard` (défaut `moi`).
- `tout_lacher` : Tout lâcher. Le joueur lâche tout son inventaire. Params : `cible` parmi `moi`, `hasard` (défaut `moi`).
- `esquimau` : Esquimau gelé. Colle au joueur la malédiction de l'esquimau pendant une minute. Params : `cible` parmi `moi`, `hasard` (défaut `moi`).
- `tuer` : Coup fatal. Met un joueur K.-O. : ses coéquipiers doivent le ranimer. Params : `cible` parmi `moi`, `hasard` (défaut `moi`).
- `klaxon` : Klaxon. Ton personnage klaxonne.
- `soigner` : Soin. Rend toute ta vie (rien ne se passe si elle est déjà pleine).
- `ressusciter` : Résurrection. Ramène un joueur mort à la vie. Params : `cible` parmi `moi`, `hasard` (défaut `hasard`).
- `colis` : Colis surprise. Fait apparaître un colis à ouvrir devant toi. Params : `rarete` parmi `normal`, `rare` (défaut `normal`).
- `nourriture` : Casse-croûte. Te met de la nourriture dans les mains.
- `or` : Pluie d'or. Fait tomber des pièces d'or autour de toi, à ramasser. Params : `pieces` entier 5 à 30 (défaut 10).

### Minecraft (`"jeu": "minecraft"`)

- `donner` : Donner un objet. Met un objet dans l'inventaire. Params : `objet` parmi `torch`, `bread`, `apple`, `iron_pickaxe`, `iron_sword`, `iron_axe`, `shield`, `bow`, `arrow`, `iron_ingot`, `copper_ingot`, `coal`, `cooked_beef`, `iron_helmet`, `iron_boots`, `gold_ingot`, `diamond_helmet`, `diamond_chestplate`, `diamond_leggings`, `diamond_boots`, `diamond_sword`, `diamond_pickaxe`, `golden_apple`, `enchanted_golden_apple`, `ender_pearl`, `elytra`, `totem_of_undying`, `wheat_seeds`, `beetroot_seeds`, `pumpkin_seeds`, `melon_seeds`, `carrot`, `potato`, `sugar_cane`, `cocoa_beans`, `wheat`, `beetroot`, `pumpkin`, `melon`, `shears`, `iron_hoe`, `water_bucket`, `bone_meal`, `composter`, `hay_block`, `beehive`, `diamond_hoe`, `oak_log`, `diamond`, `emerald`, `diamond_block`, `netherite_ingot`, `netherite_block` (défaut `diamond`) ; `quantite` entier 1 à 64 (défaut 1) ; `qui` parmi `joueur`, `tous` (défaut `joueur`).
- `invoquer` : Faire apparaître une créature. Une créature (ou de la TNT, un éclair) apparaît près du joueur. Params : `creature` parmi `zombie`, `spider`, `slime`, `skeleton`, `cave_spider`, `silverfish`, `witch`, `creeper`, `husk`, `lightning_bolt`, `drowned`, `blaze`, `tnt`, `enderman`, `vindicator`, `pillager`, `wither_skeleton`, `ravager`, `piglin_brute`, `evoker`, `wither`, `ender_dragon`, `warden`, `chicken`, `pig`, `sheep`, `cow`, `rabbit`, `bee`, `mooshroom`, `iron_golem` (défaut `zombie`) ; `position` parmi `sur`, `devant_2`, `devant_3`, `devant_4`, `cote`, `dessus_15`, `dessus_35` (défaut `sur`) ; `qui` parmi `joueur`, `tous` (défaut `joueur`).
- `effet` : Appliquer un effet. Un effet de potion pendant quelques secondes. Params : `effet` parmi `poison`, `blindness`, `nausea`, `slowness`, `weakness`, `hunger`, `regeneration`, `fire_resistance`, `strength`, `speed`, `levitation` (défaut `speed`) ; `secondes` entier 1 à 600 (défaut 20) ; `niveau` entier 0 à 9 (défaut 0) ; `qui` parmi `joueur`, `tous` (défaut `joueur`).
- `heure` : Changer l'heure. Le jour ou la nuit, tout de suite. Params : `moment` parmi `jour`, `nuit`, `midi`, `minuit` (défaut `jour`).
- `meteo` : Changer la météo. Orage, pluie ou grand beau. Params : `temps` parmi `orage`, `pluie`, `clair` (défaut `orage`).
- `annonce` : Annoncer le cadeau dans le chat du jeu. « [pseudo] a offert <cadeau> ! » dans le chat de Minecraft.
- `villageois_fermier` : Villageois fermier. Un villageois fermier (niveau 2) apparaît. Params : `qui` parmi `joueur`, `tous` (défaut `joueur`).
- `houe_enchantee` : Houe en diamant Fortune III. Une houe en diamant enchantée Fortune III et Solidité III. Params : `qui` parmi `joueur`, `tous` (défaut `joueur`).

### ARK: Survival Evolved (`"jeu": "ark-survival-evolved"`)

- `donner` : Donner un objet. Met un objet dans l'inventaire du joueur (identifiant de joueur requis). Params : `objet` parmi `viande`, `soin`, `stimulant`, `narcotique`, `parachute`, `lingot`, `cristal`, `polymere`, `pique`, `epee`, `pistolet`, `fusil`, `grenade`, `grappin` (défaut `viande`) ; `quantite` entier 1 à 100 (défaut 1).
- `experience` : Donner de l'expérience. De l'expérience pour le joueur seul (identifiant de joueur requis). Params : `points` entier 1 à 100000 (défaut 1000).
- `heure` : Changer l'heure. Règle l'horloge du monde. Params : `moment` parmi `aube`, `midi`, `soir`, `minuit` (défaut `midi`).
- `vitesse` : Ralenti ou accéléré. Change la vitesse de tout le serveur. Pense à une règle qui remet la vitesse normale. Params : `vitesse` parmi `ralenti`, `normal`, `rapide` (défaut `ralenti`).
- `bandeau` : Message en grand à l'écran. « [pseudo] a offert <cadeau> ! » affiché en grand à tous les joueurs.
- `annonce` : Annoncer le cadeau dans le chat du jeu. « [pseudo] a offert <cadeau> ! » dans le chat du jeu.

### Counter-Strike 2 (`"jeu": "counter-strike-2"`)

- `gravite` : Changer la gravité (triche). Gravité lunaire ou écrasante (800 = normale). Demande sv_cheats 1, qui coupe les statistiques et les succès Steam de tous les joueurs. Params : `gravite` entier 100 à 2000 (défaut 200).
- `bunny_hop` : Bunny hop. Sauts enchaînés automatiquement et vitesse non plafonnée. Params : `etat` parmi `oui`, `non` (défaut `oui`).
- `tir_ami` : Tir ami. Les coéquipiers peuvent se blesser entre eux. Params : `etat` parmi `oui`, `non` (défaut `oui`).
- `tous_ennemis` : Tous contre tous. Les coéquipiers deviennent des ennemis. Params : `etat` parmi `oui`, `non` (défaut `oui`).
- `headshot` : Tirs à la tête seulement. Seuls les tirs à la tête font des dégâts. Params : `etat` parmi `oui`, `non` (défaut `oui`).
- `achat_partout` : Acheter partout. Les joueurs peuvent acheter hors de la zone d'achat. Params : `camp` parmi `non`, `tous`, `t`, `ct` (défaut `tous`).
- `bot` : Ajouter un bot. Un bot rejoint une équipe. Params : `camp` parmi `t`, `ct` (défaut `t`).
- `relancer` : Relancer la partie. La partie redémarre après quelques secondes. Params : `secondes` entier 1 à 10 (défaut 3).
- `annonce` : Annoncer le cadeau dans le chat du jeu. « [pseudo] a offert <cadeau> ! » dans le chat du jeu.

### Factorio (`"jeu": "factorio"`)

- `donner` : Donner un objet. Met un objet dans l'inventaire du joueur. Params : `objet` parmi `iron-plate`, `copper-plate`, `steel-plate`, `coal`, `stone`, `wood`, `iron-gear-wheel`, `electronic-circuit`, `advanced-circuit`, `solid-fuel`, `raw-fish`, `firearm-magazine`, `piercing-rounds-magazine`, `submachine-gun`, `grenade`, `gun-turret`, `defender-capsule`, `construction-robot`, `heavy-armor`, `modular-armor`, `car`, `tank` (défaut `iron-plate`) ; `quantite` entier 1 à 200 (défaut 10).
- `ennemis` : Lâcher des ennemis. Des biters ou des spitters apparaissent près du joueur. Params : `creature` parmi `small-biter`, `medium-biter`, `big-biter`, `behemoth-biter`, `small-spitter`, `medium-spitter`, `big-spitter` (défaut `small-biter`) ; `nombre` entier 1 à 10 (défaut 3).
- `jour` : Jour sans fin. Le soleil ne se couche plus, ou revient au cycle normal. Params : `etat` parmi `oui`, `non` (défaut `oui`).
- `annonce` : Annoncer le cadeau dans le chat du jeu. « [pseudo] a offert <cadeau> ! » dans le chat du jeu.

### Left 4 Dead 2 (`"jeu": "left-4-dead-2"`)

- `infecte` : Faire apparaître un infecté (triche). Un infecté spécial, une Witch ou une horde apparaît dans la carte. Demande sv_cheats 1. Params : `infecte` parmi `tank`, `witch`, `boomer`, `smoker`, `hunter`, `spitter`, `jockey`, `charger`, `mob` (défaut `boomer`).
- `panique` : Événement de panique (triche). Le directeur lance une vague de zombies. Demande sv_cheats 1.
- `munitions` : Munitions infinies (triche). L'arme active ne se vide plus. Demande sv_cheats 1. Params : `etat` parmi `oui`, `non` (défaut `oui`).
- `difficulte` : Changer la difficulté. La difficulté de la partie en cours. Params : `niveau` parmi `easy`, `normal`, `hard`, `impossible` (défaut `hard`).
- `gravite` : Changer la gravité. Gravité lunaire ou écrasante (800 = normale). Params : `gravite` entier 100 à 2000 (défaut 300).
- `annonce` : Annoncer le cadeau dans le chat du jeu. « [pseudo] a offert <cadeau> ! » dans le chat du jeu.

### Project Zomboid (`"jeu": "project-zomboid"`)

- `donner` : Donner un objet. Met un objet dans l'inventaire du joueur. Params : `objet` parmi `axe`, `crowbar`, `baseball_bat`, `katana`, `sledgehammer`, `hunting_knife`, `pan`, `pistol`, `bullets9mm_box`, `shotgun`, `shotgun_shells_box`, `molotov`, `bandage`, `pills`, `first_aid_kit`, `crisps`, `tinned_soup` (défaut `bandage`) ; `quantite` entier 1 à 20 (défaut 1).
- `horde` : Faire venir une horde. Des zombies apparaissent près du joueur. Params : `nombre` entier 1 à 200 (défaut 10).
- `helicoptere` : L'hélicoptère. L'événement de l'hélicoptère, sur un joueur au hasard : il attire les zombies.
- `coup_de_feu` : Coup de feu. Un bruit de coup de feu sur un joueur au hasard : les zombies accourent.
- `orage` : Éclair ou tonnerre. Un éclair ou un coup de tonnerre sur le joueur. Params : `type` parmi `lightning`, `thunder` (défaut `lightning`).
- `pluie` : Faire pleuvoir. La pluie tombe sur tout le serveur. Params : `intensite` entier 1 à 100 (défaut 50).
- `tempete` : Tempête. Une tempête, pour quelques heures de jeu. Params : `heures` entier 1 à 24 (défaut 2).
- `beau_temps` : Arrêter la météo. Plus de pluie ni de tempête.
- `vehicule` : Une ambulance. Une ambulance apparaît près du joueur.
- `annonce` : Annoncer le cadeau sur le serveur. « [pseudo] a offert <cadeau> ! » affiché à tous les joueurs.

### Rust (`"jeu": "rust"`)

- `donner` : Donner un objet. Met un objet dans l'inventaire du joueur. Params : `objet` parmi `wood`, `stones`, `metal_fragments`, `metal_refined`, `sulfur`, `scrap`, `lowgradefuel`, `apple`, `bandage`, `syringe_medical`, `largemedkit`, `hatchet`, `pickaxe`, `spear_wooden`, `bow_hunting`, `arrow_wooden`, `crossbow`, `pistol_revolver`, `pistol_semiauto`, `ammo_pistol`, `rifle_ak`, `ammo_rifle`, `hazmatsuit`, `grenade_f1`, `supply_signal`, `explosive_timed`, `rocket_launcher`, `ammo_rocket_basic` (défaut `scrap`) ; `quantite` entier 1 à 1000 (défaut 1).
- `annonce` : Annoncer le cadeau dans le chat du jeu. « [pseudo] a offert <cadeau> ! » dans le chat du jeu.
- `heure` : Changer l'heure. Règle l'horloge du monde (0 = minuit, 12 = midi). Params : `heure` entier 0 à 23 (défaut 12).
- `meteo` : Changer la météo. Pluie, brouillard ou vent, avec une intensité. Params : `type` parmi `rain`, `fog`, `wind` (défaut `rain`) ; `intensite` parmi `nulle`, `moyenne`, `forte` (défaut `forte`).
- `helicoptere` : Appeler l'hélicoptère de patrouille. L'hélicoptère d'attaque part en patrouille sur la carte.

### Squad (`"jeu": "squad"`)

- `annonce` : Annoncer le cadeau à tout le serveur. « [pseudo] a offert <cadeau> ! » en message système.
- `avertir` : Message privé au streamer. Un avertissement à l'écran, pour toi seul.
- `changer_equipe` : Changer d'équipe. Te fait passer dans l'autre équipe.
- `vitesse` : Ralenti ou accéléré. Change la vitesse de tout le serveur. Pense à une règle qui remet la vitesse normale. Params : `vitesse` parmi `ralenti`, `normal`, `rapide` (défaut `ralenti`).

### Team Fortress 2 (`"jeu": "team-fortress-2"`)

- `bots` : Ajouter des bots. Des joueurs contrôlés par l'ordinateur rejoignent la partie. Params : `nombre` entier 1 à 6 (défaut 1).
- `gravite` : Changer la gravité. Gravité lunaire ou écrasante (800 = normale). Params : `gravite` entier 100 à 2000 (défaut 200).
- `fete` : Forcer une fête. Anniversaire, Halloween, Noël ou pleine lune sur le serveur. Params : `fete` parmi `aucune`, `anniversaire`, `halloween`, `noel`, `pleine_lune` (défaut `halloween`).
- `critiques` : Coups critiques aléatoires. Active ou coupe les critiques aléatoires. Params : `etat` parmi `oui`, `non` (défaut `oui`).
- `tir_ami` : Tir ami. Les coéquipiers peuvent se blesser entre eux. Params : `etat` parmi `oui`, `non` (défaut `oui`).
- `relancer` : Relancer la manche. La manche redémarre après quelques secondes. Params : `secondes` entier 1 à 10 (défaut 3).
- `annonce` : Annoncer le cadeau dans le chat du jeu. « [pseudo] a offert <cadeau> ! » dans le chat du jeu.

### Tomb Raider I-III Remastered (`"jeu": "tomb-raider-remastered"`)

- `small_medkit` : Soins : petite trousse de soins. Donne une petite trousse de soins à Lara.
- `large_medkit` : Soins : grande trousse de soins. Donne une grande trousse de soins à Lara.
- `fusil` : Arme : fusil à pompe. Donne le fusil à pompe à Lara.
- `magnums` : Arme : Magnums. Donne les Magnums à Lara.
- `uzis` : Arme : Uzis. Donne les Uzis à Lara.
- `shotgun_ammo` : Munitions : cartouches de fusil à pompe. Donne des cartouches de fusil à pompe.
- `magnum_ammo` : Munitions : balles de Magnums. Donne des munitions de Magnums.
- `uzi_ammo` : Munitions : balles d'Uzis. Donne des munitions d'Uzis.
- `bat` : Ennemi : chauve-souris. Fait apparaître l'ennemi « chauve-souris ».
- `rat` : Ennemi : rat. Fait apparaître l'ennemi « rat ».
- `wolf` : Ennemi : loup. Fait apparaître l'ennemi « loup ».
- `bear` : Ennemi : ours. Fait apparaître l'ennemi « ours ».
- `crocodile` : Ennemi : crocodile. Fait apparaître l'ennemi « crocodile ».
- `raptor` : Ennemi : raptor. Fait apparaître l'ennemi « raptor ».
- `gorilla` : Ennemi : gorille. Fait apparaître l'ennemi « gorille ».
- `lioness` : Ennemi : lionne. Fait apparaître l'ennemi « lionne ».
- `lion` : Ennemi : lion. Fait apparaître l'ennemi « lion ».
- `panther` : Ennemi : panthère. Fait apparaître l'ennemi « panthère ».
- `trex` : Ennemi : T-Rex. Fait apparaître l'ennemi « T-Rex ».
- `grounded_atlantean_variant` : Ennemi : mutant atlante au sol. Fait apparaître l'ennemi « mutant atlante au sol ».
- `flying_atlantean_variant` : Ennemi : mutant atlante ailé. Fait apparaître l'ennemi « mutant atlante ailé ».
- `centaur` : Ennemi : centaure. Fait apparaître l'ennemi « centaure ».
- `larson` : Ennemi : Larson. Fait apparaître l'ennemi « Larson ».
- `pierre` : Ennemi : Pierre Dupont. Fait apparaître l'ennemi « Pierre Dupont ».
- `skate_kid` : Ennemi : le Kid au skate. Fait apparaître l'ennemi « le Kid au skate ».
- `cowboy` : Ennemi : le Cowboy. Fait apparaître l'ennemi « le Cowboy ».
- `kold` : Ennemi : Kold. Fait apparaître l'ennemi « Kold ».
- `torso` : Ennemi : le Torse (Adam). Fait apparaître l'ennemi « le Torse (Adam) ».
- `natla` : Ennemi : Natla. Fait apparaître l'ennemi « Natla ».
- `explode_lara` : Effet : Lara explose. Fait exploser Lara, comme dans le jeu.
