Turning Your Living Room into a Couch Co-op Arena with TouchCoop
Source: Dev.to

Overview
Hey everyone 👋,
Today I want to share something fun. Imagine this: you’re at home with friends, the big TV is on, and instead of everyone fighting over Bluetooth controllers or passing around one gamepad… everyone just pulls out their phone and instantly becomes a player.
No accounts. No installs. Just scan a QR code and start mashing buttons.
That’s exactly what TouchCoop enables — a tiny TypeScript library that turns this vision into reality with almost zero server hassle.
- Host runs the game on a laptop/TV‑connected browser
- Up to 4 players join via QR code on their mobiles
- Touch buttons on phone → real‑time input to the game via WebRTC
- Perfect for casual games: platformers, party games, local puzzles
Not suited for low‑latency games like FPS (WebRTC latency is good but not esports‑level)
Quick architecture overview
Your game needs two distinct entry points (URLs):
- The Match page (main game): Creates a
Matchinstance, shows QR codes for joining, and receives player events. - The Gamepad page (controller): Opened via QR code, creates a
Playerinstance, connects, and sends touch events.
Both are just static web pages — no backend required beyond the signaling phase.
Getting started in 60 seconds
Install the library
npm install touch-coop
1. The Match side (your game)
import { Match, PlayerEvent } from "touch-coop";
const gamePadURL = "https://your-domain.com/gamepad"; // Must be absolute URL for QR
function handlePlayerEvent(event: PlayerEvent) {
switch (event.action) {
case "JOIN":
console.log(`Player ${event.playerId} joined 🎉`);
// Maybe spawn player avatar, play sound, etc.
break;
case "LEAVE":
console.log(`Player ${event.playerId} left 😢`);
break;
case "MOVE":
console.log(`Player ${event.playerId} → ${event.button}`);
// Map "up", "A", "X" etc. to game actions
if (event.button === "up") jumpPlayer(event.playerId);
break;
}
}
const match = new Match(gamePadURL, handlePlayerEvent);
// Optional: custom PeerJS server for better reliability
// const match = new Match(gamePadURL, handlePlayerEvent, {
// host: 'your-peerjs-server.com',
// port: 9000,
// path: '/peerjs'
// });
// Later: match.requestNewPlayerToJoin() → returns promise with QR data/URL
Call match.requestNewPlayerToJoin() each time you want to add a slot — it gives you the join URL to turn into a QR code (many libraries can help with that).
2. The Gamepad side (React example)
import React, { useEffect, useState } from "react";
import { Player } from "touch-coop";
const player = new Player(); // Can pass custom PeerJS config too
export default function GamePad() {
const [loading, setLoading] = useState(true);
useEffect(() => {
(async () => {
try {
await player.joinMatch(); // Parses peer ID from URL query params
setLoading(false);
} catch (err) {
console.error("Failed to join", err);
}
})();
}, []);
if (loading) return <>Connecting...</>;
return (
<>
<button onClick={() => player.sendMove("up")}>↑</button>
<button onClick={() => player.sendMove("left")}>←</button>
<button onClick={() => player.sendMove("right")}>→</button>
<button onClick={() => player.sendMove("down")}>↓</button>
<button onClick={() => player.sendMove("A")}>A</button>
<button onClick={() => player.sendMove("B")}>B</button>
<button onClick={() => player.sendMove("X")}>X</button>
<button onClick={() => player.sendMove("Y")}>Y</button>
</>
);
}
Live demo & try it yourself
The original project has a nice little demo:
→
Final thoughts
TouchCoop is a beautiful example of how far browser APIs have come: WebRTC + TypeScript + modern build tools = couch co‑op without native apps or complex backends.
If you’re building casual multiplayer experiences or party games, give it a try.
Have you built (or are you planning to build) a couch co‑op game? Drop a comment below — I’d love to hear your multiplayer war stories or see links to your projects!
Happy coding, and see you in the comments ✌️