


























@@ -1,199 +1,78 @@
1-# Canvas Skill
1+---
2+name: canvas
3+description: "Present HTML on connected OpenClaw node canvases, navigate/eval/snapshot, and debug canvas host URLs."
4+metadata: { "openclaw": { "emoji": "🖼️" } }
5+---
263-Display HTML content on connected OpenClaw nodes (Mac app, iOS, Android).
7+# Canvas
485-## Overview
9+Use canvas to show HTML on connected Mac/iOS/Android nodes.
6107-The canvas tool lets you present web content on any connected node's canvas view. Great for:
11+## Model
8129-- Displaying games, visualizations, dashboards
10-- Showing generated HTML content
11-- Interactive demos
13+- Canvas host serves files from `plugins.entries.canvas.config.host.root`.
14+- Canvas routes live on the Gateway HTTP port (`gateway.port`, default `18789`).
15+- Node bridge sends canvas URLs to connected node apps.
16+- Node apps render URLs in a WebView.
17+- Host name follows `gateway.bind`: loopback local only, LAN IP for LAN, Tailscale host for tailnet, auto picks best route.
18+- Localhost URLs only work for a node on the same machine.
19+- Paired nodes normally receive node-scoped `pluginSurfaceUrls.canvas` capability URLs; prefer those when available.
122013-## How It Works
21+## Config
142215-### Architecture
16-17-```
18-┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐
19-│ Canvas Host │────▶│ Node Bridge │────▶│ Node App │
20-│ (HTTP Server) │ │ (TCP Server) │ │ (Mac/iOS/ │
21-│ Port 18793 │ │ Port 18790 │ │ Android) │
22-└─────────────────┘ └──────────────────┘ └─────────────┘
23-```
24-25-1. **Canvas Host Server**: Serves static HTML/CSS/JS files from `canvasHost.root` directory
26-2. **Node Bridge**: Communicates canvas URLs to connected nodes
27-3. **Node Apps**: Render the content in a WebView
28-29-### Tailscale Integration
30-31-The canvas host server binds based on `gateway.bind` setting:
32-33-| Bind Mode | Server Binds To | Canvas URL Uses |
34-| ---------- | ------------------- | -------------------------- |
35-| `loopback` | 127.0.0.1 | localhost (local only) |
36-| `lan` | LAN interface | LAN IP address |
37-| `tailnet` | Tailscale interface | Tailscale hostname |
38-| `auto` | Best available | Tailscale > LAN > loopback |
39-40-**Key insight:** The `canvasHostHostForBridge` is derived from `bridgeHost`. When bound to Tailscale, nodes receive URLs like:
41-42-```
43-http://<tailscale-hostname>:18793/__openclaw__/canvas/<file>.html
44-```
45-46-This is why localhost URLs don't work - the node receives the Tailscale hostname from the bridge!
47-48-## Actions
49-50-| Action | Description |
51-| ---------- | ------------------------------------ |
52-| `present` | Show canvas with optional target URL |
53-| `hide` | Hide the canvas |
54-| `navigate` | Navigate to a new URL |
55-| `eval` | Execute JavaScript in the canvas |
56-| `snapshot` | Capture screenshot of canvas |
57-58-## Configuration
59-60-In the active OpenClaw config file (`$OPENCLAW_CONFIG_PATH`, default `~/.openclaw/openclaw.json`):
23+Active config: `$OPENCLAW_CONFIG_PATH` or `~/.openclaw/openclaw.json`.
61246225```json
6326{
64-"canvasHost": {
65-"enabled": true,
66-"port": 18793,
67-"root": "/Users/you/clawd/canvas",
68-"liveReload": true
27+"plugins": {
28+"entries": {
29+"canvas": {
30+"config": {
31+"host": {
32+"enabled": true,
33+"root": "~/.openclaw/canvas",
34+"liveReload": true
35+ }
36+ }
37+ }
38+ }
6939 },
70-"gateway": {
71-"bind": "auto"
72- }
40+"gateway": { "bind": "auto" }
7341}
7442```
754376-### Live Reload
77-78-When `liveReload: true` (default), the canvas host:
79-80-- Watches the root directory for changes (via chokidar)
81-- Injects a WebSocket client into HTML files
82-- Automatically reloads connected canvases when files change
44+## Actions
834584-Great for development!
46+- `present`: show canvas, optional URL.
47+- `hide`: hide canvas.
48+- `navigate`: open new URL.
49+- `eval`: run JavaScript in current canvas.
50+- `snapshot`: capture screenshot.
85518652## Workflow
875388-### 1. Create HTML content
89-90-Place files in the canvas root directory (default `~/clawd/canvas/`):
91-92-```bash
93-cat > ~/clawd/canvas/my-game.html << 'HTML'
94-<!DOCTYPE html>
95-<html>
96-<head><title>My Game</title></head>
97-<body>
98- <h1>Hello Canvas!</h1>
99-</body>
100-</html>
101-HTML
102-```
103-104-### 2. Find your canvas host URL
105-106-Check how your gateway is bound:
107-108-```bash
109-CONFIG_PATH="${OPENCLAW_CONFIG_PATH:-${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/openclaw.json}"
110-cat "$CONFIG_PATH" | jq '.gateway.bind'
111-```
112-113-Then construct the URL:
114-115-- **loopback**: `http://127.0.0.1:18793/__openclaw__/canvas/<file>.html`
116-- **lan/tailnet/auto**: `http://<hostname>:18793/__openclaw__/canvas/<file>.html`
117-118-Find your Tailscale hostname:
119-120-```bash
121-tailscale status --json | jq -r '.Self.DNSName' | sed 's/\.$//'
122-```
123-124-### 3. Find connected nodes
125-126-```bash
127-openclaw nodes list
128-```
129-130-Look for Mac/iOS/Android nodes with canvas capability.
131-132-### 4. Present content
133-134-```
135-canvas action:present node:<node-id> target:<full-url>
136-```
137-138-**Example:**
139-140-```
141-canvas action:present node:mac-63599bc4-b54d-4392-9048-b97abd58343a target:http://peters-mac-studio-1.sheep-coho.ts.net:18793/__openclaw__/canvas/snake.html
142-```
54+1. Ensure Canvas plugin host is enabled.
55+2. Put HTML/CSS/JS under `plugins.entries.canvas.config.host.root` or the default state canvas dir.
56+3. Use a route reachable by the target node.
57+4. Present the hosted URL: `/__openclaw__/canvas/<file>.html`.
58+5. Use `snapshot` when the user needs proof.
14359144-### 5. Navigate, snapshot, or hide
60+## URL shape
1456162+```text
63+http://<gateway-host>:<gateway.port>/__openclaw__/canvas/index.html
64+http://<gateway-host>:<gateway.port>/__openclaw__/canvas/games/snake.html
14665```
147-canvas action:navigate node:<node-id> url:<new-url>
148-canvas action:snapshot node:<node-id>
149-canvas action:hide node:<node-id>
150-```
151-152-## Debugging
153-154-### White screen / content not loading
15566156-**Cause:** URL mismatch between server bind and node expectation.
157-158-**Debug steps:**
159-160-1. Check server bind: `CONFIG_PATH="${OPENCLAW_CONFIG_PATH:-${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/openclaw.json}"; cat "$CONFIG_PATH" | jq '.gateway.bind'`
161-2. Check what port canvas is on: `lsof -i :18793`
162-3. Test URL directly: `curl http://<hostname>:18793/__openclaw__/canvas/<file>.html`
163-164-**Solution:** Use the full hostname matching your bind mode, not localhost.
165-166-### "node required" error
167-168-Always specify `node:<node-id>` parameter.
169-170-### "node not connected" error
171-172-Node is offline. Use `openclaw nodes list` to find online nodes.
173-174-### Content not updating
175-176-If live reload isn't working:
177-178-1. Check `liveReload: true` in config
179-2. Ensure file is in the canvas root directory
180-3. Check for watcher errors in logs
181-182-## URL Path Structure
183-184-The canvas host serves from `/__openclaw__/canvas/` prefix:
185-186-```
187-http://<host>:18793/__openclaw__/canvas/index.html → ~/clawd/canvas/index.html
188-http://<host>:18793/__openclaw__/canvas/games/snake.html → ~/clawd/canvas/games/snake.html
189-```
67+Path mapping:
19068191-The `/__openclaw__/canvas/` prefix is defined by `CANVAS_HOST_PATH` constant.
69+- `/__openclaw__/canvas/index.html` -> `<canvas host root>/index.html`
70+- `/__openclaw__/canvas/games/snake.html` -> `<canvas host root>/games/snake.html`
19271193-## Tips
72+## Troubleshooting
19473195-- Keep HTML self-contained (inline CSS/JS) for best results
196-- Use the default index.html as a test page (has bridge diagnostics)
197-- The canvas persists until you `hide` it or navigate away
198-- Live reload makes development fast - just save and it updates!
199-- A2UI JSON push is WIP - use HTML files for now
74+- Node sees localhost but is remote: fix `gateway.bind` or public URL, regenerate URL.
75+- LAN node cannot load: verify same network, firewall, Gateway port, and auth/capability URL.
76+- Tailnet node cannot load: verify Tailscale status and advertised host.
77+- Blank page: open URL locally, check browser console, then snapshot node.
78+- Live reload missing: verify `liveReload` and file write under root.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。