Collaborative UX sounds simple until you actually try to build it.
At the product level, the feature request usually sounds like this:
“Can we show who else is viewing this page?”
“Can we add multiplayer cursors?”
“Can teammates edit or review this together?”
“Can we show who is typing, selecting, or reacting in real time?”
But once you start implementing it, the feature quickly turns into infrastructure work.
You need transport handling.
Peer lifecycle.
Presence state.
Cursor sync.
Reconnect behavior.
Ephemeral awareness.
Shared state rules.
Sometimes auth.
Sometimes a relay.
Sometimes CRDTs.
And usually a lot of glue code before you even know whether the collaborative feature is useful.
That is the problem I wanted to solve with Roomful.
Roomful is an open-source, zero-backend, framework-agnostic SDK for adding realtime collaboration primitives to frontend apps.
The goal is simple:
Let frontend developers prototype and ship multiplayer UX without building custom realtime infrastructure from scratch.
GitHub: https://github.com/erayates/roomful
Website: https://www.roomful.dev/
Docs: https://docs.roomful.dev/
Demo: https://demo.roomful.dev/
What Roomful gives you
Roomful focuses on a small set of composable collaboration primitives:
- Presence — who is currently in the room
- Cursors — live pointer positions for multiplayer interfaces
- Shared state — synchronized values across peers
- Awareness — temporary UI context like typing, selection, focus, or active tool
- Events — fire-and-forget realtime signals for reactions, nudges, toasts, and product interactions
Instead of forcing every app into one specific collaboration model, Roomful gives you the building blocks.
You can use only presence.
Or only cursors.
Or shared state with awareness.
Or a full collaborative interface.
The SDK is designed to stay close to frontend product code instead of becoming a separate realtime backend project.
Why zero-backend matters
A lot of collaborative features die before they are properly validated.
Not because they are bad ideas.
Because the first version requires too much setup.
For example, imagine you want to add a basic “who is viewing this page?” feature to a dashboard or design review screen.
The product feature is small.
But the implementation can quickly require:
- WebSocket infrastructure
- connection state
- room management
- peer identity
- reconnect handling
- event broadcasting
- cleanup logic
- deployment
- usage billing decisions
That is too much weight for a feature that may still be experimental.
Roomful is built around a different path:
- Start with a frontend-first collaborative primitive.
- Use the transport that fits your current stage.
- Move to more controlled infrastructure only when you actually need it.
That means you can prototype with zero backend, then scale later without rewriting the product-level API.
The transport model
Roomful supports multiple transport modes behind the same collaboration primitives:
WebRTC
Useful when you want peer-to-peer rooms without running your own server from day one.
This works well for small rooms, prototypes, demos, and product experiments where direct peer communication is enough.
BroadcastChannel
Useful for same-device or local-first experiences.
For example:
- syncing state between tabs
- building local demos
- testing multiplayer flows without network infrastructure
- creating “collaboration-like” behavior on one machine
Self-hosted relay
When you need more control, Roomful can move to a self-hosted WebSocket relay.
That gives you a more production-oriented path with infrastructure you control, instead of forcing a hosted realtime service or usage-billed API into the first version.
The important part is that the product code should not need to care too much about which transport you started with.
You should be able to prototype fast, then graduate to a relay when the app needs it.
Basic example
Install the core package:
npm install @roomful/core
Create and connect to a room:
import { createRoom } from '@roomful/core';
const room = createRoom('my-first-room', {
transport: 'auto',
presence: {
name: 'Alice',
color: '#4F46E5',
},
});
await room.connect();
const presence = room.usePresence();
presence.subscribe((peers) => {
console.log('Peers in room:', peers.length);
});
window.addEventListener('beforeunload', () => {
void room.disconnect();
});
This is the core idea of Roomful:
- create a room
- connect peers
- subscribe to collaboration primitives
- render the result in your UI
No mandatory backend setup just to start.
React example
Roomful also includes framework adapters, including React.
A simplified React example can look like this:
import {
RoomfulProvider,
usePresence,
useCursors,
useSharedState,
} from '@roomful/react';
function DesignReview() {
return (
<RoomfulProvider
roomId="design-review"
presence={{ name: 'Ada' }}
>
<Canvas />
</RoomfulProvider>
);
}
function Canvas() {
const { others } = usePresence();
const [zoom, setZoom] = useSharedState('zoom', {
initialValue: 1,
});
useCursors();
return (
<p>
{others.length} teammates exploring at {zoom}×
</p>
);
}
This is the kind of developer experience I wanted:
- wrap the app or feature in a provider
- call hooks for presence, cursors, state, or awareness
- render realtime collaboration directly inside the product UI
Framework-agnostic by design
Roomful is not meant to be tied to one frontend stack.
The core package is framework-agnostic, and the project includes adapters for modern frontend frameworks.
The current package structure includes:
@roomful/core@roomful/react@roomful/vue@roomful/svelte@roomful/solid@roomful/angular@roomful/next@roomful/cursors@roomful/relay@roomful/devtools
The reason for this structure is practical.
Collaboration primitives should be reusable across stacks, but the developer experience should still feel native inside each framework.
React developers should get hooks and providers.
Vue developers should get composables.
Svelte developers should get stores and actions.
Angular and Solid should have their own natural integration patterns too.
The core concepts stay the same, but the framework surface should feel familiar.
What can you build with it?
Roomful is useful anywhere a product needs lightweight multiplayer behavior.
Some examples:
Design review tools
Show who is viewing a canvas, where their cursor is, what they selected, and which comment thread they are focused on.
Collaborative dashboards
Let teams inspect the same report or admin panel together with shared filters, live presence, and cursor context.
Local-first apps
Use BroadcastChannel to sync tabs or windows without network infrastructure.
Whiteboards and editors
Combine cursors, awareness, events, and shared state to build multiplayer interfaces.
Product review flows
Show who is currently reviewing, typing, approving, commenting, or reacting.
Internal tools
Add lightweight collaboration to tools where building full realtime infrastructure would not be worth the cost.
Why I built it this way
I did not want Roomful to be “magic.”
Magic abstractions often feel impressive in demos but become hard to control in real products.
The goal is different:
Make multiplayer UX composable, typed, and frontend-native.
That means Roomful should expose primitives that developers can understand and combine.
Presence should be presence.
Cursors should be cursors.
Awareness should be ephemeral UI context.
Events should be fire-and-forget signals.
Shared state should be explicit.
The SDK should remove repetitive infrastructure work, not hide every decision from the developer.
Where Roomful fits
Roomful is not trying to replace every realtime tool.
It is designed for frontend teams that want to add collaborative UX without immediately committing to a heavy infrastructure path.
A useful way to think about it:
- If you only need a managed realtime database, Roomful may not be the right abstraction.
- If you need low-level CRDT control from day one, you may want to work directly with CRDT libraries.
- If you want composable collaboration primitives that can start without backend infrastructure, Roomful is designed for that gap.
The project also supports Yjs-based CRDT usage when richer merge behavior is needed.
So the intent is not to avoid serious collaboration problems.
The intent is to make the first step much lighter.
Current status
Roomful is open source and MIT licensed.
The project includes:
- core collaboration primitives
- framework adapters
- transport support
- optional relay server
- package-level structure
- docs
- live demo
- Storybook
- contribution files
It is still early publicly, and I am looking for feedback from developers who build collaborative products, local-first tools, editors, whiteboards, dashboards, internal tools, or multiplayer interfaces.
What I want feedback on
The most useful feedback right now would be:
- Does the “zero-backend collaboration primitives” positioning make sense?
- Which primitive would you try first: presence, cursors, shared state, awareness, or events?
- Which example app would make the project easiest to understand?
- Does the API feel frontend-native enough?
- Which framework adapter matters most to you?
- Where would you expect Roomful to break in a real product?
- What would make you comfortable using it in production?
Try it
GitHub: https://github.com/erayates/roomful
Website: https://www.roomful.dev/
Docs: https://docs.roomful.dev/
Demo: https://demo.roomful.dev/
If Roomful looks useful, a star on GitHub helps other developers find it and helps me understand where to keep investing in docs, examples, and integrations.
I would also be interested in seeing what people build with it.
Top comments (0)