Hou.la Connect · Développeurs
Relie ton jeu, ton outil ou ton matériel à Hou.la Connect
Ce que Connect sait piloter, comment écrire le plugin d'un jeu, le format d'un pack, et ce qu'un plugin ne peut pas faire. Chaque exemple de cette page passe le validateur de Hou.la.
Le principe
Trois pièces, trois rôles
Un spectateur agit ; Connect, sur le PC du streamer, décide quoi faire et le fait. Un pack et un plugin sont des fichiers JSON : Connect n'exécute jamais le code de leur auteur.
Le pack : quand, alors
Il dit quand agir (un cadeau, un like, une commande de chat, sur Hou.la, TikTok, YouTube ou Kick) et quoi faire (un son, une scène OBS, une action de jeu…). N'importe quel créateur l'écrit dans le Lab de Connect.
Le plugin : ce qu'un jeu sait faire
Il décrit un jeu, ses actions et leurs réglages, et comment le joindre : un mod, RCON, WebSocket ou HTTP. Un par jeu, partagé par tous les packs de ce jeu.
La connexion : l'adresse chez le streamer
L'adresse, le port, le mot de passe ou le jeton, saisis par le streamer dans « Mes plugins ». Ils restent sur son PC : un pack ne contient jamais d'identifiants, il demande une connexion par son rôle.
Tout se passe sur le PC du streamer. Connect revérifie chaque réglage avant de l'envoyer.
Les actions
Ce que Connect sait piloter
Quinze sortes d'actions, chacune jouée par un exécuteur de Connect. Un pack n'en invente pas : il choisit dans cette liste, et un type inconnu fait refuser le pack.
| Action | type | Ce que ça fait, et ses limites |
|---|---|---|
| Action de jeu | jeu | Une action d'un plugin de jeu, avec ses réglages écrits en clair (jamais une variable). Voir « Créer le plugin d'un jeu ». |
| Clavier | keyboard | Touches, combinaisons (shift+c), suites (up,up,down), maintien (space:400). Le jeu doit être au premier plan. Désactivé par défaut : le streamer l'allume dans « Mes plugins ». |
| Manette virtuelle | gamepad | Une manette Xbox virtuelle : boutons, sticks, gâchettes, séquences. Windows seulement (pilote ViGEmBus). Désactivée par défaut. |
| OBS Studio | obs | Une requête d'OBS WebSocket v5 prise dans une liste fermée : scène, sources, filtres, micro, médias, transitions, enregistrement, replay, caméra virtuelle. Jamais démarrer ni couper le stream. |
| Streamlabs Desktop | streamlabs | Une commande d'une liste fermée : scènes, sources, son, enregistrement, replay. Jamais démarrer le stream. |
| Overlay | overlay | Piloter un overlay du streamer : afficher, masquer, ajouter, retirer, fixer, démarrer, arrêter. L'overlay est choisi par le streamer dans sa bibliothèque. |
| Son | sound | Un son de la bibliothèque Hou.la, par son identifiant, ou un fichier du PC désigné par un rôle que le streamer relie (jamais un chemin). Volume, coupure du son précédent, durée maximale. |
| Voix de synthèse | tts | Lire un texte à voix haute avec une voix du système, 300 caractères au plus. |
| Voicemod | voicemod | Changer de voix, jouer un son de la soundboard. Voicemod doit être lancé (Windows). |
| Chat | chat | Écrire dans le chat Hou.la du live, avec au moins 2 secondes entre deux messages. |
| RCON | rcon | Une commande à un serveur de jeu (Minecraft, Rust, ARK…). Les verbes destructeurs (stop, ban, op, whitelist…) sont refusés. |
| HTTP | http | Une requête GET, POST ou PUT. Par une connexion du streamer : son adresse, même locale (http://127.0.0.1:…), son jeton, et la réponse est lue ({reponse.…}). Par une adresse écrite dans le pack : jamais ce PC ni le réseau local, ni jeton, ni redirection, et la réponse n'est pas lue. 5 secondes au plus. |
| WebSocket | ws | Un message texte, par une connexion du streamer ou une adresse écrite dans le pack (mêmes règles que HTTP pour ce PC et le réseau local). |
| MQTT | mqtt | Un message sur un topic, vers le courtier de la connexion du streamer (domotique, Zigbee2MQTT, Tasmota…). |
| OSC | osc | Un message OSC en UDP (VRChat, TouchDesigner, Resolume), par défaut vers 127.0.0.1:9000. UDP ne confirme rien : réussi veut dire envoyé. |
Les plugins de jeu officiels
Livrés avec Connect, au même format que ceux de la communauté. Sers-t'en dans tes packs tels quels, ou lis-les comme exemples.
| Jeu | id | Mode | Actions |
|---|---|---|---|
| Pratfall | pratfall | mod | 16 actions |
| Minecraft | minecraft | rcon | 8 actions |
| ARK: Survival Evolved | ark-survival-evolved | rcon | 6 actions |
| Counter-Strike 2 | counter-strike-2 | rcon | 9 actions |
| Factorio | factorio | rcon | 4 actions |
| Left 4 Dead 2 | left-4-dead-2 | rcon | 6 actions |
| Project Zomboid | project-zomboid | rcon | 10 actions |
| Rust | rust | rcon | 5 actions |
| Squad | squad | rcon | 4 actions |
| Team Fortress 2 | team-fortress-2 | rcon | 7 actions |
| Tomb Raider I-III Remastered | tomb-raider-remastered | http | 30 actions |
Et un logiciel, un objet connecté ?
Connect a des plugins officiels génériques (HTTP, WebSocket, MQTT, OSC, RCON, OBS, Streamlabs) et des plugins prêts à l'emploi (Home Assistant, Elgato Key Light, Discord, Telegram, webhook) : un pack y envoie ses requêtes par la connexion du streamer. « + Créer un plugin », « Un logiciel ou un objet connecté » publie un descripteur (protocole, champs, commandes), mais installé depuis le Store, ce type de plugin ne se configure pas encore dans Connect. Pour piloter ton programme aujourd'hui, le plus direct est un plugin de jeu en mode http ou ws, qui fonctionne de bout en bout.
Plugin de jeu
Créer le plugin de ton jeu
Un plugin de jeu est une fiche JSON : le jeu, ses actions, leurs réglages, et le mode de liaison. Tu n'écris aucun code côté Connect ; le seul code éventuel est le mod de ton jeu.
Quatre façons de joindre un jeu
Un mod dans le jeu
"mode": "mod"
Pour un jeu sans serveur que tu peux moder. Ton mod se relie tout seul à Connect par le pont local. Hou.la héberge l'archive du mod, et Connect l'installe dans le dossier du jeu, trouvé par Steam.
Plugins officiels dans ce mode : 1
Le serveur du jeu, par RCON
"mode": "rcon"
Pour un jeu à serveur qui accepte des commandes. Chaque action envoie 1 à 5 commandes, jouées dans l'ordre. Le streamer saisit l'hôte, le port, le mot de passe et son pseudo en jeu.
Plugins officiels dans ce mode : 9
Un WebSocket local
"mode": "ws"
Pour un jeu ou un outil qui écoute déjà un WebSocket. Chaque action envoie un message (2 000 caractères au plus). Le streamer saisit l'adresse.
Plugins officiels dans ce mode : 0
Une API HTTP locale
"mode": "http"
Pour un jeu ou un outil qui expose une API HTTP. Chaque action est une requête GET, POST ou PUT sur un chemin, avec un corps JSON facultatif. Le streamer saisit l'adresse de base et, si besoin, un jeton.
Plugins officiels dans ce mode : 1
Pas à pas, dans Connect
Ouvre l'assistant
« Mes plugins », « + Créer un plugin », « Un jeu ». Ou depuis un pack : dans le Lab, bloc « Dans le jeu », « Mon jeu n'est pas dans la liste », « Créer le plugin de mon jeu ». Si ton mod tourne déjà, ton jeu est proposé « relié en développement » et l'assistant reprend les actions qu'il annonce.
Le jeu
Nom, identifiant (minuscules, chiffres et tirets, 2 à 40 caractères, le même que dans ton mod), numéro Steam et description. Le numéro Steam est facultatif, mais sans lui Connect ne trouve pas le dossier où installer un mod.
La liaison
Un mod, RCON, WebSocket ou HTTP. Tu n'écris pas les champs de connexion : ils viennent du mode, et le streamer retrouve le formulaire qu'il connaît.
Les actions
Pour chacune : un nom (en français, en anglais si tu veux), une description, un effet (aide, gêne ou neutre) et jusqu'à 8 réglages (un entier borné, ou un choix dans une liste). 60 actions au plus. En RCON, WebSocket et HTTP, écris le modèle de la commande, du message ou de la requête.
Le mod (mode mod)
Moteur, dossier d'installation relatif au dossier du jeu (3 niveaux au plus, sans
..), version (1.0.0), prérequis, puis l'archive.zip(100 Mo au plus), envoyée à Hou.la qui l'héberge et en calcule l'empreinte.Teste, puis publie
« Pour moi, pour tester » : le plugin s'installe tout de suite sur ton PC, pour tes packs privés. Dans un pack, « Tester » joue l'action pour de vrai, sans être en live. Puis « Pour tout le monde » : une personne de l'équipe Hou.la le relit avant le Store. L'onglet JSON de l'assistant importe et exporte le fichier.
Le format, champ par champ
Le validateur est fermé : une clé inconnue fait refuser le plugin. Un libellé peut être une simple chaîne, ou un objet { "fr": "…", "en": "…" }.
| Clé | Règle |
|---|---|
id | Identifiant du plugin : ^[a-z0-9][a-z0-9-]{1,39}$. Unique dans le Store, et le même que celui que ton mod annonce. |
nom | Nom du jeu, 60 caractères au plus. |
protocole | Toujours "jeu". |
description | Facultative, 400 caractères au plus. Dis ce qu'il faut installer ou lancer. |
jeu.steamAppId | Facultatif : le numéro de la page Steam du jeu (store.steampowered.com/app/4244510/… donne 4244510). Sans lui, Connect ne peut pas installer de mod. |
mode | mod, rcon, ws ou http. |
mod | Mode mod seulement : moteur (godot, unity, lua, autre), dossier, version, prerequis. Le bloc fichier (adresse, empreinte, taille) est rempli par Hou.la quand l'assistant envoie l'archive. |
actions[].id | Identifiant de l'action : a-z, 0-9, _ et -, 40 caractères au plus. |
actions[].libelle | Nom de l'action, 80 caractères au plus. |
actions[].description | Facultative, 300 caractères au plus. |
actions[].effet | aide, gene ou neutre (par défaut). Le Lab l'écrit à côté de l'action. |
actions[].params | 8 au plus. entier : min, max, defaut. choix : valeurs (60 au plus) et defaut ; une valeur peut porter une valeur, substituée dans le modèle à la place de son identifiant (pas en mode mod, où le mod reçoit l'identifiant). |
actions[].commandes | Mode rcon : 1 à 5 commandes, une ligne chacune, 500 caractères au plus. |
actions[].message | Mode ws : le message, 2 000 caractères au plus. |
actions[].method / path / json | Mode http : method (GET, POST, PUT), path ajouté à l'adresse de la connexion (commence par /, sans ..), json facultatif (un objet, 2 000 caractères au plus). |
Ce qu'un modèle peut contenir
{param.<réglage>} : la valeur d'un réglage de l'action. {player} et les autres champs non secrets de la connexion : un mot de passe ou un jeton n'entre jamais dans une commande. Les données de l'événement : {sender.name} (le pseudo du spectateur), {gift.name}, {gift.quantity}… Chaque valeur est échappée selon sa destination (adresse, JSON, texte).
Un exemple par mode
Chacun passe le vrai validateur de Hou.la. Importe-le dans l'assistant (onglet JSON) pour partir de là.
plugin-mode-mod.jsonUn mod dans le jeu
Les actions ne portent pas de modèle : le mod reçoit l'identifiant de l'action et ses réglages.
{
"id": "mon-jeu-godot",
"nom": "Mon jeu Godot",
"protocole": "jeu",
"mode": "mod",
"description": "Exemple : un jeu Godot 4 .NET piloté par un mod qui se relie à Hou.la Connect.",
"actions": [
{
"id": "ralenti",
"libelle": {
"fr": "Ralenti",
"en": "Slow motion"
},
"description": {
"fr": "Le jeu tourne au ralenti quelques secondes.",
"en": "The game runs in slow motion for a few seconds."
},
"effet": "gene",
"params": [
{
"id": "secondes",
"type": "entier",
"min": 1,
"max": 10,
"defaut": 3,
"libelle": {
"fr": "Durée (secondes)",
"en": "Duration (seconds)"
}
}
]
},
{
"id": "soigner",
"libelle": {
"fr": "Soigner",
"en": "Heal"
},
"effet": "aide",
"params": [
{
"id": "cible",
"type": "choix",
"defaut": "moi",
"libelle": {
"fr": "Qui",
"en": "Who"
},
"valeurs": [
{
"id": "moi",
"libelle": {
"fr": "Le streamer",
"en": "The streamer"
}
},
{
"id": "tous",
"libelle": {
"fr": "Tout le monde",
"en": "Everyone"
}
}
]
}
]
}
],
"mod": {
"moteur": "godot",
"dossier": "mods/MonMod",
"version": "1.0.0",
"prerequis": {
"fr": "Aucun : le jeu charge les mods de son dossier mods.",
"en": "None: the game loads mods from its mods folder."
}
}
}Télécharger ce fichierplugin-mode-rcon.jsonLe serveur du jeu, par RCON
{param.valeur} est remplacé par le réglage choisi dans le pack ; {sender.name} et {gift.name} par l'événement.
{
"id": "mon-serveur-rcon",
"nom": "Mon serveur RCON",
"protocole": "jeu",
"mode": "rcon",
"description": "Exemple : un jeu à serveur dédié qui accepte des commandes RCON.",
"actions": [
{
"id": "gravite",
"libelle": {
"fr": "Changer la gravité",
"en": "Change gravity"
},
"effet": "neutre",
"params": [
{
"id": "valeur",
"type": "entier",
"min": 100,
"max": 2000,
"defaut": 200,
"libelle": {
"fr": "Gravité (800 = normale)",
"en": "Gravity (800 = normal)"
}
}
],
"commandes": [
"sv_gravity {param.valeur}"
]
},
{
"id": "annonce",
"libelle": {
"fr": "Annonce",
"en": "Announcement"
},
"effet": "neutre",
"commandes": [
"say {sender.name} a offert {gift.name} !"
]
}
]
}Télécharger ce fichierplugin-mode-ws.jsonUn WebSocket local
Le message est du texte, ici du JSON. Pour un choix, la valeur (goblin) remplace le réglage, pas son identifiant.
{
"id": "mon-jeu-websocket",
"nom": "Mon jeu WebSocket",
"protocole": "jeu",
"mode": "ws",
"description": "Exemple : un jeu qui écoute déjà un WebSocket sur ce PC (son adresse se saisit dans la connexion, par exemple ws://127.0.0.1:8123).",
"actions": [
{
"id": "ennemis",
"libelle": {
"fr": "Faire apparaître des ennemis",
"en": "Spawn enemies"
},
"effet": "gene",
"params": [
{
"id": "nombre",
"type": "entier",
"min": 1,
"max": 10,
"defaut": 3,
"libelle": {
"fr": "Nombre",
"en": "Count"
}
},
{
"id": "type",
"type": "choix",
"defaut": "petit",
"libelle": {
"fr": "Type",
"en": "Type"
},
"valeurs": [
{
"id": "petit",
"libelle": {
"fr": "Petits",
"en": "Small"
},
"valeur": "goblin"
},
{
"id": "gros",
"libelle": {
"fr": "Gros",
"en": "Big"
},
"valeur": "troll"
}
]
}
],
"message": "{\"action\":\"spawn\",\"enemy\":\"{param.type}\",\"count\":{param.nombre},\"by\":\"{sender.name}\"}"
}
]
}Télécharger ce fichierplugin-mode-http.jsonUne API HTTP locale
L'architecture d'un outil compagnon : un chemin par action, un corps JSON facultatif.
{
"id": "mon-outil-compagnon",
"nom": "Mon outil compagnon",
"protocole": "jeu",
"mode": "http",
"description": "Exemple : un programme que le joueur lance à côté du jeu, et qui expose une API HTTP locale (son adresse se saisit dans « URL de base », par exemple http://127.0.0.1:7777).",
"actions": [
{
"id": "soin",
"libelle": {
"fr": "Soins : trousse",
"en": "Health: medipack"
},
"effet": "aide",
"method": "POST",
"path": "/actions/soin"
},
{
"id": "ennemi",
"libelle": {
"fr": "Ennemi : au choix",
"en": "Enemy: pick one"
},
"effet": "gene",
"params": [
{
"id": "quoi",
"type": "choix",
"defaut": "loup",
"libelle": {
"fr": "Ennemi",
"en": "Enemy"
},
"valeurs": [
{
"id": "loup",
"libelle": {
"fr": "Loup",
"en": "Wolf"
}
},
{
"id": "ours",
"libelle": {
"fr": "Ours",
"en": "Bear"
}
}
]
}
],
"method": "POST",
"path": "/actions/ennemi",
"json": {
"type": "{param.quoi}",
"de": "{sender.name}"
}
}
]
}Télécharger ce fichierTrois plugins officiels, en extrait
Pratfall (mod), Counter-Strike 2 (RCON) et Tomb Raider I-III Remastered (HTTP) : l'en-tête et les deux premières actions, tels que Connect les charge.
pratfallPratfall · mod · 16 actions
{
"id": "pratfall",
"nom": "Pratfall",
"protocole": "jeu",
"mode": "mod",
"jeu": {
"steamAppId": 4244510
},
"actions": [
{
"id": "bombes",
"libelle": {
"fr": "Pluie de bombes",
"en": "Bomb rain"
},
"effet": "gene",
"params": [
{
"id": "nombre",
"type": "entier",
"libelle": {
"fr": "Nombre de bombes",
"en": "Number of bombs"
},
"min": 1,
"max": 5,
"defaut": 3
},
{
"id": "cible",
"type": "choix",
"libelle": {
"fr": "Qui",
"en": "Who"
},
"defaut": "moi",
"valeurs": [
{
"id": "moi",
"libelle": {
"fr": "Toi",
"en": "You"
}
},
{
"id": "hasard",
"libelle": {
"fr": "Un joueur au hasard",
"en": "A random player"
}
}
]
}
]
},
{
"id": "mine",
"libelle": {
"fr": "Mine foreuse",
"en": "Digging mine"
},
"effet": "gene",
"params": [
{
"id": "cible",
"type": "choix",
"libelle": {
"fr": "Qui",
"en": "Who"
},
"defaut": "moi",
"valeurs": [
{
"id": "moi",
"libelle": {
"fr": "Toi",
"en": "You"
}
},
{
"id": "hasard",
"libelle": {
"fr": "Un joueur au hasard",
"en": "A random player"
}
}
]
}
]
}
]
}counter-strike-2Counter-Strike 2 · rcon · 9 actions
{
"id": "counter-strike-2",
"nom": "Counter-Strike 2",
"protocole": "jeu",
"mode": "rcon",
"jeu": {
"steamAppId": 730
},
"actions": [
{
"id": "gravite",
"libelle": {
"fr": "Changer la gravité (triche)",
"en": "Change gravity (cheat)"
},
"effet": "neutre",
"params": [
{
"id": "gravite",
"type": "entier",
"libelle": {
"fr": "Gravité (800 = normale)",
"en": "Gravity (800 = normal)"
},
"min": 100,
"max": 2000,
"defaut": 200
}
],
"commandes": [
"sv_gravity {param.gravite}"
]
},
{
"id": "bunny_hop",
"libelle": {
"fr": "Bunny hop",
"en": "Bunny hop"
},
"effet": "aide",
"params": [
{
"id": "etat",
"type": "choix",
"libelle": {
"fr": "État",
"en": "State"
},
"defaut": "oui",
"valeurs": [
{
"id": "oui",
"libelle": {
"fr": "Activé",
"en": "On"
},
"valeur": "1"
},
{
"id": "non",
"libelle": {
"fr": "Désactivé",
"en": "Off"
},
"valeur": "0"
}
]
}
],
"commandes": [
"sv_enablebunnyhopping {param.etat}",
"sv_autobunnyhopping {param.etat}"
]
}
]
}tomb-raider-remasteredTomb Raider I-III Remastered · http · 30 actions
{
"id": "tomb-raider-remastered",
"nom": "Tomb Raider I-III Remastered",
"protocole": "jeu",
"mode": "http",
"jeu": {
"steamAppId": 2478970
},
"actions": [
{
"id": "small_medkit",
"libelle": {
"fr": "Soins : petite trousse de soins",
"en": "Health: small medipack"
},
"effet": "aide",
"method": "POST",
"path": "/small_medkit"
},
{
"id": "large_medkit",
"libelle": {
"fr": "Soins : grande trousse de soins",
"en": "Health: large medipack"
},
"effet": "aide",
"method": "POST",
"path": "/large_medkit"
}
]
}La question qu'on nous pose
Un plugin peut-il embarquer et lancer un programme (.exe) ?
Non. Ni un pack, ni un plugin, ni un mod ne font lancer un programme par Connect. La bonne architecture existe pourtant, et elle marche aujourd'hui : ton outil reste un programme que le joueur lance, il expose une API locale, et ton plugin lui parle en HTTP ou en WebSocket.
Ce que Connect ne fait pas
Connect ne lance aucun programme fourni par un pack ou un plugin : aucun de leurs champs ne désigne un fichier à exécuter, et une clé inconnue fait refuser le fichier. Les seuls programmes qu'il démarre sont ses propres composants, livrés avec lui (le pilote de la manette virtuelle, par exemple).
Pourquoi
Un pack s'installe en un clic chez de nombreux streamers. S'il pouvait lancer un programme, chaque pack serait un logiciel à auditer. Un pack et un plugin restent donc de la donnée, relue avant publication ; le code qui tourne chez le streamer est celui qu'il a choisi d'installer lui-même.
Et le mode mod ?
Hou.la héberge l'archive de ton mod. Connect vérifie son empreinte, contrôle son contenu (aucun chemin qui sorte du dossier, aucun lien symbolique) et l'extrait dans le dossier du jeu. Il ne lance rien : c'est le jeu qui charge son mod au démarrage. Un plugin public avec un mod est toujours relu par une personne de l'équipe.
La voie qui marche : un outil compagnon en HTTP
Ton outil écoute en local
Il ouvre une API HTTP (ou un WebSocket) sur
127.0.0.1, à un port fixe de ton choix. Une route par action :POST /soin,POST /ennemi… Réponds par un statut 2xx quand l'action a réussi : Connect attend 5 secondes au plus (4 en WebSocket), et tout autre statut s'affiche comme un échec dans le journal du live.Tu publies un plugin de jeu en mode http
Une action par route, avec ses réglages. Dans la description, dis où télécharger ton outil et quelle adresse saisir. C'est le rôle de « Mes plugins » : déclarer cette connexion, pas livrer le programme.
Le streamer installe et lance ton outil
Il le télécharge chez toi, le lance à côté du jeu, puis saisit dans Connect l'« URL de base » (par exemple
http://127.0.0.1:7777) et un jeton si ton outil en demande un. Le jeton part dans l'en-têteAuthorization: Bearer …, ou dans l'en-tête que la connexion nomme.Les packs choisissent tes actions
Dans le Lab, bloc « Dans le jeu » : ton jeu et ses actions apparaissent. Une adresse locale ne passe que par une connexion : un pack ne peut pas écrire
http://127.0.0.1lui-même.
C'est le cas de Tomb Raider I-III Remastered : son plugin officiel (tomb-raider-remastered, 30 actions en POST) parle à l'outil « Director » qui tourne à côté du jeu. Le plugin ne connaît que l'adresse saisie par le streamer ; l'outil fait le travail dans le jeu.
Mode mod
Le pont local : le protocole d'un mod
Ton mod est le client, Connect le serveur : le jeu n'ouvre aucun port, et le mod se reconnecte tout seul quand Connect redémarre. Des messages JSON en texte, sur un WebSocket local.
Lire le fichier d'appairage
Au démarrage, Connect écrit
~/.houla/pont-jeu.json:{ "v": 1, "port": 30212, "jeton": "<48 caractères hexadécimaux>" }. Le jeton change à chaque démarrage et le fichier est effacé à la fermeture : relis-le avant chaque tentative.Se connecter
ws://127.0.0.1:<port>/pont/v1, avec l'en-têteX-Houla-Pont: <jeton>, et sans en-têteOrigin.Dire bonjour, en 5 secondes
{ "t": "bonjour", "v": 2, "jeu": "mon-jeu", "versionMod": "1.0.0", "actions": [ … ] }. En version 2,actionsdécrit chaque action (identifiant, libellé, réglages) : l'assistant s'en sert pour préremplir ton plugin. Connect répond{ "t": "bienvenue", "v": 2 }.Recevoir une action
{ "t": "action", "id": "a7", "action": "bombes", "params": { … }, "de": { "pseudo": "Lina", "quantite": 3, "cadeau": "Bombe" } }.Répondre, en 5 secondes
{ "t": "fait", "id": "a7", "ok": true }, ou"ok": falseavec uneraison(tableau ci-dessous) et undetailfacultatif. Sans réponse en 5 secondes, l'action échoue.Un jeu que Connect ne connaît pas encore
Un identifiant valide sans plugin est accepté et marqué « en développement » dans « Mes plugins » : c'est ainsi que tu testes ton mod avant d'avoir publié son plugin. Un second mod du même jeu remplace le premier (le jeu a été relancé).
Les raisons d'un refus
pas_en_partie | Aucune partie en cours (menu, chargement). |
|---|---|
mode_interdit | Ce mode de jeu refuse les actions des spectateurs. |
pas_maintenant | L'action n'a pas pu se jouer à ce moment. |
sans_effet | Rien à faire (vie déjà pleine, personne à ranimer). |
action_inconnue | Le mod installé ne connaît pas cette action (trop ancien). |
params | Réglages refusés par le mod. |
erreur | Erreur dans le jeu, précisée dans le champ detail. |
pas_hote | Seul l'hôte de la partie peut recevoir les actions. |
Ce que le serveur du pont garantit
- Il n'écoute que sur
127.0.0.1. - Le jeton est exigé, et comparé en temps constant.
- Tout en-tête
Originest refusé : une page web ouverte sur le PC ne peut pas se faire passer pour un jeu. - L'en-tête
Hostdoit nommer127.0.0.1oulocalhost(contre le DNS rebinding). - Des messages de 64 Ko au plus, et un battement toutes les 15 secondes : un jeu planté ne reste pas « connecté ».
Les kits de mod
Hou.la maintient trois clients du pont, chacun avec un exemple complet : Godot 4 .NET (C#), Unity avec BepInEx 5 (C#), et Lua avec LuaSocket. Ils ne sont pas encore proposés en téléchargement public ; le protocole ci-dessus suffit pour écrire ton client dans n'importe quel langage. Il n'existe pas de kit pour Unreal Engine.
Packs
Le format d'un pack (schéma 3)
Un pack est un fichier JSON que le Lab de Connect écrit pour toi, et que tu peux aussi écrire à la main ou faire écrire par une IA. La référence complète, générée depuis Connect, est le guide pour une IA du kit.
{ "schema": 3, "rules": [ { "id", "label", "on": [ … ], "do": [ … ] } ] }rules: les interactions. Chacune a unidstable (les réglages des streamers y sont attachés), unlabel, un ou plusieurs déclencheurs danson(l'un ou l'autre lance la chaîne, 8 au plus) et une chaîne de blocs dansdo.- Déclencheurs : cadeau Hou.la, dont les cadeaux personnalisés (
ix_slot_01,ix_slot_02… avec leur prix et leur rayon), follow, message du chat, commande déclarée (gratuite ou payante), likes et partages (paliers ou « tous les N »), spectateurs, sondage, roue, raccourci du streamer, et les événements de TikTok, YouTube, Kick et Twitch ("type": "platform"). - Blocs :
action,delay,if,switch(la première condition vraie part),random(tirage pondéré),parallel,repeat(etcasespour choisir le nombre de tours),counter,var. - Conditions :
{ "all": [ … ] }ou{ "any": [ … ] }, sur le montant (coins), la quantité, le palier de likes (hearts.palier), le montant d'une autre plateforme (platform.amount), un compteur, une variable… - Variables dans les textes :
{sender.name},{gift.name},{hearts.palier},{commande.texte}… Seules celles que le déclencheur remplit ont une valeur, et une variable inconnue fait refuser le pack. Jamais de variable dans un identifiant (son, overlay, réglage de jeu).
Bornes : 32 blocs par interaction, 6 niveaux d'imbrication, 30 s de durée calculée par chaîne, 50 tours pour un repeat.
Des packs d'exemple, vérifiés
pack-multi-sources.jsonUn événement, cinq plateformes, une seule action
Un cadeau personnalisé Hou.la à 100 pièces, un cadeau TikTok d'au moins 99 diamants, un Super Chat YouTube, 100 KICKs ou 100 bits Twitch : chacun fait apparaître le même creeper devant le streamer (plugin Minecraft). Twitch arrive bientôt dans Connect ; le pack est déjà prêt.
{
"schema": 3,
"rules": [
{
"id": "creeper",
"label": "Creeper",
"on": [
{
"type": "gift",
"giftSlug": "ix_slot_01",
"coinCost": 100,
"group": "Pagaille"
},
{
"type": "platform",
"platform": "tiktok",
"event": "gift",
"min": 99
},
{
"type": "platform",
"platform": "youtube",
"event": "superchat"
},
{
"type": "platform",
"platform": "kick",
"event": "kicks",
"min": 100
},
{
"type": "platform",
"platform": "twitch",
"event": "bits",
"min": 100
}
],
"do": [
{
"kind": "action",
"id": "creeper",
"effect": {
"type": "jeu",
"jeu": "minecraft",
"action": "invoquer",
"params": {
"creature": "creeper",
"position": "devant_3",
"qui": "joueur"
}
}
}
]
}
]
}Télécharger ce fichierpack-paliers-et-montants.jsonPaliers de likes et de partages, routage selon le montant
Les likes de Hou.la et de TikTok passent par la même chaîne ; un switch sur hearts.palier choisit la réaction (trois fanfares à 10 000, avec repeat). Les partages lisent leur total. Un cadeau quelconque est routé selon coins, et repeat joue cinq klaxons quand la quantité atteint 5.
{
"schema": 3,
"rules": [
{
"id": "paliers-likes",
"label": "Paliers de likes",
"on": [
{
"type": "hearts",
"milestones": [
1000,
5000,
10000
]
},
{
"type": "platform",
"platform": "tiktok",
"event": "like_total",
"milestones": [
1000,
5000,
10000
]
}
],
"do": [
{
"kind": "switch",
"id": "selon-palier",
"conditions": [
{
"all": [
{
"left": "hearts.palier",
"op": ">=",
"right": 10000
}
]
},
{
"all": [
{
"left": "hearts.palier",
"op": ">=",
"right": 5000
}
]
}
],
"branches": [
[
{
"kind": "repeat",
"id": "trois-fanfares",
"times": 3,
"gapMs": 1500,
"branches": [
[
{
"kind": "action",
"id": "fanfare",
"effect": {
"type": "sound",
"soundId": "34f7bfb4-b51f-11f1-a1b0-920007989f15",
"volume": 0.8
}
}
]
]
}
],
[
{
"kind": "action",
"id": "wow",
"effect": {
"type": "sound",
"soundId": "2ebf44c5-b51a-11f1-a1b0-920007989f15"
}
}
]
],
"else": [
{
"kind": "action",
"id": "merci",
"effect": {
"type": "chat",
"text": "{hearts.palier} likes, merci à tous !",
"cooldownMs": 10000
}
}
]
}
]
},
{
"id": "paliers-partages",
"label": "Paliers de partages",
"on": {
"type": "share_total",
"milestones": [
10,
50,
100
]
},
"do": [
{
"kind": "action",
"id": "voix",
"effect": {
"type": "tts",
"text": "{shares.total} partages, merci !"
}
}
]
},
{
"id": "selon-montant",
"label": "Selon le montant du cadeau",
"on": {
"type": "gift",
"minCoins": 1
},
"do": [
{
"kind": "switch",
"id": "selon-pieces",
"conditions": [
{
"all": [
{
"left": "coins",
"op": ">=",
"right": 500
}
]
},
{
"all": [
{
"left": "coins",
"op": ">=",
"right": 100
}
]
}
],
"branches": [
[
{
"kind": "action",
"id": "gros",
"effect": {
"type": "sound",
"soundId": "34f7bfb4-b51f-11f1-a1b0-920007989f15"
}
}
],
[
{
"kind": "repeat",
"id": "klaxons",
"times": 1,
"gapMs": 600,
"cases": [
{
"when": {
"all": [
{
"left": "quantity",
"op": ">=",
"right": 5
}
]
},
"times": 5
}
],
"branches": [
[
{
"kind": "action",
"id": "klaxon",
"effect": {
"type": "sound",
"soundId": "301b847c-b529-11f1-a1b0-920007989f15"
}
}
]
]
}
]
],
"else": [
{
"kind": "action",
"id": "petit",
"effect": {
"type": "chat",
"text": "Merci {sender.name} pour {gift.name} !",
"cooldownMs": 5000
}
}
]
}
]
}
]
}Télécharger ce fichierpack-commandes-chat.jsonCommandes de chat
/klaxon est gratuite, une fois toutes les 30 secondes par spectateur, et tire un son au hasard (70 / 30). /dis coûte 10 pièces et lit le texte du spectateur à voix haute. « !gg » est écouté sur les chats de Hou.la, TikTok, YouTube et Kick.
{
"schema": 3,
"rules": [
{
"id": "commande-klaxon",
"label": "Klaxon",
"on": {
"type": "command",
"name": "klaxon",
"description": "Joue un klaxon au hasard",
"perViewerMs": 30000
},
"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": "commande-dis",
"label": "Dis-le à voix haute",
"on": {
"type": "command",
"name": "dis",
"description": "Le streamer lit ton message à voix haute",
"coinCost": 10,
"args": "texte",
"who": "tous"
},
"do": [
{
"kind": "action",
"id": "lire",
"effect": {
"type": "tts",
"text": "{sender.name} dit : {commande.texte}"
}
}
]
},
{
"id": "mot-gg",
"label": "GG dans le chat",
"on": {
"type": "comment",
"startsWith": "!gg",
"platforms": [
"houla",
"tiktok",
"youtube",
"kick"
]
},
"enchainement": "ignorer",
"do": [
{
"kind": "action",
"id": "roulement",
"effect": {
"type": "sound",
"soundId": "5703a3d3-b522-11f1-a1b0-920007989f15",
"volume": 0.6
}
}
]
}
]
}Télécharger ce fichierpack-cadeaux-personnalises.jsonUn cadeau personnalisé par action de jeu
Quatre cadeaux personnalisés (ix_slot_01 à 04), chacun avec son nom, son prix dans l'échelle fermée et son rayon, reliés aux actions du plugin Pratfall. L'icône d'un cadeau se règle ensuite dans le Lab.
{
"schema": 3,
"rules": [
{
"id": "bombes",
"label": "Pluie de bombes",
"on": {
"type": "gift",
"giftSlug": "ix_slot_01",
"coinCost": 30,
"group": "Pagaille"
},
"do": [
{
"kind": "action",
"id": "bombes",
"effect": {
"type": "jeu",
"jeu": "pratfall",
"action": "bombes",
"params": {
"nombre": 3,
"cible": "hasard"
}
}
}
]
},
{
"id": "soins",
"label": "Soins",
"on": {
"type": "gift",
"giftSlug": "ix_slot_02",
"coinCost": 45,
"group": "Coup de main"
},
"do": [
{
"kind": "action",
"id": "soigner",
"effect": {
"type": "jeu",
"jeu": "pratfall",
"action": "soigner",
"params": {}
}
}
]
},
{
"id": "klaxon",
"label": "Klaxon",
"on": {
"type": "gift",
"giftSlug": "ix_slot_03",
"coinCost": 5,
"group": "Ambiance"
},
"do": [
{
"kind": "action",
"id": "klaxon",
"effect": {
"type": "jeu",
"jeu": "pratfall",
"action": "klaxon",
"params": {}
}
}
]
},
{
"id": "resurrection",
"label": "Résurrection",
"on": {
"type": "gift",
"giftSlug": "ix_slot_04",
"coinCost": 280,
"group": "Coup de main"
},
"do": [
{
"kind": "action",
"id": "ressusciter",
"effect": {
"type": "jeu",
"jeu": "pratfall",
"action": "ressusciter",
"params": {
"cible": "hasard"
}
}
}
]
}
]
}Télécharger ce fichierpack-outil-compagnon-http.jsonUn outil compagnon en HTTP
Deux cadeaux qui pilotent Tomb Raider I-III Remastered par son plugin officiel en mode http ; la trousse répond aussi à la Rose de TikTok (giftId 5655).
{
"schema": 3,
"rules": [
{
"id": "trousse",
"label": "Trousse de soins",
"on": [
{
"type": "gift",
"giftSlug": "ix_slot_01",
"coinCost": 20,
"group": "Coup de main"
},
{
"type": "platform",
"platform": "tiktok",
"event": "gift",
"giftId": "5655"
}
],
"do": [
{
"kind": "action",
"id": "trousse",
"effect": {
"type": "jeu",
"jeu": "tomb-raider-remastered",
"action": "small_medkit",
"params": {}
}
}
]
},
{
"id": "trex",
"label": "T-Rex",
"on": {
"type": "gift",
"giftSlug": "ix_slot_02",
"coinCost": 490,
"group": "Pagaille"
},
"do": [
{
"kind": "action",
"id": "annonce",
"effect": {
"type": "chat",
"text": "{sender.name} lâche un T-Rex sur Lara !",
"cooldownMs": 5000
}
},
{
"kind": "action",
"id": "trex",
"effect": {
"type": "jeu",
"jeu": "tomb-raider-remastered",
"action": "trex",
"params": {}
}
}
]
}
]
}Télécharger ce fichierSécurité
Ce qu'un pack ou un plugin ne peut pas faire
Ces règles sont vérifiées deux fois : par Hou.la à la publication, puis par Connect avant chaque action.
- Lancer un programme, exécuter un script, ou faire tourner le code de son auteur.
- Viser ce PC ou le réseau local par une adresse écrite dans le pack (
127.0.0.1,192.168.…,localhost, ou un nom qui y mène). Seule une connexion saisie par le streamer, ou un hôte qu'il a approuvé, y accède. - Envoyer un jeton ou un mot de passe ailleurs que vers la connexion du streamer, ou suivre une redirection depuis une adresse écrite dans le pack.
- Insérer un champ secret d'une connexion (mot de passe, jeton, webhook) dans une commande ou une requête.
- Jouer une commande RCON destructrice :
stop,restart,op,ban,kick,whitelist,save-off,gamemode… - Prendre le clavier, la manette ou le pilote bas niveau sans que le streamer les ait allumés : ils sont désactivés par défaut.
- Démarrer ou couper le stream depuis OBS ou Streamlabs.
- Envoyer à un jeu une action ou un réglage que son plugin ne déclare pas, ou mettre une variable venue du chat dans un réglage.
- Porter une clé inconnue : chaque objet est reconstruit depuis une liste fermée, et le reste fait refuser le fichier.
Publier
Privé tout de suite, public après relecture
Tout le monde peut publier. Ce qui part chez les autres streamers est relu avant.
- Un plugin « pour moi » est utilisable tout de suite sur ton PC, dans tes packs privés. « Pour tout le monde » : relu par une personne de l'équipe avant d'entrer dans le Store ; le modifier le renvoie en relecture.
- Un pack public a besoin de plugins publics : tant que le plugin de ton jeu est privé ou en relecture, Hou.la refuse de publier le pack (
PLUGIN_JEU_PRIVE). - Un pack public est relu : l'analyse automatique peut seulement refuser, une personne approuve. Approuvé, il est signé, et Connect vérifie sa signature.
- Installer un pack installe ses plugins : la liste se calcule depuis ses actions de jeu, il n'y a rien à déclarer. Le mod d'un plugin s'installe avec lui.
- Commission : le créateur d'un pack peut fixer la sienne, de 0 à 15 %.
Kit
Le kit développeur
Tout ce que cette page montre, en fichiers. Les exemples sont générés depuis Connect et vérifiés par le validateur de Hou.la.
guide-ia.md: le format complet d'un pack, avec les variables de chaque déclencheur, l'échelle des prix, les bornes, et les actions de chaque plugin de jeu officiel. C'est le même fichier que le bouton « Guide pour une IA… » du Lab.packs/: les cinq packs d'exemple de cette page.plugins/: un plugin de jeu par mode.visuels/gabarit-banniere-1600x900.jpg,visuels/prompt-banniere.md: le gabarit de la bannière d'un pack (1600 x 900) et le prompt qui va avec, pour une IA d'images. Les icônes de cadeaux : 512 x 512, PNG transparent.

Faire écrire un pack par une IA
- Donne-lui
guide-ia.md, et l'adresse de cette page. - Si ton pack joue des sons, ajoute la liste des sons : dans Connect, « Sons », « Exporter la liste… » (ou « Liste des sons… » dans le Lab).
- Elle rend un fichier JSON. Dans le Lab : onglet « Écouteurs », « JSON », « Importer un fichier… », puis « Vérifier mon pack ».
- Règle ensuite ce qu'une IA ne peut pas deviner : l'icône d'un cadeau personnalisé, les overlays du streamer, les connexions.
Prêt à relier ton jeu ?
Installe Hou.la Connect, ouvre « Mes plugins » et crée ton premier plugin. Une question : la communauté Hou.la est sur Discord.