Skip to content

Examples

The examples folder holds three small apps. The chat and the call are modules with tests that run them over real peer connections in a browser, and the code here wires them to the DOM. Serve them all from a clone of the repository:

Terminal window
npm ci
npm run examples

http://localhost:5173/chat/ — open it in two tabs. The chat itself, joinChat, is on the getting started page; this is the page around it:

examples/chat/page.ts
import type { Signaling } from 'peer-data';
import { joinChat } from './chat.js';
/** Runs the chat page: the log, the form, and the peer count, over the given signaling. */
export function runChatPage(signaling: Signaling): void {
const log = document.querySelector<HTMLUListElement>('#log');
const status = document.querySelector<HTMLParagraphElement>('#status');
const form = document.querySelector<HTMLFormElement>('#form');
const input = document.querySelector<HTMLInputElement>('#text');
if (!log || !status || !form || !input) throw new Error('chat page markup is missing');
const name = `Guest ${String(Math.floor(Math.random() * 1000))}`;
const show = (text: string): void => {
const item = document.createElement('li');
item.textContent = text;
log.append(item);
log.scrollTop = log.scrollHeight;
};
const chat = joinChat(signaling, name, {
line: ({ from, text }) => {
show(`${from}: ${text}`);
},
peers: (count) => {
status.textContent = `You are ${name}, connected to ${String(count)} ${count === 1 ? 'peer' : 'peers'}.`;
},
});
status.textContent = `You are ${name}. Waiting for someone to join.`;
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (text === '') return;
chat.say(text);
show(`${name}: ${text}`);
input.value = '';
});
window.addEventListener('pagehide', chat.leave);
// A page restored from the back-forward cache has left the chat: join afresh.
window.addEventListener('pageshow', (event) => {
if (event.persisted) location.reload();
});
}
examples/chat/main.ts
import { BroadcastChannelSignaling } from 'peer-data';
import { runChatPage } from './page.js';
runChatPage(new BroadcastChannelSignaling('peer-data-chat'));

http://localhost:5173/video/ — open it in two tabs and start each. joinCall is on the live demo page; this page shares your camera with it:

examples/video/main.ts
import { BroadcastChannelSignaling } from 'peer-data';
import { joinCall } from './video.js';
const videos = document.querySelector<HTMLDivElement>('#videos');
const start = document.querySelector<HTMLButtonElement>('#start');
const status = document.querySelector<HTMLParagraphElement>('#status');
if (!videos || !start || !status) throw new Error('video page markup is missing');
/** A muted, playing video element for stream. */
function videoFor(stream: MediaStream, muted: boolean): HTMLVideoElement {
const video = document.createElement('video');
video.autoplay = true;
video.playsInline = true;
video.muted = muted;
video.srcObject = stream;
return video;
}
const startCall = async (): Promise<void> => {
start.disabled = true;
let stream: MediaStream;
try {
stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
} catch (error) {
status.textContent = `No camera: ${String(error)}`;
start.disabled = false;
return;
}
videos.append(videoFor(stream, true));
status.textContent = 'Sharing your camera with every other tab that joins.';
const remote = new Map<string, HTMLVideoElement>();
const call = joinCall(new BroadcastChannelSignaling('peer-data-video'), stream, {
stream: (id, theirs) => {
const existing = remote.get(id);
if (existing) {
existing.srcObject = theirs;
return;
}
const video = videoFor(theirs, false);
remote.set(id, video);
videos.append(video);
},
left: (id) => {
remote.get(id)?.remove();
remote.delete(id);
},
});
window.addEventListener('pagehide', call.leave);
};
// A page restored from the back-forward cache has left its call: start afresh.
window.addEventListener('pageshow', (event) => {
if (event.persisted) location.reload();
});
start.addEventListener('click', () => {
void startCall();
});

http://localhost:5173/socket/ — open it in two browsers. The same chat page, signaling through the socket.io server in examples/socket/server.ts, which the dev server runs on the same port through a Vite plugin:

examples/socket/main.ts
import { io } from 'socket.io-client';
import { SocketChannel } from 'peer-data';
import { runChatPage } from '../chat/page.js';
// vite-plugin.ts runs the signaling server on the examples' dev server, on the same port, so io() reaches it.
runChatPage(new SocketChannel(io()));