bombo/tsconfig.tsbuildinfo
Vibe Kanban 983feb9b20 Create an ipfs multiplayer game (vibe-kanban 3f05cdd0)
Perfect — that’s the sweet spot for IPFS/libp2p + WebRTC:
you want low-latency multiplayer, but also no permanent backend to maintain.

Let’s walk through a design that gives you both: a serverless, P2P Bomberman-style game that just needs minimal bootstrap infrastructure (or even none, if you’re willing to use public networks).

---

🌐 Goal Recap

You want:

1. Zero long-lived servers
2. Fast, real-time gameplay (low latency)
3. Players connect directly (P2P)
4. Optional decentralized content (maps, replays, etc.)

We can absolutely do that with:

WebRTC DataChannels → real-time gameplay

libp2p / IPFS → discovery, signaling, content sharing

(Optional) fallback relay → coturn or public relays, not your own infra

---

🧠 Architecture: “Serverless Hybrid P2P”

Here’s the picture:

┌───────────────────────┐
            │   IPFS / libp2p DHT   │
            │  (public bootstrap)   │
            └───────────────────────┘
                     ▲
                     │ (publish lobby info, peer IDs)
                     ▼
┌──────────────┐   WebRTC   ┌──────────────┐
│   Player A   │◄──────────►│   Player B   │
│ (Host peer)  │             │ (Client peer)│
└──────────────┘             └──────────────┘
     ▲  ▲                           ▲
     │  │                           │
     │  └────── IPFS ───────────────┘
     │         (fetch maps, assets, replays)
     │
     └─ deterministic lockstep or host-authoritative gameplay

---

⚙️ Components Breakdown

1. Peer Discovery (No Central Server)

You need a way for players to find each other before connecting directly.

Options:

✅ libp2p DHT (decentralized)

Each peer advertises its lobby on the DHT with a unique topic ID.

Another peer queries that topic to find peers.

Under the hood, libp2p handles NAT traversal and peer routing.

You can bootstrap with public libp2p bootstrap nodes (so you don’t host your own).

👉 This means: you literally publish “hey, I’m hosting game X” to the DHT.
Anyone who looks for X can find you and establish a WebRTC connection.

Example (in JS):

import { createLibp2p } from 'libp2p'
import { webRTCStar } from '@libp2p/webrtc-star'
import { pubsub } from '@libp2p/pubsub'

const node = await createLibp2p({
  transports: [webRTCStar()],
  pubsub: pubsub()
})

await node.start()
node.pubsub.subscribe('bomberman-lobby', (msg) => {
  console.log('Found peer:', msg.from)
})

This replaces the need for a Node.js signaling server.

---

2. Signaling for WebRTC

WebRTC peers need to exchange “SDP offers/answers” to connect.

You can use:

libp2p webrtc-star transport, which includes signaling built-in, or

IPFS pubsub (you can post the SDP offer/answer messages there).

No centralized WebSocket signaling server is needed.
The DHT acts as a “gossip network” for signaling messages.

---

3. Real-Time Data Channel

Once peers are connected:

Use a WebRTC DataChannel (binary mode) for game traffic.

Exchange inputs or state deltas each tick.

No need to route through IPFS — the data channel is direct.

This gives you latency similar to a central server (\~30–60ms typical).

Example pseudo-flow:

// after signaling done
const channel = peerConnection.createDataChannel('game')
channel.onmessage = (e) => handleGameMessage(e.data)
channel.send(encodeInput(inputState))

---

4. Game State Sync

You have two options:

Host-authoritative: one peer simulates the full game and broadcasts snapshots.

Lockstep deterministic: all peers simulate the same logic (just exchange inputs).

For a tile-based Bomberman clone, deterministic lockstep is realistic:

Low bandwidth (just input bits per tick)

Everyone sees the same outcome

No single point of authority (fully P2P)

If you want simplicity and less chance of divergence → go host-authoritative.

---

5. IPFS for Assets / Mods

Let players fetch maps and assets via IPFS instead of HTTP/CDN.

Example:

Host publishes map JSON to IPFS → gets a CID

CID is included in lobby metadata

Clients fetch from IPFS gateway or browser IPFS node:

const mapData = JSON.parse(await ipfs.cat(mapCid))
2026-01-30 23:30:20 +01:00

1 line
No EOL
326 B
Text

{"root":["./src/main.ts","./src/vite-env.d.ts","./src/game/Grid.ts","./src/game/engine.ts","./src/game/types.ts","./src/network/libp2p-browser.ts","./src/network/lobby.ts","./src/network/relay-client.ts","./src/network/types.ts","./src/network/webrtc-channel.ts","./src/ui/controls.ts","./src/ui/render.ts"],"version":"5.6.3"}