diff --git a/engine/demo/.gitignore b/engine/demo/.gitignore
new file mode 100644
index 0000000..c2658d7
--- /dev/null
+++ b/engine/demo/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/engine/demo/index.html b/engine/demo/index.html
new file mode 100644
index 0000000..d179ab9
--- /dev/null
+++ b/engine/demo/index.html
@@ -0,0 +1,760 @@
+
+
+
+
+
+
+
Pixel Stream ยท Click to Interact
+
+
+
Waiting for source stream...
+
+
+
+
Frames 0
+
Bytes 0B
+
FPS 0
+
Decode โ
+
RTT โ
+
Saved โ
+
+
+
+
+
+
โฑ Round-Trip Latency
+
โ
+
click โ source โ render โ back
+
Click to measure
+
+
+
๐ฆ Compression
+
โ
+
delta + RLE vs raw RGBA
+
โ
+
+
+
+
Interactions
+
0 clicks sent
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/engine/demo/relay.js b/engine/demo/relay.js
new file mode 100644
index 0000000..4d90d91
--- /dev/null
+++ b/engine/demo/relay.js
@@ -0,0 +1,69 @@
+// DreamStack ds-stream Pixel Relay Server (bidirectional)
+// Source โ Receiver: pixel frames
+// Receiver โ Source: interaction signals (clicks, drags)
+const { WebSocketServer } = require('ws');
+const http = require('http');
+
+const PORT = 9800;
+const sources = new Set();
+const receivers = new Set();
+let frameCount = 0;
+let byteCount = 0;
+let signalCount = 0;
+
+const server = http.createServer((req, res) => {
+ res.writeHead(200, {
+ 'Content-Type': 'text/plain',
+ 'Access-Control-Allow-Origin': '*',
+ });
+ res.end(`ds-stream relay | sources: ${sources.size} | receivers: ${receivers.size} | frames: ${frameCount} | signals: ${signalCount} | bytes: ${byteCount}`);
+});
+
+const wss = new WebSocketServer({ server });
+
+wss.on('connection', (ws, req) => {
+ const path = req.url || '/';
+
+ if (path.startsWith('/source')) {
+ sources.add(ws);
+ console.log(`[relay] source connected (${sources.size} total)`);
+
+ ws.on('message', (data) => {
+ frameCount++;
+ byteCount += data.length;
+ for (const recv of receivers) {
+ if (recv.readyState === 1) recv.send(data);
+ }
+ });
+
+ ws.on('close', () => {
+ sources.delete(ws);
+ console.log(`[relay] source disconnected (${sources.size} remaining)`);
+ });
+ } else {
+ receivers.add(ws);
+ console.log(`[relay] receiver connected (${receivers.size} total)`);
+
+ ws.on('message', (data) => {
+ // Forward interaction signals from receiver โ source
+ signalCount++;
+ for (const src of sources) {
+ if (src.readyState === 1) src.send(data);
+ }
+ });
+
+ ws.on('close', () => {
+ receivers.delete(ws);
+ console.log(`[relay] receiver disconnected (${receivers.size} remaining)`);
+ });
+ }
+});
+
+server.listen(PORT, () => {
+ console.log(`\n โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ`);
+ console.log(` โ ds-stream relay on :${PORT} โ`);
+ console.log(` โ Source: ws://localhost:${PORT}/source โ`);
+ console.log(` โ Receiver: ws://localhost:${PORT}/stream โ`);
+ console.log(` โ Mode: bidirectional (pixels + signals) โ`);
+ console.log(` โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n`);
+});