Browser mesh.
No servers in the data path.
Drop one <script> tag into any web page โ Bitcoin inscription, static site, browser extension. Every other instance finds it, meshes up, and exchanges data end-to-end encrypted โ direct peer-to-peer.
๐ End-to-end encrypted
AES-GCM 256-bit keys derived from the room id. The relay sees only ciphertext.
โก Direct peer-to-peer
Once browsers exchange SDP through the relay, all data flows direct. The relay drops out of the path.
๐ Inscription sandbox escape
Bitcoin inscriptions block fetch() and WebSocket. Lumamesh uses WebRTC DataChannels โ the one network primitive that still works. The relay SDP is static and embedded, so zero external fetches are needed to connect.
๐ Community relays
Anyone can run a relay node. The network discovers nodes automatically โ no curator required.
Integrate in 5 lines
In a Bitcoin inscription (on-chain import โ no external fetches)
Inscriptions run in a strict sandbox where fetch() and external imports are blocked. Import the library by its inscription ID โ the content is served from the same ordinals node, so no external network call is needed:
<script type="module">
// Replace LIB_INSCRIPTION_ID with the inscription id of lumamesh.js
import { connect } from '/r/content/LIB_INSCRIPTION_ID';
const net = await connect();
const room = await net.joinRoom('my-game-lobby', { nick: 'alice' });
room.on('peer', peer => {
peer.on('open', () => peer.send({ hello: 'world' }));
peer.on('data', msg => console.log(peer.nick, msg));
});
room.broadcast({ text: 'hi everyone' });
</script>
This is the reason Lumamesh exists: WebRTC DataChannels are the only way to open a network connection from inside an inscription sandbox. The relay is bootstrapped from a static SDP offer embedded on the page โ zero external fetches needed to open the relay connection.
In a regular web page or browser extension
<script type="module">
import { connect } from 'https://lumamesh.com/lumamesh.js';
const net = await connect();
const room = await net.joinRoom('my-app-lobby', { nick: 'alice' });
room.on('peer', peer => {
peer.on('open', () => peer.send({ hello: 'world' }));
peer.on('data', msg => console.log(peer.nick, msg));
});
</script>
Send game state (60 Hz unreliable)
room.broadcast({ x, y, angle }, { reliable: false });
Private rooms
const room = await net.joinRoom('lobby', {
secret: location.hash.slice(1) // #key never sent to servers
});
Media (camera / screen / mic)
const cam = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
room.publish(cam, { kind: 'cam' });
room.on('peer', peer => {
peer.on('track', ({ stream, kind }) => {
document.querySelector('video').srcObject = stream;
});
});
How it works
Lumamesh has two layers:
Layer 1 โ A signaling-free WebRTC DataChannel to a community relay. No HTTP, no WebSocket โ just a single UDP port. Works inside the strictest browser sandboxes.
Layer 2 โ Full mesh RTCPeerConnection between browsers, signaled over Layer 1. Once connected, the relay is out of the data path entirely.
The relay config (IP, DTLS fingerprint, node identity key) is stored as a Bitcoin inscription and fetched at connect time. Re-inscribing rotates the network config for every consumer on next page load โ the library itself never changes.