Aller au contenu

Relier plusieurs écrans

Faire discuter des téléphones et un grand écran en temps réel avec un serveur WebSocket en Node.js. Code seulement : il faut lancer le serveur chez toi.

Le principe

Un WebSocket est une connexion qui reste ouverte entre le navigateur et un serveur : chacun peut envoyer un message à tout moment, sans recharger la page. Pour relier plusieurs écrans, on fait passer tous les messages par un petit serveur Node.js :

  1. chaque page (les téléphones, le grand écran) se connecte au serveur ;
  2. quand une page envoie un message, le serveur le renvoie à toutes les pages connectées ;
  3. chaque page décide quoi faire du message reçu (bouger un objet, changer une couleur…).

Cette doc n’a pas de démo en direct : le serveur doit tourner sur ton ordinateur. Tout le code est ci-dessous.

Installer le paquet ws

Dans ton projet Vite (voir la doc « Première scène »), installe ws, la bibliothèque WebSocket la plus utilisée côté Node.js, et ajoute un script pour lancer le serveur :

Terminal
npm install ws
package.json
{
  "type": "module",
  "scripts": {
    "dev": "vite",
    "server": "node server.js"
  }
}

Le serveur

À la racine du projet, à côté de index.html :

server.js
import { WebSocketServer } from "ws";

const server = new WebSocketServer({
  port: 8080,
});

console.log("Serveur démarré");

server.on("connection", (client) => {
  console.log("+1 personne connectée !");

  client.on("message", (message) => {
    console.log("client ->", message.toString());

    for (const otherClient of server.clients) {
      otherClient.send(message.toString());
    }
  });
});

Le serveur écoute sur le port 8080. À chaque connexion, il attend les messages de ce client et les renvoie à tous les clients connectés, celui qui a envoyé compris. message arrive sous forme d’octets : toString() le remet en texte.

La page

index.html
<!doctype html>
<html lang="fr">
  <head>
    <meta charset="UTF-8" />
    <title>Démo WebSocket</title>
  </head>
  <body>
    <form>
      <button>Envoyer un message</button>
    </form>
    <script type="module" src="/main.js"></script>
  </body>
</html>
main.js
const ws = new WebSocket("ws://" + location.hostname + ":8080");

ws.addEventListener("open", () => {
  console.log("Connecté !");
});

ws.addEventListener("close", () => {
  console.log("Serveur éteint ? Lance npm run server");
});

const form = document.querySelector("form");

form.addEventListener("submit", (event) => {
  event.preventDefault();
  ws.send(JSON.stringify({ text: "Hello World" }));
});

ws.addEventListener("message", (event) => {
  const data = JSON.parse(event.data);
  console.log("message reçu :", data);
});
  • location.hostname reprend l’adresse de la page : le même code marche en localhost sur l’ordi et avec l’adresse IP sur un téléphone.
  • event.preventDefault() empêche le formulaire de recharger la page.
  • Les messages voyagent en texte : on envoie un objet avec JSON.stringify, on le relit avec JSON.parse.

Lancer les deux serveurs

Il faut deux terminaux ouverts en même temps, dans le dossier du projet :

Terminal
npm run server
Terminal
npm run dev -- --host

Le premier lance le serveur WebSocket, le second lance Vite. L’option --host rend la page accessible aux autres appareils : Vite affiche une adresse « Network » du type http://192.168.1.20:5173. Ouvre-la sur ton téléphone, ouvre localhost:5173 sur l’ordi, envoie un message et regarde les deux consoles.

Le téléphone et l’ordi doivent être sur le même réseau Wi-Fi. Si le téléphone ne trouve pas la page, le réseau bloque peut-être les échanges entre appareils : passe par le partage de connexion de ton téléphone.

Brancher le message sur la scène 3D

Le message peut transporter n’importe quelle donnée. Par exemple, chaque téléphone envoie une couleur, et le grand écran colore son cube avec :

main.js
form.addEventListener("submit", (event) => {
  event.preventDefault();
  ws.send(JSON.stringify({ color: "#ff0000" }));
});

ws.addEventListener("message", (event) => {
  const data = JSON.parse(event.data);

  if (data.color) {
    cube.material.color.set(data.color);
  }
});

Pour que le grand écran et les téléphones n’affichent pas la même chose, fais deux pages (par exemple index.html pour l’écran et telephone.html pour la manette) : Vite sert tous les fichiers HTML du dossier.

Pour aller plus loin

  • Envoie la position du doigt (pointermove) pour piloter un objet depuis le téléphone.
  • Ajoute un champ type à chaque message ({ type: "color", value: "#ff0000" }) pour en gérer plusieurs sortes.
  • La documentation de ws détaille les options du serveur.

Mise à jour : ven. 30 oct. à 17:05