Workshop Chat

About Workshop Chat

A fully static, serverless peer-to-peer chat built for live PHP workshops — no sign-up, no database, nothing stored on a server.

Two roles

🎛️

Controller

The workshop host opens the app and starts a room. A 5-digit PIN and QR code appear — these go on the beamer. The controller's view shows the full chat feed, a participant list, and lets the host assign team colours.

💬

Participant

Attendees open /chat/?room=<name> (from the QR code or a link) and type the PIN. After choosing a display name they're live in the chat, able to send messages and share syntax-highlighted code snippets in PHP, JavaScript, Python, HTML, CSS, or plain text.

Connection diagram

💬 Participant A
browser
1. SDP / ICE
(signaling only)
☁️ PeerJS
Cloud
signaling server
1. SDP / ICE
(signaling only)
🎛️ Controller
browser / beamer
💬 Participant A
2. Encrypted WebRTC
data channel (DTLS)
PeerJS server not involved
🎛️ Controller

⚠️ If a direct path cannot be established (strict firewall / symmetric NAT), traffic may route via a TURN relay server — see Privacy below.

Step-by-step connection flow

  1. 1
    Controller registers a Peer ID On session start the controller generates a random 5-digit PIN and registers the Peer ID phpgrn-{PIN} on the PeerJS signaling server. The server hands back a confirmation — no message content is involved.
  2. 2
    QR code & join URL generated The app builds a join URL (/chat/?room=name) and encodes it in a QR code entirely in the browser — no server call. If Network relay mode is enabled, &relay=1 is appended so participants automatically inherit the relay setting.
  3. 3
    Participant scans / types the PIN The participant's browser sends an SDP offer to phpgrn-{PIN} via the PeerJS signaling server. The controller receives it and replies with an SDP answer. ICE candidates (network addresses) are also exchanged through this channel.
  4. 4
    Direct WebRTC data channel opens Once ICE negotiation succeeds the browsers connect directly, encrypted with DTLS. The PeerJS signaling server is no longer involved. All chat messages, code snippets, history packets, and colour assignments travel through this channel.
  5. 5
    Controller relays to all participants The topology is a star: every participant connects to the controller, not to each other. When a participant sends a message the controller receives it and rebroadcasts it to all other connected participants. This keeps things simple and gives the controller full visibility.
  6. 6
    Session ends — everything is wiped When the controller closes the tab a session-end message is broadcast. Each participant clears its feed, resets state, and returns to the start screen. Nothing is written to disk anywhere.

Privacy & data

No server-side storage. This app has no database, no backend, and no analytics. All message history lives in the controller's browser tab and is gone the moment the session ends.
Message content is end-to-end encrypted. WebRTC data channels are mandated to use DTLS encryption. Once the direct channel is established, the PeerJS signaling server cannot read your messages — it only sees who connected to whom.
TURN relay caveat. If a direct peer-to-peer path cannot be established (e.g., on a guest Wi-Fi network with client isolation) WebRTC falls back to a TURN relay server. Traffic is still DTLS-encrypted in transit, but the relay server operator sees the encrypted bytes. Enable Network relay mode on the Start a Room screen and enter TURN credentials (e.g. from metered.ca free tier) — the setting is automatically propagated to participants via the join URL. Credentials stay in the browser and are never sent to any server other than the TURN server you configure.
Data Seen by PeerJS Stored anywhere
Message content No — DTLS encrypted No
Code snippets No — DTLS encrypted No
Display names No Browser localStorage only (token)
Room name (in URL) No Browser history / server access logs
Peer IDs (who talks to whom) Yes — signaling metadata Not by this app
IP addresses Yes — ICE candidates Not by this app
Session history No Gone when tab closes

Open-source libraries & services

This app is built entirely on open-source tools and free tiers. We gratefully acknowledge:

P2P / WebRTC
PeerJS

Simplifies WebRTC peer-to-peer connections with a clean JavaScript API. Provides the public signaling server and TURN relay infrastructure used to establish connections between browsers.

MIT License
Syntax highlighting
Highlight.js

Automatic syntax detection and highlighting for code snippets. Used here with the GitHub light theme for clean, readable code blocks in PHP, JavaScript, Python, HTML, CSS, and plain text.

BSD 3-Clause License
TURN relay (optional)
Metered.ca

Provides free TURN relay servers (50 GB/month) for when Network relay mode is needed. The host registers once and pastes credentials into the Start a Room form — no credentials are stored server-side by this app.

Free tier available
QR code generation
QRCode.js

Generates QR codes entirely in the browser using HTML5 Canvas. Used to encode the join URL so participants can scan it from the beamer without typing a long URL.

MIT License
CDN
cdnjs

Free CDN for open-source libraries, maintained by Cloudflare. Serves Highlight.js and QRCode.js. No tracking; files are delivered over HTTPS from global edge nodes.

Free / Open
CDN (PeerJS)
unpkg

A fast, global CDN for npm packages. Used to load the PeerJS client library directly from the npm registry.

Free / Open
Hosting
GitHub Pages

Serves the entire GroningenPHP website as a static site directly from the GitHub repository — no web server to manage and free for open-source projects.

Free for public repos
Open Workshop Chat Back to Workshops