diff --git a/src/components/CanvasEmbed.tsx b/src/components/CanvasEmbed.tsx
index 6eb6f0e..3cf19d8 100644
--- a/src/components/CanvasEmbed.tsx
+++ b/src/components/CanvasEmbed.tsx
@@ -1,14 +1,31 @@
'use client';
+import { useEffect, useCallback } from 'react';
+import { isCanvasMessage, CanvasShapeMessage } from '@/lib/canvas-sync';
+
interface CanvasEmbedProps {
canvasSlug: string;
className?: string;
+ onShapeUpdate?: (message: CanvasShapeMessage) => void;
}
-export function CanvasEmbed({ canvasSlug, className = '' }: CanvasEmbedProps) {
- const rspaceUrl = process.env.NEXT_PUBLIC_RSPACE_URL || 'https://rspace.online';
+export function CanvasEmbed({ canvasSlug, className = '', onShapeUpdate }: CanvasEmbedProps) {
const canvasUrl = `https://${canvasSlug}.rspace.online`;
+ const handleMessage = useCallback(
+ (event: MessageEvent) => {
+ if (!isCanvasMessage(event)) return;
+ if (event.data.communitySlug !== canvasSlug) return;
+ onShapeUpdate?.(event.data);
+ },
+ [canvasSlug, onShapeUpdate]
+ );
+
+ useEffect(() => {
+ window.addEventListener('message', handleMessage);
+ return () => window.removeEventListener('message', handleMessage);
+ }, [handleMessage]);
+
return (
{/* Toolbar */}
diff --git a/src/lib/canvas-sync.ts b/src/lib/canvas-sync.ts
new file mode 100644
index 0000000..2dddef8
--- /dev/null
+++ b/src/lib/canvas-sync.ts
@@ -0,0 +1,40 @@
+/**
+ * Canvas sync utilities for rtrips.online <-> rspace.online integration
+ *
+ * Listens for postMessage events from the embedded rspace canvas iframe
+ * and provides methods to push structured data to the canvas.
+ */
+
+export interface CanvasShapeMessage {
+ source: 'rspace-canvas';
+ type: 'shape-updated' | 'shape-deleted';
+ communitySlug: string;
+ shapeId: string;
+ data: Record;
+}
+
+export function isCanvasMessage(event: MessageEvent): event is MessageEvent {
+ return event.data?.source === 'rspace-canvas';
+}
+
+/**
+ * Push shapes to an rspace canvas community via the shapes API
+ */
+export async function pushShapesToCanvas(
+ canvasSlug: string,
+ shapes: Record[],
+ rspaceUrl?: string
+): Promise {
+ const baseUrl = rspaceUrl || process.env.RSPACE_INTERNAL_URL || 'http://rspace-online:3000';
+
+ const response = await fetch(`${baseUrl}/api/communities/${canvasSlug}/shapes`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ shapes }),
+ });
+
+ if (!response.ok) {
+ const text = await response.text();
+ throw new Error(`Failed to push shapes: ${response.status} ${text}`);
+ }
+}