@limeade-labs/sparkui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,195 @@
1
+ # MCP Setup
2
+
3
+ Use SparkUI from AI clients like Claude Desktop, Cursor, and Windsurf via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/).
4
+
5
+ ## What is MCP?
6
+
7
+ MCP (Model Context Protocol) is an open standard that lets AI applications connect to external tools and data sources. Instead of writing custom integrations, any MCP-compatible client can use SparkUI tools through a standard protocol.
8
+
9
+ The SparkUI MCP server exposes tools like `sparkui_push` and `sparkui_compose` that AI clients can call to create ephemeral web pages.
10
+
11
+ ## Prerequisites
12
+
13
+ 1. SparkUI server running (see [Getting Started](./getting-started.md))
14
+ 2. Your push token from `.env`
15
+ 3. An MCP-compatible client (Claude Desktop, Cursor, Windsurf, Cline, etc.)
16
+
17
+ ## Install the MCP Server
18
+
19
+ ```bash
20
+ cd mcp-server
21
+ npm install
22
+ ```
23
+
24
+ The MCP server is a lightweight Node.js process that communicates with your SparkUI server over HTTP.
25
+
26
+ ## Claude Desktop Setup
27
+
28
+ Edit your Claude Desktop config file:
29
+
30
+ - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
31
+ - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
32
+
33
+ ```json
34
+ {
35
+ "mcpServers": {
36
+ "sparkui": {
37
+ "command": "node",
38
+ "args": ["/absolute/path/to/sparkui/mcp-server/index.js"],
39
+ "env": {
40
+ "SPARKUI_URL": "http://localhost:3457",
41
+ "SPARKUI_TOKEN": "your-push-token"
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ Restart Claude Desktop after saving. You should see "sparkui" in the MCP tools list (🔨 icon).
49
+
50
+ > **Tip:** Use an absolute path for the `args` value. Relative paths may not resolve correctly.
51
+
52
+ ## Cursor Setup
53
+
54
+ Add to `.cursor/mcp.json` in your project root (or global config):
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "sparkui": {
60
+ "command": "node",
61
+ "args": ["/absolute/path/to/sparkui/mcp-server/index.js"],
62
+ "env": {
63
+ "SPARKUI_URL": "http://localhost:3457",
64
+ "SPARKUI_TOKEN": "your-push-token"
65
+ }
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ## Windsurf Setup
72
+
73
+ Add to `.windsurf/mcp.json` in your project root:
74
+
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "sparkui": {
79
+ "command": "node",
80
+ "args": ["/absolute/path/to/sparkui/mcp-server/index.js"],
81
+ "env": {
82
+ "SPARKUI_URL": "http://localhost:3457",
83
+ "SPARKUI_TOKEN": "your-push-token"
84
+ }
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ ## Environment Variables
91
+
92
+ | Variable | Required | Default | Description |
93
+ |----------|----------|---------|-------------|
94
+ | `SPARKUI_URL` | No | `http://localhost:3457` | Base URL of the SparkUI server |
95
+ | `SPARKUI_TOKEN` | Yes | — | Push token for API authentication |
96
+
97
+ ## Available MCP Tools
98
+
99
+ ### `sparkui_list_templates`
100
+
101
+ List available page templates.
102
+
103
+ **Parameters:** None
104
+
105
+ **Returns:**
106
+
107
+ ```json
108
+ { "templates": ["macro-tracker", "ws-test", "feedback-form", "checkout", "workout-timer"] }
109
+ ```
110
+
111
+ ### `sparkui_list_components`
112
+
113
+ List available components for page composition.
114
+
115
+ **Parameters:** None
116
+
117
+ **Returns:**
118
+
119
+ ```json
120
+ { "components": ["header", "button", "timer", "checklist", "progress", "stats", "form", "tabs"] }
121
+ ```
122
+
123
+ ### `sparkui_push`
124
+
125
+ Create a page from a template.
126
+
127
+ | Parameter | Type | Required | Description |
128
+ |-----------|------|----------|-------------|
129
+ | `template` | string | Yes | Template name |
130
+ | `data` | object | Yes | Template data |
131
+ | `ttl` | number | No | Time-to-live in seconds |
132
+ | `og` | object | No | Open Graph overrides (`title`, `description`, `image`) |
133
+
134
+ ### `sparkui_compose`
135
+
136
+ Compose a page from individual components.
137
+
138
+ | Parameter | Type | Required | Description |
139
+ |-----------|------|----------|-------------|
140
+ | `title` | string | Yes | Page title |
141
+ | `sections` | array | Yes | Array of `{ type, config }` component sections |
142
+ | `ttl` | number | No | Time-to-live in seconds |
143
+
144
+ ### `sparkui_page_status`
145
+
146
+ Check if a page is still active.
147
+
148
+ | Parameter | Type | Required | Description |
149
+ |-----------|------|----------|-------------|
150
+ | `id` | string | Yes | Page UUID |
151
+
152
+ ## Example Usage
153
+
154
+ Once configured, you can ask your AI client naturally:
155
+
156
+ > "Create a feedback form asking about the new feature"
157
+
158
+ The AI client will call `sparkui_push` with the feedback-form template and return a URL you can open.
159
+
160
+ > "Make a dashboard showing my project stats: 42 tasks done, 8 in progress, 3 blocked"
161
+
162
+ The AI will use `sparkui_compose` with header, stats, and progress components.
163
+
164
+ > "Build me a workout timer: 3 rounds of push-ups, squats, and planks with 60-second rest"
165
+
166
+ The AI calls `sparkui_push` with the workout-timer template.
167
+
168
+ ## Architecture
169
+
170
+ ```
171
+ Claude Desktop / Cursor / Windsurf
172
+ ↓ (MCP stdio)
173
+ SparkUI MCP Server (Node.js)
174
+ ↓ (HTTP)
175
+ SparkUI Server (localhost:3457)
176
+
177
+ Ephemeral web pages
178
+ ```
179
+
180
+ The MCP server is a thin client — it translates MCP tool calls into SparkUI HTTP API requests. It doesn't import SparkUI internals or require being co-located with the SparkUI server.
181
+
182
+ ## Troubleshooting
183
+
184
+ **"Tool not found" in Claude Desktop:**
185
+ - Ensure you restarted Claude Desktop after editing the config
186
+ - Check that the path to `index.js` is absolute and correct
187
+ - Verify the MCP server starts: `node /path/to/mcp-server/index.js` (it should wait for stdin)
188
+
189
+ **"SparkUI API error: 401":**
190
+ - Your `SPARKUI_TOKEN` doesn't match the `PUSH_TOKEN` in your SparkUI `.env`
191
+ - Check for trailing whitespace in the token
192
+
193
+ **"Connection refused":**
194
+ - SparkUI server isn't running — start it with `sparkui start`
195
+ - Check that `SPARKUI_URL` matches your server's actual port
@@ -0,0 +1,177 @@
1
+ # OpenClaw Setup
2
+
3
+ Integrate SparkUI as an [OpenClaw](https://github.com/openclaw/openclaw) agent skill so your AI agent can automatically generate interactive web pages during conversations.
4
+
5
+ ## What is OpenClaw?
6
+
7
+ OpenClaw is an AI agent runtime that connects language models to tools, channels (Slack, Discord, Telegram), and external services. Skills are modular capabilities the agent can invoke — SparkUI is one such skill.
8
+
9
+ When SparkUI is installed as a skill, the agent can detect when a visual UI would be better than text (dashboards, forms, trackers) and automatically generate a page without being explicitly asked.
10
+
11
+ ## Install SparkUI as an OpenClaw Skill
12
+
13
+ ### 1. Clone SparkUI into your skills directory
14
+
15
+ ```bash
16
+ cd ~/your-openclaw-workspace/skills/
17
+ git clone https://github.com/Limeade-Labs/sparkui.git
18
+ ```
19
+
20
+ Or symlink if SparkUI is already installed elsewhere:
21
+
22
+ ```bash
23
+ ln -s /path/to/sparkui ~/your-openclaw-workspace/skills/sparkui
24
+ ```
25
+
26
+ ### 2. Verify the SKILL.md
27
+
28
+ SparkUI includes a `SKILL.md` file that tells the agent how to use it. The key sections are:
29
+
30
+ - **When to Use** — triggers (dashboards, trackers, forms, rich content)
31
+ - **Server Location** — directory, port, config file location
32
+ - **Step-by-step instructions** — check server, get token, push content
33
+ - **Available templates** — template names and data shapes
34
+ - **Composable components** — component types and configs
35
+
36
+ The agent reads this file automatically when it determines SparkUI is relevant to the task.
37
+
38
+ ### 3. Configure Environment
39
+
40
+ Ensure the SparkUI server is accessible from the OpenClaw host. The `.env` file should include:
41
+
42
+ ```bash
43
+ PUSH_TOKEN=spk_your_token_here
44
+ SPARKUI_PORT=3457
45
+ SPARKUI_BASE_URL=http://localhost:3457
46
+
47
+ # For round-trip event callbacks to OpenClaw
48
+ OPENCLAW_HOOKS_URL=http://127.0.0.1:18789/hooks/agent
49
+ OPENCLAW_HOOKS_TOKEN=your_openclaw_hooks_token
50
+ ```
51
+
52
+ ### 4. Start the SparkUI Server
53
+
54
+ ```bash
55
+ cd /path/to/sparkui
56
+ node server.js &
57
+ ```
58
+
59
+ Or use the CLI:
60
+
61
+ ```bash
62
+ sparkui start
63
+ ```
64
+
65
+ ## How the Agent Uses It
66
+
67
+ Once configured, the agent automatically detects opportunities to use SparkUI:
68
+
69
+ 1. **Agent reads SKILL.md** — on startup or when a relevant task is detected
70
+ 2. **Agent checks server health** — `curl http://localhost:3457/`
71
+ 3. **Agent loads push token** — `source /path/to/sparkui/.env`
72
+ 4. **Agent pushes a page** — via `curl` to the push or compose API
73
+ 5. **Agent shares the URL** — sends the `fullUrl` to the user in chat
74
+
75
+ The agent decides when to use SparkUI based on the "When to Use" section in SKILL.md:
76
+
77
+ - ✅ Dashboards, nutrition trackers, fitness stats
78
+ - ✅ Data displays, tables, comparisons
79
+ - ✅ Interactive forms, feedback collection
80
+ - ✅ Anything with progress bars, colors, layouts
81
+ - ❌ Simple text answers, yes/no questions, quick lists
82
+
83
+ ## Example: Macro Tracking Flow
84
+
85
+ Here's how the agent handles a nutrition tracking request end-to-end:
86
+
87
+ **User says:** "Log my lunch — chicken salad, 480 cal, 35g protein, 20g fat, 15g carbs"
88
+
89
+ **Agent does:**
90
+
91
+ 1. Updates the nutrition spreadsheet with the new meal
92
+ 2. Reads today's totals from the sheet
93
+ 3. Pushes a macro-tracker page:
94
+
95
+ ```bash
96
+ curl -s -X POST http://localhost:3457/api/push \
97
+ -H "Authorization: Bearer $PUSH_TOKEN" \
98
+ -H "Content-Type: application/json" \
99
+ -d '{
100
+ "template": "macro-tracker",
101
+ "data": {
102
+ "date": "2026-03-14",
103
+ "calories": {"current": 1250, "target": 1900},
104
+ "protein": {"current": 62, "target": 86},
105
+ "fat": {"current": 45, "target": 95},
106
+ "carbs": {"current": 15, "target": 25},
107
+ "meals": [
108
+ {"name": "Eggs & bacon", "calories": 450, "time": "6:30 AM"},
109
+ {"name": "Chicken salad", "calories": 480, "time": "12:00 PM"}
110
+ ]
111
+ },
112
+ "ttl": 7200
113
+ }'
114
+ ```
115
+
116
+ 4. Shares the link: "Logged! Here's your updated dashboard: http://..."
117
+
118
+ ## Round-Trip Events (OpenClaw Callbacks)
119
+
120
+ SparkUI can forward user interactions back to the agent via OpenClaw's webhook system. This closes the loop: **agent pushes page → user interacts → agent gets notified**.
121
+
122
+ ### Enable OpenClaw Forwarding
123
+
124
+ Add `openclaw` config when pushing a page:
125
+
126
+ ```json
127
+ {
128
+ "template": "feedback-form",
129
+ "data": { "title": "Quick Feedback" },
130
+ "openclaw": {
131
+ "enabled": true,
132
+ "channel": "slack",
133
+ "to": "C0AKMF5E0KD",
134
+ "eventTypes": ["completion"]
135
+ }
136
+ }
137
+ ```
138
+
139
+ ### Config Fields
140
+
141
+ | Field | Type | Description |
142
+ |-------|------|-------------|
143
+ | `enabled` | boolean | Enable event forwarding |
144
+ | `channel` | string | Delivery channel (default: `"slack"`) |
145
+ | `to` | string | Target channel/user ID |
146
+ | `eventTypes` | string[] | Events to forward: `["completion"]`, `["event"]`, or both |
147
+ | `sessionKey` | string | Optional session key for routing |
148
+
149
+ ### How It Works
150
+
151
+ 1. Agent pushes a page with `openclaw` config
152
+ 2. User opens the page and interacts (fills form, clicks buttons)
153
+ 3. Browser sends events via WebSocket to SparkUI server
154
+ 4. SparkUI forwards matching events to OpenClaw's `/hooks/agent` endpoint
155
+ 5. OpenClaw delivers the message to the specified channel
156
+ 6. Agent receives the notification and can respond
157
+
158
+ ### Use Cases
159
+
160
+ - **Feedback forms** — get notified when user submits a rating
161
+ - **Approval workflows** — user clicks approve/reject buttons
162
+ - **Data collection** — form submissions with structured data
163
+ - **Checklist completion** — notified when all items are checked
164
+
165
+ ## SKILL.md Reference
166
+
167
+ The full `SKILL.md` is located at the root of the SparkUI directory. It contains:
168
+
169
+ - Server location and configuration details
170
+ - Step-by-step instructions for the agent
171
+ - Template data schemas
172
+ - Component reference
173
+ - OpenClaw round-trip configuration
174
+
175
+ The agent reads this file automatically — you don't need to configure it separately.
176
+
177
+ > **Tip:** If you modify the SKILL.md (e.g., to add custom templates or change defaults), the agent will pick up the changes on its next invocation.
@@ -0,0 +1,289 @@
1
+ # Templates
2
+
3
+ SparkUI includes 5 built-in templates for common use cases. Each generates a complete, interactive HTML page with dark theme, responsive layout, and WebSocket connectivity.
4
+
5
+ Use templates via `POST /api/push` with a `template` name and `data` object.
6
+
7
+ ---
8
+
9
+ ## macro-tracker
10
+
11
+ Daily nutrition and macro tracking dashboard with animated progress bars, macro cards, and a meal log.
12
+
13
+ ### Data Schema
14
+
15
+ ```typescript
16
+ interface MacroTrackerData {
17
+ date: string; // e.g. "2026-03-14"
18
+ calories: { current: number; target: number };
19
+ protein: { current: number; target: number };
20
+ fat: { current: number; target: number };
21
+ carbs: { current: number; target: number };
22
+ meals?: Array<{
23
+ name: string; // e.g. "Grilled chicken salad"
24
+ calories: number;
25
+ time: string; // e.g. "12:00 PM"
26
+ }>;
27
+ }
28
+ ```
29
+
30
+ ### Example
31
+
32
+ ```json
33
+ {
34
+ "template": "macro-tracker",
35
+ "data": {
36
+ "date": "2026-03-14",
37
+ "calories": { "current": 1250, "target": 1900 },
38
+ "protein": { "current": 62, "target": 86 },
39
+ "fat": { "current": 45, "target": 95 },
40
+ "carbs": { "current": 15, "target": 25 },
41
+ "meals": [
42
+ { "name": "Eggs & bacon", "calories": 450, "time": "6:30 AM" },
43
+ { "name": "Grilled chicken salad", "calories": 480, "time": "12:00 PM" },
44
+ { "name": "Greek yogurt with almonds", "calories": 320, "time": "3:00 PM" }
45
+ ]
46
+ },
47
+ "ttl": 7200
48
+ }
49
+ ```
50
+
51
+ ### Features
52
+
53
+ - Animated progress bars with percentage labels
54
+ - Color-coded macro cards (Calories, Protein, Fat, Carbs)
55
+ - Meal log with times and calorie counts
56
+ - Auto-refreshes every 30 seconds
57
+ - Over-target warnings
58
+
59
+ > **Screenshot:** [screenshots/macro-tracker.png](../screenshots/macro-tracker.png)
60
+
61
+ ---
62
+
63
+ ## checkout
64
+
65
+ Stripe-inspired checkout page with product display, quantity selector, promo code field, and payment form. **Demo only — no real payment processing.**
66
+
67
+ ### Data Schema
68
+
69
+ ```typescript
70
+ interface CheckoutData {
71
+ product: {
72
+ name: string; // Product name
73
+ description: string; // Short description
74
+ price: number; // Unit price
75
+ image?: string; // Emoji (e.g. "⚡") or URL
76
+ imageUrl?: string; // Product image URL (overrides image)
77
+ };
78
+ shipping?: number; // Shipping cost (default: 0)
79
+ tax?: number; // Tax amount (default: 0)
80
+ currency?: string; // Currency code (default: "USD")
81
+ }
82
+ ```
83
+
84
+ ### Example
85
+
86
+ ```json
87
+ {
88
+ "template": "checkout",
89
+ "data": {
90
+ "product": {
91
+ "name": "SparkUI Pro",
92
+ "description": "Unlimited ephemeral UIs for your agent",
93
+ "price": 29.99,
94
+ "image": "⚡"
95
+ },
96
+ "shipping": 0,
97
+ "tax": 2.40,
98
+ "currency": "USD"
99
+ }
100
+ }
101
+ ```
102
+
103
+ ### Features
104
+
105
+ - "DEMO MODE" banner (no real charges)
106
+ - Quantity selector with live price updates
107
+ - Promo code input
108
+ - Simulated payment form (card number, expiry, CVC)
109
+ - Order summary with subtotal, shipping, tax, and total
110
+ - Sends `completion` event with order data on "Pay" click
111
+
112
+ > **Screenshot:** [screenshots/checkout.png](../screenshots/checkout.png)
113
+
114
+ ---
115
+
116
+ ## workout-timer
117
+
118
+ Fitness-app-quality workout page with exercise rounds, rest timer, warmup/cooldown checklists, and progress tracking.
119
+
120
+ ### Data Schema
121
+
122
+ ```typescript
123
+ interface WorkoutTimerData {
124
+ title: string; // Workout name
125
+ subtitle?: string; // e.g. "Day 3 — Push"
126
+ warmup?: Array<{ text: string }>;
127
+ exercises: Array<{
128
+ name: string; // Exercise name
129
+ reps: string; // e.g. "12 reps" or "30 sec"
130
+ notes?: string; // Form tips, etc.
131
+ }>;
132
+ rounds?: number; // Number of rounds (default: 3)
133
+ restSeconds?: number; // Rest between rounds (default: 60)
134
+ cooldown?: Array<{ text: string }>;
135
+ estimatedMinutes?: number;
136
+ estimatedCalories?: number;
137
+ }
138
+ ```
139
+
140
+ ### Example
141
+
142
+ ```json
143
+ {
144
+ "template": "workout-timer",
145
+ "data": {
146
+ "title": "Upper Body Blast",
147
+ "subtitle": "Day 1 — Push",
148
+ "warmup": [
149
+ { "text": "Arm circles — 30 sec" },
150
+ { "text": "Band pull-aparts — 15 reps" }
151
+ ],
152
+ "exercises": [
153
+ { "name": "Push-ups", "reps": "15 reps", "notes": "Full range of motion" },
154
+ { "name": "Dumbbell press", "reps": "12 reps", "notes": "Slow negatives" },
155
+ { "name": "Lateral raises", "reps": "12 reps" }
156
+ ],
157
+ "rounds": 3,
158
+ "restSeconds": 60,
159
+ "cooldown": [
160
+ { "text": "Chest stretch — 30 sec each side" },
161
+ { "text": "Shoulder stretch — 30 sec each side" }
162
+ ],
163
+ "estimatedMinutes": 35,
164
+ "estimatedCalories": 280
165
+ }
166
+ }
167
+ ```
168
+
169
+ ### Features
170
+
171
+ - Stats bar: rounds, exercises, estimated time and calories
172
+ - Interactive warmup/cooldown checklists
173
+ - Round tracker with exercise completion
174
+ - Built-in rest timer with start/skip controls
175
+ - Progress tracking across all rounds
176
+ - Sends `completion` event when workout finishes
177
+
178
+ > **Screenshot:** [screenshots/workout-timer.png](../screenshots/workout-timer.png)
179
+
180
+ ---
181
+
182
+ ## feedback-form
183
+
184
+ Simple feedback form with star rating, text input, and optional extra questions. Sends completion event with all form data.
185
+
186
+ ### Data Schema
187
+
188
+ ```typescript
189
+ interface FeedbackFormData {
190
+ title?: string; // Form title (default: "Feedback")
191
+ subtitle?: string; // Subtitle text
192
+ questions?: string[]; // Optional extra text input fields
193
+ }
194
+ ```
195
+
196
+ ### Example
197
+
198
+ ```json
199
+ {
200
+ "template": "feedback-form",
201
+ "data": {
202
+ "title": "How was your experience?",
203
+ "subtitle": "We'd love to hear from you",
204
+ "questions": [
205
+ "What did you like most?",
206
+ "What could be improved?"
207
+ ]
208
+ }
209
+ }
210
+ ```
211
+
212
+ ### Features
213
+
214
+ - 5-star rating selector
215
+ - Free-text feedback textarea
216
+ - Optional extra question fields
217
+ - Success animation on submit
218
+ - Sends `completion` event with `{ rating, feedback, ...extraFields }`
219
+
220
+ > **Screenshot:** [screenshots/feedback-form.png](../screenshots/feedback-form.png)
221
+
222
+ ---
223
+
224
+ ## ws-test
225
+
226
+ WebSocket connectivity test page for debugging and development. Tests all WS bridge features.
227
+
228
+ ### Data Schema
229
+
230
+ ```typescript
231
+ interface WsTestData {
232
+ // No required data — this template works with defaults
233
+ }
234
+ ```
235
+
236
+ ### Example
237
+
238
+ ```json
239
+ {
240
+ "template": "ws-test",
241
+ "data": {}
242
+ }
243
+ ```
244
+
245
+ ### Features
246
+
247
+ - Live connection status indicator
248
+ - Send click events and custom events
249
+ - Test form that sends completion events
250
+ - Real-time message log showing all WebSocket traffic
251
+ - Useful for verifying WebSocket connectivity and event forwarding
252
+
253
+ ---
254
+
255
+ ## Using Templates
256
+
257
+ ### Push a template page
258
+
259
+ ```bash
260
+ curl -X POST http://localhost:3457/api/push \
261
+ -H "Authorization: Bearer $PUSH_TOKEN" \
262
+ -H "Content-Type: application/json" \
263
+ -d '{
264
+ "template": "TEMPLATE_NAME",
265
+ "data": { ... },
266
+ "ttl": 3600
267
+ }'
268
+ ```
269
+
270
+ ### Update a template page
271
+
272
+ ```bash
273
+ curl -X PATCH http://localhost:3457/api/pages/PAGE_ID \
274
+ -H "Authorization: Bearer $PUSH_TOKEN" \
275
+ -H "Content-Type: application/json" \
276
+ -d '{
277
+ "data": { ... }
278
+ }'
279
+ ```
280
+
281
+ When updating, you can just send `data` — SparkUI re-renders using the page's original template.
282
+
283
+ ### List available templates
284
+
285
+ ```bash
286
+ curl http://localhost:3457/ | jq .templates
287
+ ```
288
+
289
+ > **Tip:** For custom layouts that don't fit a template, use the [compose API](./components.md) to build pages from individual components.