介绍
# Canvas OS
Canvas 作为一个应用平台。在 OpenClaw Canvas 上构建、存储和运行丰富的可视化应用。
## 理念
你是一个操作系统。Canvas 是窗口。应用在本地构建,并在 Canvas 上运行。
**富 HTML/CSS/JS UI** —— 不仅仅是文本。完全的交互性、动画、实时数据。
## 快速命令
| 命令 | Jarvis 做什么 | |---------|------------------| | "Open [app]" | 启动服务器,导航 Canvas,注入数据 | | "Build me a [type]" | 从模板创建应用,打开它 | | "Update [element]" | 注入 JS 以实时修改 | | "Show [data] on canvas" | 快速 A2UI 显示 | | "Close canvas" | 停止服务器,隐藏 Canvas |
## 工作原理
**关键原则:** 应用运行在 **Canvas** 上,而不是浏览器标签页中。Canvas 是你的 UI 窗口。
### Canvas 加载方法
Canvas 具有**安全限制**,会阻止文件路径访问。有三种方法可行:
| 方法 | 何时使用 | 优点 | 缺点 | |--------|-------------|------|------| | **Localhost Server** | 复杂应用,外部资源 | 完整的浏览器功能 | 需要端口管理 | | **Direct HTML Injection** | 快速显示,演示 | 即时,无需服务器 | 无外部资源,大小限制 | | **Data URLs** | 小内容 | 自包含 | 在某些系统上不可靠 |
**❌ 不工作:** `file:///path/to/file.html`(被 Canvas 安全机制阻止)
**📖 参见:** `CANVAS-LOADING-中文.md` 以获取详细指南 + 故障排除
**辅助脚本:** `canvas-inject.py` — 格式化 HTML 以直接注入
### 1. 应用是 HTML/CSS/JS 文件 ``` ~/.openclaw/workspace/apps/[app-name]/ ├── index.html # The UI (self-contained recommended) ├── data.json # Persistent state └── manifest.json # App metadata ```
### 2. 通过 localhost 服务 ```bash cd ~/.openclaw/workspace/apps/[app-name] python3 -m http.server [PORT] > /dev/null 2>&1 & ```
### 3. 将 **Canvas** 导航到 localhost ```bash NODE="Your Node Name" # Get from: openclaw nodes status openclaw nodes canvas navigate --node "$NODE" "http://localhost:[PORT]/" ```
**重要:** 这会在 **Canvas**(可视化面板)上打开应用,而不是在浏览器中。
### 4. Agent 通过 JS eval 注入数据 ```bash openclaw nodes canvas eval --node "$NODE" --js "app.setData({...})" ```
**注意:** `openclaw-canvas://` URL 协议在当前 OpenClaw 版本中存在问题。请改用 `http://localhost:`。
## 打开应用
**作用:** 在 **Canvas**(可视化面板)上显示应用,而不是在浏览器标签页中。
### 方法 1:Localhost 服务器(推荐用于复杂应用)
完整流程: ```bash NODE="Your Node Name" PORT=9876 APP="my-app"
# 1. Kill any existing server on the port lsof -ti:$PORT | xargs kill -9 2>/dev/null
# 2. Start server cd ~/.openclaw/workspace/apps/$APP python3 -m http.server $PORT > /dev/null 2>&1 &
# 3. Wait for server sleep 1
# 4. Navigate Canvas openclaw nodes canvas navigate --node "$NODE" "http://localhost:$PORT/"
# 5. Inject data openclaw nodes canvas eval --node "$NODE" --js "app.loadData({...})" ```
### 方法 2:直接 HTML 注入(用于快速显示)
**何时使用:** 文件路径在 Canvas 中不起作用(安全沙箱)。Data URL 可能不可靠。使用此方法可在无需 localhost 的情况下即时显示。
```python # Example using canvas tool canvas.present(url="about:blank", target=node_name)
html_content = """<!DOCTYPE html> <html> <head> <style> body { background: #667eea; color: white; padding: 40px; } .card { background: white; color: #333; padding: 30px; border-radius: 16px; } </style> </head> <body> <div class="card"> <h1>Your Content Here</h1> </div> </body> </html>"""
# Escape backticks and inject js_code = f"""document.open(); document.write(`{html_content}`); document.close();"""
canvas.eval(javaScript=js_code, target=node_name) ```
**关键限制:** 文件路径(`file:///path/to/file.html`)在 Canvas 中因安全原因被**阻止**。始终使用 localhost 或直接注入。
## 构建应用
### 应用 API 约定
每个应用都应暴露一个 `window.app` 或 `window.[appname]` 对象:
```javascript window.app = { // Update values setValue: (key, val) => { document.getElementById(key).textContent = val; }, // Bulk update loadData: (data) => { /* render all */ }, // Notifications notify: (msg) => { /* show toast */ } }; ```
### 双向通信
应用通过深度链接发回命令:
```javascript function sendToAgent(message) { window.location.href = `openclaw://agent?message=${encodeURIComponent(message)}`; }
// Button click → agent command document.getElementById('btn').onclick = () => { sendToAgent('Refresh my dashboard'); }; ```
## 模板
### 仪表盘
统计卡片、进度条、列表。自包含 HTML。 - 默认端口:9876 - API:`dashboard.setRevenue()`,`dashboard.setProgress()`,`dashboard.notify()`
### 追踪器
带复选框和连续记录的习惯/任务。自包含 HTML。 - 默认端口:9877 - API:`tracker.setItems()`,`tracker.addItem()`,`tracker.toggleItem()`
## 快速显示 (A2UI)
用于没有完整应用的临时显示:
```bash openclaw nodes canvas a2ui push --node "$NODE" --text " 📊 QUICK STATUS
Revenue: \$500 Users: 100
Done! " ```
## 端口分配
| 应用类型 | 默认端口 | |----------|--------------| | Dashboard | 9876 | | Tracker | 9877 | | Timer | 9878 | | Display | 9879 | | Custom | 9880+ |
## 设计系统
```css :root { --bg-primary: #0a0a0a; --bg-card: #1a1a2e; --accent-green: #00d4aa; --accent-blue: #4a9eff; --accent-orange: #f59e0b; --text-primary: #fff; --text-muted: #888; --border: #333; } ```
## 最佳实践
1. **自包含 HTML** —— 内联 CSS/JS 以便于移植 2. **深色主题** —— 匹配 OpenClaw 美学 3. **暴露应用 API** —— 让 agent 通过 `window.app.*` 更新 4. **使用 IDs** —— 在 agent 将更新的元素上使用 5. **实时时钟** —— 表明应用正在运行 6. **深度链接** —— 用于双向通信
## 故障排除
**应用在浏览器中打开而不是在 Canvas 中?** - 确保你使用的是 `openclaw nodes canvas navigate`,而不仅仅是 `open` - Canvas navigate 专门针对 Canvas 面板
**Canvas 上显示 "Not Found"?** - **文件路径不起作用:** Canvas 因安全(沙箱)阻止 `file:///` URLs - **Data URLs 可能失败:** 改用通过 `canvas eval` + `document.write()` 的直接 HTML 注入 - 对于 localhost:验证服务器是否正在运行:`curl http://localhost:[PORT]/` - 检查端口是否正确 - 使用 `http://localhost:` 而不是 `openclaw-canvas://`(URL 协议有问题)
**即使 URL 正确,Canvas 仍显示 "Not Found"?** - 这是一个安全边界:Canvas 无法访问本地文件系统 - **解决方案:** 使用“打开应用”部分中的方法 2(直接 HTML 注入) - 或者通过 localhost 服务(方法 1)
**应用未更新?** - 检查 window.app API 是否已定义:`openclaw nodes canvas eval --js "typeof window.app"` - 验证 JS eval 语法:双引号内使用单引号
**服务器端口已被占用?** - 终止现有进程:`lsof -ti:[PORT] | xargs kill -9`
## 辅助脚本
### canvas-inject.py
用于直接 HTML 注入(方法 2)的 Python 辅助工具。
```bash # Example usage in Python from canvas_inject import inject_html_to_canvas
html = open("my-dashboard.html").read() commands = inject_html_to_canvas(html, node_name="Your Node")
# Then use canvas tool with these commands canvas.present(**commands["step1_present"]) canvas.eval(**commands["step2_inject"]) ```
或者只是手动遵循该模式(参见“打开应用”中的方法 2)。
## 需求
- 支持 Canvas 的 OpenClaw(macOS 应用) - Python 3(用于 http.server) - 具有 canvas 功能的已配对节点