diff --git a/.cursor/rules/snippet-to-example-rules.mdc b/.cursor/rules/snippet-to-example-rules.mdc
new file mode 100644
index 000000000..003a68386
--- /dev/null
+++ b/.cursor/rules/snippet-to-example-rules.mdc
@@ -0,0 +1,35 @@
+---
+description: 
+globs: 
+alwaysApply: false
+---
+
+# Converting a Snippet to Fullstack Example
+
+Create a new folder for our snippet inside of example folder .
+1. Copy `tsconfig.json`, `package.json`, `src/index.tsx`, `public/index.html`, `public/github.css`, and `.gitignore` from the `chat-room-react` example folder (1) into the new snippet example folder. (1: `examples/chat-room-react`)
+- Update index.html's github anchor link to point to `https://github.com/rivet-gg/actor-core/tree/main/examples/{insert example name}`
+2. Copy the `actor-json.ts` file from the snippet folder into the file `actors/app.ts` in the example folder. Make sure its being exported & setup correctly (see example from `chat-room-react/actors/app.ts`: )
+    ```
+    // We get rid of the default export
+    // export default ...
+
+    // and instead...
+    
+    // Create and export the app
+    export const app = setup({
+        actors: { actor },
+    });
+
+    // Export type for client type checking
+    export type App = typeof app;
+    ```
+3. Copy the `App.tsx` from the snippet folder into `src/App.tsx` file, and then make it export the main app class as `export default function ReactApp`
+4. Ask for user review at this point and see if you should continue. If you continue:
+5. Call `yarn install` and fix any type errors. Review to other `examples/*` folders for sample.
+
+# NOTES
+1. Everything should be installed wit yarn
+2. Environment variables should be used for any LLM calls
+- Make sure to use dotenv to put the env to use
+3. Feel free to install any missing packages that were present in the original snippet.
\ No newline at end of file
diff --git a/examples/chat-room-react/.gitignore b/examples/chat-room-react/.gitignore
new file mode 100644
index 000000000..6cbdaa262
--- /dev/null
+++ b/examples/chat-room-react/.gitignore
@@ -0,0 +1,4 @@
+.actorcore
+node_modules
+# React
+build/
\ No newline at end of file
diff --git a/examples/chat-room-react/actors/app.ts b/examples/chat-room-react/actors/app.ts
new file mode 100644
index 000000000..752cd884a
--- /dev/null
+++ b/examples/chat-room-react/actors/app.ts
@@ -0,0 +1,32 @@
+import { actor, setup } from "actor-core";
+
+export type Message = { sender: string; text: string; timestamp: number; }
+
+export const chatRoom = actor({
+  // State is automatically persisted
+  state: { 
+    messages: [] as Message[] 
+  },
+
+  actions: {
+    sendMessage: (c, sender: string, text: string) => {
+      const message = { sender, text, timestamp: Date.now() };
+      
+      // Any changes to state are automatically saved
+      c.state.messages.push(message);
+      
+      // Broadcast events trigger real-time updates in connected clients
+      c.broadcast("newMessage", message);
+    },
+
+    getHistory: (c) => c.state.messages
+  }
+});
+
+// Create and export the app
+export const app = setup({
+	actors: { chatRoom },
+});
+
+// Export type for client type checking
+export type App = typeof app;
diff --git a/examples/chat-room-react/package.json b/examples/chat-room-react/package.json
new file mode 100644
index 000000000..c0592d6e7
--- /dev/null
+++ b/examples/chat-room-react/package.json
@@ -0,0 +1,50 @@
+{
+  "name": "chat-room-react",
+  "version": "0.8.0",
+  "private": true,
+  "type": "module",
+  "main": "src/index.ts",
+  "scripts": {
+    "dev:actors": "npx @actor-core/cli@latest dev actors/app.ts",
+    "dev:frontend": "react-scripts start",
+    "build": "react-scripts build",
+    "check-types": "tsc --noEmit",
+    "test": "vitest run"
+  },
+  "dependencies": {
+    "@actor-core/react": "workspace:*",
+    "@types/react": "^19",
+    "@types/react-dom": "^19",
+    "actor-core": "workspace:*",
+    "react": "^19",
+    "react-dom": "^19",
+    "react-scripts": "^5.0.1"
+  },
+  "devDependencies": {
+    "@actor-core/cli": "workspace:*",
+    "actor-core": "workspace:*",
+    "typescript": "^5.5.2"
+  },
+  "example": {
+    "platforms": [
+      "*"
+    ]
+  },
+  "browserslist": {
+    "production": [
+      ">0.2%",
+      "not dead",
+      "not op_mini all"
+    ],
+    "development": [
+      "last 1 chrome version",
+      "last 1 firefox version",
+      "last 1 safari version"
+    ]
+  },
+  "resolutions": {
+    "react@^19": "^19.0.0",
+    "react-dom@^19": "^19.0.0",
+    "react@^18": "^18.3"
+  }
+}
diff --git a/examples/chat-room-react/public/github.css b/examples/chat-room-react/public/github.css
new file mode 100644
index 000000000..7e1e085cf
--- /dev/null
+++ b/examples/chat-room-react/public/github.css
@@ -0,0 +1,37 @@
+body, html {
+    margin: 0;
+    padding: 0;
+    padding-top: 24px;
+    width: 100%;
+    height: 100%;
+}
+#example--repo-ref {
+    position: fixed;
+    top: 0px;
+    left: 0px;
+    cursor: pointer;
+    background-color: rgb(243, 243, 243);
+    height: 24px;
+    width: 100%;
+    padding: 8px 8px;
+}
+#example--github-icon {
+    height: 24px;
+    float: left;
+}
+#example--repo-link {
+    height: 24px;
+    margin-left: 8px;
+    color: rgb(45, 50, 55);
+    font-weight: bold;
+    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
+    font-size: 15px;
+    vertical-align: middle;
+}
+
+#example--repo-ref:hover #example--repo-link {
+    color: black;
+}
+#example--repo-ref:hover svg {
+    fill: black !important;
+}
\ No newline at end of file
diff --git a/examples/chat-room-react/public/index.html b/examples/chat-room-react/public/index.html
new file mode 100644
index 000000000..9bad958c3
--- /dev/null
+++ b/examples/chat-room-react/public/index.html
@@ -0,0 +1,27 @@
+
+
+  
+    
+    
+    
+    Chat Room
+    
+  
+  
+    
+    
+    
+    
+
+    
+  
+
\ No newline at end of file
diff --git a/examples/chat-room-react/public/main.css b/examples/chat-room-react/public/main.css
new file mode 100644
index 000000000..a173b1eb4
--- /dev/null
+++ b/examples/chat-room-react/public/main.css
@@ -0,0 +1,100 @@
+body {
+  margin: 0;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+  background-color: rgb(180, 216, 255);
+}
+
+.chat-container {
+  max-width: 800px;
+  margin: 0 auto;
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+  display: flex;
+  flex-direction: column;
+  height: 80vh;
+}
+
+.room-header {
+  padding: 20px;
+  border-bottom: 1px solid #eee;
+}
+
+.room-header h3 {
+  margin: 0;
+  color: #333;
+}
+
+.messages {
+  flex: 1;
+  overflow-y: auto;
+  padding: 20px;
+}
+
+.message {
+  margin-bottom: 15px;
+  padding: 10px;
+  background: #f8f9fa;
+  border-radius: 8px;
+  position: relative;
+}
+
+.message b {
+  color: #2c5282;
+  margin-right: 8px;
+}
+
+.timestamp {
+  font-size: 0.8em;
+  color: #666;
+  position: absolute;
+  right: 10px;
+  top: 10px;
+}
+
+.empty-message {
+  text-align: center;
+  color: #666;
+  padding: 20px;
+  font-style: italic;
+}
+
+.input-area {
+  padding: 20px;
+  border-top: 1px solid #eee;
+  display: flex;
+  gap: 10px;
+}
+
+.input-area input {
+  flex: 1;
+  padding: 12px;
+  border: 1px solid #ddd;
+  border-radius: 6px;
+  font-size: 16px;
+  outline: none;
+  transition: border-color 0.2s;
+}
+
+.input-area input:focus {
+  border-color: #4299e1;
+}
+
+.input-area button {
+  padding: 12px 24px;
+  background: #4299e1;
+  color: white;
+  border: none;
+  border-radius: 6px;
+  font-size: 16px;
+  cursor: pointer;
+  transition: background-color 0.2s;
+}
+
+.input-area button:hover {
+  background: #3182ce;
+}
+
+.input-area button:active {
+  background: #2b6cb0;
+}
diff --git a/examples/chat-room-react/src/App.tsx b/examples/chat-room-react/src/App.tsx
new file mode 100644
index 000000000..241a13b31
--- /dev/null
+++ b/examples/chat-room-react/src/App.tsx
@@ -0,0 +1,70 @@
+import { createClient } from "actor-core/client";
+import { createReactActorCore } from "@actor-core/react";
+import { useState, useEffect } from "react";
+import type { App, Message } from "../actors/app";
+
+const client = createClient("http://localhost:6420");
+const { useActor, useActorEvent } = createReactActorCore(client);
+
+export default function ReactApp({ roomId = "general" }) {
+  // Connect to specific chat room using tags
+  const [{ actor }] = useActor("chatRoom", { 
+    tags: { roomId }
+  });
+  
+  const [messages, setMessages] = useState([]);
+  const [input, setInput] = useState("");
+
+  // Load initial state
+  useEffect(() => {
+    if (actor) {
+      // Load chat history
+      actor.getHistory().then(setMessages);
+    }
+  }, [actor]);
+
+  // Listen for real-time updates from the server
+  useActorEvent({ actor, event: "newMessage" }, (message) => {
+    setMessages(prev => [...prev, message as Message]);
+  });
+
+  const sendMessage = () => {
+    if (actor && input.trim()) {
+      actor.sendMessage("User", input);
+      setInput("");
+    }
+  };
+
+  return (
+    
+      
+        
Chat Room: {roomId}
+      
+      
+      
+        {messages.length === 0 ? (
+          
No messages yet. Start the conversation!
+        ) : (
+          messages.map((msg, i) => (
+            
+              {msg.sender}: {msg.text}
+              
+                {new Date(msg.timestamp).toLocaleTimeString()}
+              
+            
+          ))
+        )}
+      
+      
+      
+         setInput(e.target.value)}
+          onKeyDown={e => e.key === "Enter" && sendMessage()}
+          placeholder="Type a message..."
+        />
+        
+      
+