Decentralized peer-to-peer WebRTC networking for Bevy games using Nostr as the signaling layer.
This project replaces traditional centralized signaling servers with the Nostr protocol, enabling truly decentralized multiplayer gaming without relying on any central infrastructure.
Nostr (Notes and Other Stuff Transmitted by Relays) is a simple, open protocol that enables censorship-resistant global "social" networks. Instead of relying on centralized servers, Nostr uses a network of decentralized relays to transmit messages between users, each identified by cryptographic key pairs.
Traditional WebRTC requires a signaling server to help peers discover each other and establish connections. This project replaces that centralized signaling server with Nostr's decentralized relay network:
┌─────────────┐ Nostr Relays ┌─────────────┐
│ Player A │ ◄─────────────────► │ Player B │
│ │ │ │
│ ┌─────────┐ │ │ ┌─────────┐ │
│ │ Nostr │ │ ◄─── Encrypted ───► │ │ Nostr │ │
│ │ Keys │ │ Signaling │ │ Keys │ │
│ └─────────┘ │ │ └─────────┘ │
└─────────────┘ └─────────────┘
│ │
└────── Direct WebRTC P2P ─────────┘
- Peer Discovery: Players connect to one or more Nostr relays
- Signaling: WebRTC offers/answers are encrypted using NIP-04 and sent as Nostr events
- Connection: Once WebRTC negotiation completes, data flows directly between peers
- Decentralization: No single point of failure - if one relay goes down, others continue working
- ✅ Truly Decentralized: No central servers required
- ✅ Censorship Resistant: Uses Nostr's distributed relay network
- ✅ Encrypted Signaling: All signaling data encrypted with NIP-04
- ✅ Bevy 0.15 Compatible: Works with the latest Bevy release
- ✅ Cross-Platform: Supports both native and WASM targets
- ✅ GGRS Compatible: Drop-in replacement for rollback netcode
- ✅ Multiple Channels: Configurable reliable/unreliable data channels
[dependencies]
bevy = "0.15"
bevy_matchbox_nostr = "0.6.4"
nostr = { version = "0.43", features = ["nip04"] }use bevy::prelude::*;
use bevy_matchbox_nostr::prelude::*;
use nostr::Keys;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, start_matchbox_socket)
.add_systems(Update, handle_socket_events)
.run();
}
fn start_matchbox_socket(mut commands: Commands) {
// Generate or load Nostr keys
let nostr_keys = Keys::generate();
// Create socket with Nostr relay as room URL
let socket = MatchboxSocket::new_reliable(
"wss://relay.damus.io/your-game-room",
nostr_keys
);
commands.insert_resource(socket);
}
fn handle_socket_events(mut socket: ResMut<MatchboxSocket<SingleChannel>>) {
// Handle incoming connections
for (peer, new_state) in socket.update_peers() {
match new_state {
PeerState::Connected => {
info!("Peer {peer:?} connected");
}
PeerState::Disconnected => {
info!("Peer {peer:?} disconnected");
}
}
}
// Send data to all connected peers
let packet = b"Hello, decentralized world!";
socket.send(packet.into());
// Receive data from peers
for (peer, packet) in socket.receive() {
info!("Received from {peer:?}: {:?}", packet);
}
}For rollback netcode with GGRS:
use bevy_matchbox_nostr::prelude::*;
use bevy_ggrs::prelude::*;
fn start_ggrs_socket(mut commands: Commands) {
let nostr_keys = Keys::generate();
let socket = MatchboxSocket::new_ggrs(
"wss://relay.damus.io/fighting-game-room",
nostr_keys
);
commands.insert_resource(socket);
}This repository contains two main crates:
matchbox_socket_nostr: Core WebRTC socket implementation with Nostr signalingbevy_matchbox_nostr: Bevy integration providing Components, Resources, and Commands
Any Nostr relay that supports NIP-04 encrypted direct messages will work. Popular public relays include:
wss://relay.damus.iowss://nos.lolwss://relay.snort.socialwss://nostr.wine
For production games, consider running your own relay or using multiple relays for redundancy.
- Linux: ✅ Full support
- Windows: ✅ Full support
- macOS: ✅ Requires LLVM (see build notes below)
- iOS/Android: ✅ Via Bevy mobile support
- ✅ All modern browsers with WebRTC support
- ✅ Works with
wasm-bindgenandbevy_web
macOS requires LLVM for cryptographic compilation:
brew install llvm
export LLVM_PATH=$(brew --prefix llvm)
export AR="${LLVM_PATH}/bin/llvm-ar"
export CC="${LLVM_PATH}/bin/clang"
# For WASM target
cargo build --target wasm32-unknown-unknownMigrating from the original matchbox is straightforward:
// Before: Centralized matchbox
let socket = MatchboxSocket::new_reliable("wss://matchbox.example.com/room");
// After: Decentralized with Nostr
let nostr_keys = Keys::generate(); // or load existing keys
let socket = MatchboxSocket::new_reliable("wss://relay.damus.io/room", nostr_keys);The socket API remains identical - only the construction changes.
- Current: Bevy 0.15.x ✅
- Previous: Bevy 0.14.x ❌ (use earlier versions)
- Current: nostr 0.43.x with NIP-04 support ✅
- Previous: nostr 0.21.x ❌ (significant API changes)
- Development: Use
Keys::generate()for testing - Production: Implement proper key storage and recovery
- Privacy: Each game session can use different keys
- Relays only see encrypted signaling data (via NIP-04)
- Game data flows directly between peers via WebRTC
- Use multiple relays to avoid single points of failure
- All signaling encrypted with NIP-04 standard
- WebRTC provides end-to-end encryption for game data
- Peer authentication via Nostr cryptographic identities
Contributions welcome! This project follows the same patterns as the original Matchbox:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
git clone https://github.com/your-username/matchbox_nostr.git
cd matchbox_nostr
cargo test
cargo build- Examples: Complete working examples with different game types
- Relay Discovery: Automatic relay selection and failover
- Key Management: Integrated key storage solutions
- Performance: Benchmarks vs centralized signaling
- Mobile: Enhanced mobile platform support
- Nostr Extensions: Support for additional NIPs (Nostr Improvement Proposals)
- Matchbox: Original centralized WebRTC library for Bevy
- GGRS: Rollback netcode library with Bevy integration
- Nostr Protocol: Decentralized communication protocol specification
- rust-nostr: Rust implementation of Nostr protocol
- Johan Helsing for the original Matchbox library
- Ernest Wong for the Dango Tribute WebRTC experiment
- Nostr Community for building the decentralized communication protocol
- Bevy Community for the amazing game engine
This project is dual-licensed under:
- MIT License or http://opensource.org/licenses/MIT
- Apache License, Version 2.0 or http://www.apache.org/licenses/LICENSE-2.0
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Learn more about Nostr: nostr.org | Learn more about Bevy: bevyengine.org