<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Eray Ateş</title>
    <description>The latest articles on DEV Community by Eray Ateş (@erayates).</description>
    <link>https://dev.to/erayates</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2147573%2F67554512-ff6d-4d1b-a695-4631d260304b.jpeg</url>
      <title>DEV Community: Eray Ateş</title>
      <link>https://dev.to/erayates</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/erayates"/>
    <language>en</language>
    <item>
      <title>How I Built Roomful: Zero-Backend Collaboration Primitives for Frontend Apps</title>
      <dc:creator>Eray Ateş</dc:creator>
      <pubDate>Mon, 29 Jun 2026 00:53:04 +0000</pubDate>
      <link>https://dev.to/erayates/how-i-built-roomful-zero-backend-collaboration-primitives-for-frontend-apps-3gia</link>
      <guid>https://dev.to/erayates/how-i-built-roomful-zero-backend-collaboration-primitives-for-frontend-apps-3gia</guid>
      <description>&lt;p&gt;Collaborative UX sounds simple until you actually try to build it.&lt;/p&gt;

&lt;p&gt;At the product level, the feature request usually sounds like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can we show who else is viewing this page?”&lt;br&gt;
“Can we add multiplayer cursors?”&lt;br&gt;
“Can teammates edit or review this together?”&lt;br&gt;
“Can we show who is typing, selecting, or reacting in real time?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But once you start implementing it, the feature quickly turns into infrastructure work.&lt;/p&gt;

&lt;p&gt;You need transport handling.&lt;br&gt;
Peer lifecycle.&lt;br&gt;
Presence state.&lt;br&gt;
Cursor sync.&lt;br&gt;
Reconnect behavior.&lt;br&gt;
Ephemeral awareness.&lt;br&gt;
Shared state rules.&lt;br&gt;
Sometimes auth.&lt;br&gt;
Sometimes a relay.&lt;br&gt;
Sometimes CRDTs.&lt;br&gt;
And usually a lot of glue code before you even know whether the collaborative feature is useful.&lt;/p&gt;

&lt;p&gt;That is the problem I wanted to solve with &lt;strong&gt;Roomful&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Roomful is an open-source, zero-backend, framework-agnostic SDK for adding realtime collaboration primitives to frontend apps.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let frontend developers prototype and ship multiplayer UX without building custom realtime infrastructure from scratch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/erayates/roomful" rel="noopener noreferrer"&gt;https://github.com/erayates/roomful&lt;/a&gt;&lt;br&gt;
Website: &lt;a href="https://www.roomful.dev/" rel="noopener noreferrer"&gt;https://www.roomful.dev/&lt;/a&gt;&lt;br&gt;
Docs: &lt;a href="https://docs.roomful.dev/" rel="noopener noreferrer"&gt;https://docs.roomful.dev/&lt;/a&gt;&lt;br&gt;
Demo: &lt;a href="https://demo.roomful.dev/" rel="noopener noreferrer"&gt;https://demo.roomful.dev/&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What Roomful gives you
&lt;/h2&gt;

&lt;p&gt;Roomful focuses on a small set of composable collaboration primitives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Presence&lt;/strong&gt; — who is currently in the room&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cursors&lt;/strong&gt; — live pointer positions for multiplayer interfaces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared state&lt;/strong&gt; — synchronized values across peers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Awareness&lt;/strong&gt; — temporary UI context like typing, selection, focus, or active tool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Events&lt;/strong&gt; — fire-and-forget realtime signals for reactions, nudges, toasts, and product interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of forcing every app into one specific collaboration model, Roomful gives you the building blocks.&lt;/p&gt;

&lt;p&gt;You can use only presence.&lt;br&gt;
Or only cursors.&lt;br&gt;
Or shared state with awareness.&lt;br&gt;
Or a full collaborative interface.&lt;/p&gt;

&lt;p&gt;The SDK is designed to stay close to frontend product code instead of becoming a separate realtime backend project.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why zero-backend matters
&lt;/h2&gt;

&lt;p&gt;A lot of collaborative features die before they are properly validated.&lt;/p&gt;

&lt;p&gt;Not because they are bad ideas.&lt;/p&gt;

&lt;p&gt;Because the first version requires too much setup.&lt;/p&gt;

&lt;p&gt;For example, imagine you want to add a basic “who is viewing this page?” feature to a dashboard or design review screen.&lt;/p&gt;

&lt;p&gt;The product feature is small.&lt;/p&gt;

&lt;p&gt;But the implementation can quickly require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSocket infrastructure&lt;/li&gt;
&lt;li&gt;connection state&lt;/li&gt;
&lt;li&gt;room management&lt;/li&gt;
&lt;li&gt;peer identity&lt;/li&gt;
&lt;li&gt;reconnect handling&lt;/li&gt;
&lt;li&gt;event broadcasting&lt;/li&gt;
&lt;li&gt;cleanup logic&lt;/li&gt;
&lt;li&gt;deployment&lt;/li&gt;
&lt;li&gt;usage billing decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is too much weight for a feature that may still be experimental.&lt;/p&gt;

&lt;p&gt;Roomful is built around a different path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with a frontend-first collaborative primitive.&lt;/li&gt;
&lt;li&gt;Use the transport that fits your current stage.&lt;/li&gt;
&lt;li&gt;Move to more controlled infrastructure only when you actually need it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That means you can prototype with zero backend, then scale later without rewriting the product-level API.&lt;/p&gt;


&lt;h2&gt;
  
  
  The transport model
&lt;/h2&gt;

&lt;p&gt;Roomful supports multiple transport modes behind the same collaboration primitives:&lt;/p&gt;
&lt;h3&gt;
  
  
  WebRTC
&lt;/h3&gt;

&lt;p&gt;Useful when you want peer-to-peer rooms without running your own server from day one.&lt;/p&gt;

&lt;p&gt;This works well for small rooms, prototypes, demos, and product experiments where direct peer communication is enough.&lt;/p&gt;
&lt;h3&gt;
  
  
  BroadcastChannel
&lt;/h3&gt;

&lt;p&gt;Useful for same-device or local-first experiences.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;syncing state between tabs&lt;/li&gt;
&lt;li&gt;building local demos&lt;/li&gt;
&lt;li&gt;testing multiplayer flows without network infrastructure&lt;/li&gt;
&lt;li&gt;creating “collaboration-like” behavior on one machine&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Self-hosted relay
&lt;/h3&gt;

&lt;p&gt;When you need more control, Roomful can move to a self-hosted WebSocket relay.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The important part is that the product code should not need to care too much about which transport you started with.&lt;/p&gt;

&lt;p&gt;You should be able to prototype fast, then graduate to a relay when the app needs it.&lt;/p&gt;


&lt;h2&gt;
  
  
  Basic example
&lt;/h2&gt;

&lt;p&gt;Install the core package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @roomful/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create and connect to a room:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRoom&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@roomful/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-first-room&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#4F46E5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;presence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;usePresence&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;peers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Peers in room:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;peers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beforeunload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the core idea of Roomful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a room&lt;/li&gt;
&lt;li&gt;connect peers&lt;/li&gt;
&lt;li&gt;subscribe to collaboration primitives&lt;/li&gt;
&lt;li&gt;render the result in your UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No mandatory backend setup just to start.&lt;/p&gt;




&lt;h2&gt;
  
  
  React example
&lt;/h2&gt;

&lt;p&gt;Roomful also includes framework adapters, including React.&lt;/p&gt;

&lt;p&gt;A simplified React example can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;RoomfulProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;usePresence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useCursors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useSharedState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@roomful/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DesignReview&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RoomfulProvider&lt;/span&gt;
      &lt;span class="na"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"design-review"&lt;/span&gt;
      &lt;span class="na"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ada&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Canvas&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RoomfulProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Canvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;others&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePresence&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setZoom&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSharedState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zoom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;useCursors&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; teammates exploring at &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;zoom&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;×
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the kind of developer experience I wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wrap the app or feature in a provider&lt;/li&gt;
&lt;li&gt;call hooks for presence, cursors, state, or awareness&lt;/li&gt;
&lt;li&gt;render realtime collaboration directly inside the product UI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Framework-agnostic by design
&lt;/h2&gt;

&lt;p&gt;Roomful is not meant to be tied to one frontend stack.&lt;/p&gt;

&lt;p&gt;The core package is framework-agnostic, and the project includes adapters for modern frontend frameworks.&lt;/p&gt;

&lt;p&gt;The current package structure includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@roomful/core&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@roomful/react&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@roomful/vue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@roomful/svelte&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@roomful/solid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@roomful/angular&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@roomful/next&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@roomful/cursors&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@roomful/relay&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@roomful/devtools&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reason for this structure is practical.&lt;/p&gt;

&lt;p&gt;Collaboration primitives should be reusable across stacks, but the developer experience should still feel native inside each framework.&lt;/p&gt;

&lt;p&gt;React developers should get hooks and providers.&lt;br&gt;
Vue developers should get composables.&lt;br&gt;
Svelte developers should get stores and actions.&lt;br&gt;
Angular and Solid should have their own natural integration patterns too.&lt;/p&gt;

&lt;p&gt;The core concepts stay the same, but the framework surface should feel familiar.&lt;/p&gt;




&lt;h2&gt;
  
  
  What can you build with it?
&lt;/h2&gt;

&lt;p&gt;Roomful is useful anywhere a product needs lightweight multiplayer behavior.&lt;/p&gt;

&lt;p&gt;Some examples:&lt;/p&gt;

&lt;h3&gt;
  
  
  Design review tools
&lt;/h3&gt;

&lt;p&gt;Show who is viewing a canvas, where their cursor is, what they selected, and which comment thread they are focused on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Collaborative dashboards
&lt;/h3&gt;

&lt;p&gt;Let teams inspect the same report or admin panel together with shared filters, live presence, and cursor context.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local-first apps
&lt;/h3&gt;

&lt;p&gt;Use BroadcastChannel to sync tabs or windows without network infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Whiteboards and editors
&lt;/h3&gt;

&lt;p&gt;Combine cursors, awareness, events, and shared state to build multiplayer interfaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Product review flows
&lt;/h3&gt;

&lt;p&gt;Show who is currently reviewing, typing, approving, commenting, or reacting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Internal tools
&lt;/h3&gt;

&lt;p&gt;Add lightweight collaboration to tools where building full realtime infrastructure would not be worth the cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I built it this way
&lt;/h2&gt;

&lt;p&gt;I did not want Roomful to be “magic.”&lt;/p&gt;

&lt;p&gt;Magic abstractions often feel impressive in demos but become hard to control in real products.&lt;/p&gt;

&lt;p&gt;The goal is different:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make multiplayer UX composable, typed, and frontend-native.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That means Roomful should expose primitives that developers can understand and combine.&lt;/p&gt;

&lt;p&gt;Presence should be presence.&lt;br&gt;
Cursors should be cursors.&lt;br&gt;
Awareness should be ephemeral UI context.&lt;br&gt;
Events should be fire-and-forget signals.&lt;br&gt;
Shared state should be explicit.&lt;/p&gt;

&lt;p&gt;The SDK should remove repetitive infrastructure work, not hide every decision from the developer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Roomful fits
&lt;/h2&gt;

&lt;p&gt;Roomful is not trying to replace every realtime tool.&lt;/p&gt;

&lt;p&gt;It is designed for frontend teams that want to add collaborative UX without immediately committing to a heavy infrastructure path.&lt;/p&gt;

&lt;p&gt;A useful way to think about it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you only need a managed realtime database, Roomful may not be the right abstraction.&lt;/li&gt;
&lt;li&gt;If you need low-level CRDT control from day one, you may want to work directly with CRDT libraries.&lt;/li&gt;
&lt;li&gt;If you want composable collaboration primitives that can start without backend infrastructure, Roomful is designed for that gap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project also supports Yjs-based CRDT usage when richer merge behavior is needed.&lt;/p&gt;

&lt;p&gt;So the intent is not to avoid serious collaboration problems.&lt;/p&gt;

&lt;p&gt;The intent is to make the first step much lighter.&lt;/p&gt;




&lt;h2&gt;
  
  
  Current status
&lt;/h2&gt;

&lt;p&gt;Roomful is open source and MIT licensed.&lt;/p&gt;

&lt;p&gt;The project includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;core collaboration primitives&lt;/li&gt;
&lt;li&gt;framework adapters&lt;/li&gt;
&lt;li&gt;transport support&lt;/li&gt;
&lt;li&gt;optional relay server&lt;/li&gt;
&lt;li&gt;package-level structure&lt;/li&gt;
&lt;li&gt;docs&lt;/li&gt;
&lt;li&gt;live demo&lt;/li&gt;
&lt;li&gt;Storybook&lt;/li&gt;
&lt;li&gt;contribution files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I want feedback on
&lt;/h2&gt;

&lt;p&gt;The most useful feedback right now would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the “zero-backend collaboration primitives” positioning make sense?&lt;/li&gt;
&lt;li&gt;Which primitive would you try first: presence, cursors, shared state, awareness, or events?&lt;/li&gt;
&lt;li&gt;Which example app would make the project easiest to understand?&lt;/li&gt;
&lt;li&gt;Does the API feel frontend-native enough?&lt;/li&gt;
&lt;li&gt;Which framework adapter matters most to you?&lt;/li&gt;
&lt;li&gt;Where would you expect Roomful to break in a real product?&lt;/li&gt;
&lt;li&gt;What would make you comfortable using it in production?&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/erayates/roomful" rel="noopener noreferrer"&gt;https://github.com/erayates/roomful&lt;/a&gt;&lt;br&gt;
Website: &lt;a href="https://www.roomful.dev/" rel="noopener noreferrer"&gt;https://www.roomful.dev/&lt;/a&gt;&lt;br&gt;
Docs: &lt;a href="https://docs.roomful.dev/" rel="noopener noreferrer"&gt;https://docs.roomful.dev/&lt;/a&gt;&lt;br&gt;
Demo: &lt;a href="https://demo.roomful.dev/" rel="noopener noreferrer"&gt;https://demo.roomful.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I would also be interested in seeing what people build with it.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
