diff --git a/skills/canvas/SKILL.md b/skills/canvas/SKILL.md index db0e54fed..f93a3251f 100644 --- a/skills/canvas/SKILL.md +++ b/skills/canvas/SKILL.md @@ -9,24 +9,84 @@ The canvas tool lets you present web content on any connected node's canvas view - Showing generated HTML content - Interactive demos +## How It Works + +### Architecture + +``` +┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐ +│ Canvas Host │────▶│ Node Bridge │────▶│ Node App │ +│ (HTTP Server) │ │ (TCP Server) │ │ (Mac/iOS/ │ +│ Port 18793 │ │ Port 18790 │ │ Android) │ +└─────────────────┘ └──────────────────┘ └─────────────┘ +``` + +1. **Canvas Host Server**: Serves static HTML/CSS/JS files from `canvasHost.root` directory +2. **Node Bridge**: Communicates canvas URLs to connected nodes +3. **Node Apps**: Render the content in a WebView + +### Tailscale Integration + +The canvas host server binds based on `gateway.bind` setting: + +| Bind Mode | Server Binds To | Canvas URL Uses | +|-----------|-----------------|-----------------| +| `loopback` | 127.0.0.1 | localhost (local only) | +| `lan` | LAN interface | LAN IP address | +| `tailnet` | Tailscale interface | Tailscale hostname | +| `auto` | Best available | Tailscale > LAN > loopback | + +**Key insight:** The `canvasHostHostForBridge` is derived from `bridgeHost`. When bound to Tailscale, nodes receive URLs like: +``` +http://:18793/__clawdbot__/canvas/.html +``` + +This is why localhost URLs don't work - the node receives the Tailscale hostname from the bridge! + ## Actions | Action | Description | |--------|-------------| -| `present` | Show the canvas with optional URL | +| `present` | Show canvas with optional target URL | | `hide` | Hide the canvas | | `navigate` | Navigate to a new URL | | `eval` | Execute JavaScript in the canvas | | `snapshot` | Capture screenshot of canvas | +## Configuration + +In `~/.clawdbot/clawdbot.json`: + +```json +{ + "canvasHost": { + "enabled": true, + "port": 18793, + "root": "/Users/you/clawd/canvas", + "liveReload": true + }, + "gateway": { + "bind": "auto" + } +} +``` + +### Live Reload + +When `liveReload: true` (default), the canvas host: +- Watches the root directory for changes (via chokidar) +- Injects a WebSocket client into HTML files +- Automatically reloads connected canvases when files change + +Great for development! + ## Workflow ### 1. Create HTML content -Place HTML files in the canvas directory (configured in `canvasHost.root`, typically `~/clawd/canvas/`): +Place files in the canvas root directory (default `~/clawd/canvas/`): ```bash -# Write your HTML file cat > ~/clawd/canvas/my-game.html << 'HTML' @@ -38,26 +98,34 @@ cat > ~/clawd/canvas/my-game.html << 'HTML' HTML ``` -### 2. Find a connected node +### 2. Find your canvas host URL + +Check how your gateway is bound: +```bash +cat ~/.clawdbot/clawdbot.json | jq '.gateway.bind' +``` + +Then construct the URL: +- **loopback**: `http://127.0.0.1:18793/__clawdbot__/canvas/.html` +- **lan/tailnet/auto**: `http://:18793/__clawdbot__/canvas/.html` + +Find your Tailscale hostname: +```bash +tailscale status --json | jq -r '.Self.DNSName' | sed 's/\.$//' +``` + +### 3. Find connected nodes -List available nodes: ```bash clawdbot nodes list ``` -Look for nodes with canvas capability (Mac/iOS/Android apps). +Look for Mac/iOS/Android nodes with canvas capability. -### 3. Present the content +### 4. Present content ``` -canvas action:present node: target: -``` - -**Important:** The canvas host server binds to the Tailscale hostname, not localhost! - -**Correct URL format:** -``` -http://:18793/__clawdbot__/canvas/.html +canvas action:present node: target: ``` **Example:** @@ -65,94 +133,57 @@ http://:18793/__clawdbot__/canvas/.html canvas action:present node:mac-63599bc4-b54d-4392-9048-b97abd58343a target:http://peters-mac-studio-1.sheep-coho.ts.net:18793/__clawdbot__/canvas/snake.html ``` -### 4. Navigate to different content +### 5. Navigate, snapshot, or hide ``` canvas action:navigate node: url: -``` - -### 5. Take a screenshot - -``` canvas action:snapshot node: -``` - -### 6. Hide when done - -``` canvas action:hide node: ``` -## Configuration - -In `~/.clawdbot/clawdbot.json`: - -```json -{ - "canvasHost": { - "enabled": true, - "port": 18793, - "root": "/Users/you/clawd/canvas" - } -} -``` - -## Common Issues +## Debugging ### White screen / content not loading -**Problem:** Canvas shows white/blank screen. +**Cause:** URL mismatch between server bind and node expectation. -**Solution:** The canvas host server binds to Tailscale hostname. Use the full URL: -``` -http://:18793/__clawdbot__/canvas/.html -``` +**Debug steps:** +1. Check server bind: `cat ~/.clawdbot/clawdbot.json | jq '.gateway.bind'` +2. Check what port canvas is on: `lsof -i :18793` +3. Test URL directly: `curl http://:18793/__clawdbot__/canvas/.html` -NOT: -``` -http://127.0.0.1:18793/... ❌ -http://localhost:18793/... ❌ -``` +**Solution:** Use the full hostname matching your bind mode, not localhost. ### "node required" error -**Solution:** Always specify the `node` parameter with a valid node ID from `clawdbot nodes list`. +Always specify `node:` parameter. ### "node not connected" error -**Solution:** The specified node is offline. Choose a different node that's currently connected. +Node is offline. Use `clawdbot nodes list` to find online nodes. -### A2UI formats not working +### Content not updating -A2UI JSON push formats are WIP. Use HTML files instead. +If live reload isn't working: +1. Check `liveReload: true` in config +2. Ensure file is in the canvas root directory +3. Check for watcher errors in logs + +## URL Path Structure + +The canvas host serves from `/__clawdbot__/canvas/` prefix: + +``` +http://:18793/__clawdbot__/canvas/index.html → ~/clawd/canvas/index.html +http://:18793/__clawdbot__/canvas/games/snake.html → ~/clawd/canvas/games/snake.html +``` + +The `/__clawdbot__/canvas/` prefix is defined by `CANVAS_HOST_PATH` constant. ## Tips - Keep HTML self-contained (inline CSS/JS) for best results -- Test your HTML locally first before presenting -- Use `snapshot` to capture what the canvas is showing +- Use the default index.html as a test page (has bridge diagnostics) - The canvas persists until you `hide` it or navigate away - -## Example: Quick Game Display - -```bash -# 1. Create game HTML -cat > ~/clawd/canvas/game.html << 'HTML' - - - - Quick Game - - - -

🎮 Game Time!

- - -HTML - -# 2. Present it (replace with your node ID and hostname) -canvas action:present node:mac-xxx target:http://your-hostname:18793/__clawdbot__/canvas/game.html -``` +- Live reload makes development fast - just save and it updates! +- A2UI JSON push is WIP - use HTML files for now