liteagents 2.6.0 → 2.8.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.
- package/CHANGELOG.md +53 -0
- package/LICENSE +202 -21
- package/README.md +6 -4
- package/installer/cli.js +4 -1
- package/package.json +2 -2
- package/packages/ampcode/commands/live-canvas/README.md +38 -47
- package/packages/{claude/skills/live-canvas/templates/demo → ampcode/commands/live-canvas/dev}/post-variants.html +8 -3
- package/packages/ampcode/commands/live-canvas/templates/lab-banner.html +6 -0
- package/packages/ampcode/commands/live-canvas/templates/overlay-vanilla.js +64 -6
- package/packages/ampcode/commands/live-canvas.md +140 -161
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/.claude-plugin/plugin.json +1 -1
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/README.md +2 -2
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/package-lock.json +13 -13
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/package.json +1 -1
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/schema.json +1 -1
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/server.js +320 -27
- package/packages/claude/plugins/live-canvas-marketplace/setup.sh +83 -24
- package/packages/claude/skills/live-canvas/README.md +53 -57
- package/packages/claude/skills/live-canvas/SKILL.md +122 -158
- package/packages/{ampcode/commands/live-canvas/templates/demo → claude/skills/live-canvas/dev}/post-variants.html +8 -3
- package/packages/claude/skills/live-canvas/templates/lab-banner.html +6 -0
- package/packages/claude/skills/live-canvas/templates/overlay-vanilla.js +64 -6
- package/packages/droid/commands/live-canvas/README.md +38 -47
- package/packages/droid/commands/live-canvas/{templates/demo → dev}/post-variants.html +8 -3
- package/packages/droid/commands/live-canvas/templates/lab-banner.html +6 -0
- package/packages/droid/commands/live-canvas/templates/overlay-vanilla.js +64 -6
- package/packages/droid/commands/live-canvas.md +140 -161
- package/packages/opencode/command/live-canvas/README.md +38 -47
- package/packages/opencode/command/live-canvas/{templates/demo → dev}/post-variants.html +8 -3
- package/packages/opencode/command/live-canvas/templates/lab-banner.html +6 -0
- package/packages/opencode/command/live-canvas/templates/overlay-vanilla.js +64 -6
- package/packages/opencode/command/live-canvas.md +140 -161
- package/packages/ampcode/commands/live-canvas/templates/.claude/settings.local.json +0 -8
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +0 -1299
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/format-utils.ts +0 -283
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/index.ts +0 -62
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/selector-utils.ts +0 -423
- package/packages/ampcode/commands/live-canvas/templates/feedback-react/types.ts +0 -118
- package/packages/claude/skills/live-canvas/INTEGRATION_NOTES.md +0 -210
- package/packages/claude/skills/live-canvas/templates/.claude/settings.local.json +0 -8
- package/packages/claude/skills/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +0 -1299
- package/packages/claude/skills/live-canvas/templates/feedback-react/format-utils.ts +0 -283
- package/packages/claude/skills/live-canvas/templates/feedback-react/index.ts +0 -62
- package/packages/claude/skills/live-canvas/templates/feedback-react/selector-utils.ts +0 -423
- package/packages/claude/skills/live-canvas/templates/feedback-react/types.ts +0 -118
- package/packages/droid/commands/live-canvas/templates/.claude/settings.local.json +0 -8
- package/packages/droid/commands/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +0 -1299
- package/packages/droid/commands/live-canvas/templates/feedback-react/format-utils.ts +0 -283
- package/packages/droid/commands/live-canvas/templates/feedback-react/index.ts +0 -62
- package/packages/droid/commands/live-canvas/templates/feedback-react/selector-utils.ts +0 -423
- package/packages/droid/commands/live-canvas/templates/feedback-react/types.ts +0 -118
- package/packages/opencode/command/live-canvas/templates/.claude/settings.local.json +0 -8
- package/packages/opencode/command/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +0 -1299
- package/packages/opencode/command/live-canvas/templates/feedback-react/format-utils.ts +0 -283
- package/packages/opencode/command/live-canvas/templates/feedback-react/index.ts +0 -62
- package/packages/opencode/command/live-canvas/templates/feedback-react/selector-utils.ts +0 -423
- package/packages/opencode/command/live-canvas/templates/feedback-react/types.ts +0 -118
|
@@ -17,114 +17,117 @@ This skill implements a complete design exploration workflow: interview, generat
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
## Feedback Modes
|
|
20
|
+
## Feedback Modes — always ask the user
|
|
21
21
|
|
|
22
|
-
Live Canvas supports two feedback transports. The
|
|
22
|
+
Live Canvas supports two feedback transports. **The user picks every time** — never auto-select.
|
|
23
23
|
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
24
|
+
- **Live channel (Claude Code only):** the overlay POSTs each Save to a local MCP channel server; feedback arrives in the active session as a `<channel source="live-canvas" ...>` tag. Requires the session was launched with `live-claude` (or `claude --dangerously-load-development-channels plugin:live-canvas-channel@live-canvas-marketplace`) — channels are still an experimental Claude Code feature and a plain `claude` session silently drops the notifications. Any qualifying session can claim the channel by calling `mcp__live-canvas__channel_open`; only one holds it at a time.
|
|
25
|
+
- **JSON file (universal):** each Save accumulates locally; Submit writes `.claude-design/feedback.jsonl` (or downloads the JSON). User says "check" or pastes the file when ready. Works in any host.
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
### Host detection — do this first
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|---|---|---|
|
|
31
|
-
| Claude Code | A + B | Probe channel at Phase 0. If up → Live. If down → announce Batch and print the one-time setup block below. |
|
|
32
|
-
| Droid, Amp, Opencode | A only | Never probe the channel, never mention Live mode, never offer to install a plugin. Use Batch exclusively and collect feedback via paste-in-terminal (Phase 5). |
|
|
29
|
+
This SKILL.md is the Claude Code variant of the skill. Same content is mirrored as docs for Droid/Amp/Opencode under `packages/<tool>/commands/live-canvas/`, but those tools don't support the MCP channel.
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
**If running under Droid, Amp, or Opencode (not Claude Code):**
|
|
32
|
+
- Skip the mode question entirely.
|
|
33
|
+
- Announce: `📝 JSON mode (Live channel requires Claude Code)`.
|
|
34
|
+
- Proceed to Phase 1 with `channelUrl` omitted in the overlay init.
|
|
35
|
+
- Never mention the channel plugin.
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
How to tell which host you're in: the environment variable `CLAUDECODE=1` is set by Claude Code. If unset, assume non-Claude and go straight to JSON.
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
### Mode selection (Claude Code only)
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
curl -s --max-time 1 http://localhost:8788/health
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
**Step B — Decide which case you're in:**
|
|
45
|
-
|
|
46
|
-
| Probe result | Plugin dir exists at `~/.claude/plugins/cache/live-canvas-marketplace/`? | Case |
|
|
47
|
-
|---|---|---|
|
|
48
|
-
| `{"ok":true,...}` | (don't bother checking) | **Case 1 — Live ready** |
|
|
49
|
-
| fails | exists | **Case 2 — Plugin installed, session not in dev mode** |
|
|
50
|
-
| fails | missing | **Case 3 — First-time user** |
|
|
41
|
+
Always ask, never auto-detect. Use `AskUserQuestion`:
|
|
51
42
|
|
|
52
|
-
**
|
|
43
|
+
> **Question: Pick a feedback mode**
|
|
44
|
+
> - **Live channel** — overlay streams each Save straight into this Claude session. **Requires this session to have been started with `live-claude`** (sets the `--dangerously-load-development-channels` flag). If you started with plain `claude`, pick JSON instead — Live mode will refuse to start and tell you to open a new `live-claude` terminal.
|
|
45
|
+
> - **JSON file** — overlay writes feedback to a local JSON file; tell me "check" when ready. Works in any session, plain `claude` included.
|
|
53
46
|
|
|
54
|
-
|
|
47
|
+
**If the user picks JSON**, try to bind the batch endpoint so submissions write to disk instead of triggering a browser download. Call `mcp__live-canvas__batch_open`:
|
|
55
48
|
|
|
56
|
-
|
|
49
|
+
| Tool result | What to do |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Tool not available (no MCP) | Announce `📝 JSON mode — overlay will offer JSON download on Submit`. Proceed to Phase 1 with both `channelUrl` and `batchEndpoint` omitted. |
|
|
52
|
+
| `{status: "opened", ...}` or `{status: "already_listening", ...}` | Announce `📝 JSON mode — submissions write to .claude-design/feedback.jsonl`. Proceed to Phase 1 with `batchEndpoint: 'http://localhost:8788/feedback-jsonl'` and `channelUrl` omitted. |
|
|
53
|
+
| `{status: "in_use", ...}` | Announce `📝 JSON mode — overlay will offer JSON download on Submit (another session holds the port)`. Proceed to Phase 1 with both `channelUrl` and `batchEndpoint` omitted. |
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
✨ Live mode — your feedback will stream into this session in real time.
|
|
60
|
-
```
|
|
55
|
+
Call `mcp__live-canvas__channel_close` on cleanup/abort to release the port (same teardown as Live mode).
|
|
61
56
|
|
|
62
|
-
|
|
57
|
+
**If the user picks Live**, claim the channel by calling the MCP tool `mcp__live-canvas__channel_open`. Branch on the result:
|
|
63
58
|
|
|
64
|
-
|
|
59
|
+
| Tool result | What to do |
|
|
60
|
+
|---|---|
|
|
61
|
+
| Tool not available (no such tool / MCP error) | **Case C: First-time setup needed.** Print the install block (below) and STOP. |
|
|
62
|
+
| `{status: "opened", ...}` (no `took_over`) | **Case A: Ready.** Announce `✨ Live mode — feedback streams into this session`. Proceed to Phase 1 with `channelUrl: 'http://localhost:8788'`. |
|
|
63
|
+
| `{status: "opened", took_over: <pid>, ...}` | **Case A (takeover): Ready.** Announce `✨ Live mode — feedback streams into this session (took over channel from prior live-canvas session pid <pid>)`. Proceed to Phase 1 the same as plain Case A. The prior session's MCP was a sibling instance of this plugin (same user); its `/live-canvas` workflow there is now over, but the lab files on disk are untouched. |
|
|
64
|
+
| `{status: "already_listening", ...}` | **Case A: Ready.** Announce `✨ Live mode — feedback streams into this session`. Proceed to Phase 1 with `channelUrl: 'http://localhost:8788'`. |
|
|
65
|
+
| `{status: "in_use", holder_pid, message, ...}` | **Case B: Foreign process holds the port.** A non-live-canvas process is using port 8788 (e.g., a dev server on the wrong port). Print the busy block (below) and STOP — the plugin won't kill processes it doesn't own. |
|
|
66
|
+
| `{status: "no_channel_capability", message, ...}` | **Case D: Session lacks the channels flag.** Print the relaunch block (below) and STOP. Do NOT proceed to Live mode — notifications would be silently dropped. |
|
|
65
67
|
|
|
66
|
-
|
|
68
|
+
You must call `mcp__live-canvas__channel_close` later — see Phase 8 (Cleanup) and Abort Handling. The MCP plugin also auto-releases the port on session disconnect as a safety net, but explicit close is cleaner.
|
|
67
69
|
|
|
68
|
-
|
|
69
|
-
> - "Batch for now" — continue without live mode. Feedback writes to JSONL; paste or say 'check' when ready.
|
|
70
|
-
> - "Restart for Live mode" — I'll abort here. Close this session, run the command below in your terminal, then `/live-canvas` again in the new one.
|
|
70
|
+
**Case B — busy block (foreign holder):**
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
Substitute the actual `holder_pid` from the tool response into the message below.
|
|
73
73
|
|
|
74
74
|
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
claude --dangerously-load-development-channels plugin:live-canvas-channel@live-canvas-marketplace
|
|
75
|
+
Port 8788 is held by pid <holder_pid>, which is NOT a live-canvas server
|
|
76
|
+
(it's some other process). I won't kill processes I don't own.
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
To use Live mode:
|
|
79
|
+
• Find what it is: ps -fp <holder_pid>
|
|
80
|
+
• Stop it if it's safe to stop (e.g. a stray dev server on the wrong port).
|
|
81
|
+
• Then re-run /live-canvas in this session and pick Live.
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
alias claude-live='claude --dangerously-load-development-channels plugin:live-canvas-channel@live-canvas-marketplace'
|
|
83
|
+
Or pick JSON now — JSON mode does not require port 8788.
|
|
83
84
|
```
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
If they pick "Batch for now", announce Batch mode and proceed to Phase 1 normally.
|
|
88
|
-
|
|
89
|
-
### Case 3 — First-time user
|
|
90
|
-
|
|
91
|
-
Channel plugin has never been set up. Use `AskUserQuestion`:
|
|
92
|
-
|
|
93
|
-
> **Question: Set up Live mode?**
|
|
94
|
-
> - "Yes, walk me through it" — I'll print the one-time setup commands.
|
|
95
|
-
> - "Just use Batch mode" — skip setup, start the skill normally.
|
|
96
|
-
|
|
97
|
-
If they pick setup, print the full sequence:
|
|
86
|
+
**Case D — relaunch block (no channels flag):**
|
|
98
87
|
|
|
99
88
|
```
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
89
|
+
This Claude session is plain `claude` — it can't receive Live-mode feedback.
|
|
90
|
+
Live mode needs a session started with `live-claude` (which sets the
|
|
91
|
+
experimental --dangerously-load-development-channels flag). Without it,
|
|
92
|
+
your browser Saves would POST 200 but never appear in chat.
|
|
93
|
+
|
|
94
|
+
To use Live mode:
|
|
95
|
+
|
|
96
|
+
1. Open a NEW terminal (you can keep this one running; it's fine to have
|
|
97
|
+
both). Do NOT --continue this session — start fresh in the project.
|
|
98
|
+
2. cd to your project directory.
|
|
99
|
+
3. Run: live-claude
|
|
100
|
+
(if the command isn't found: run `source ~/.zshrc` first, or re-run
|
|
101
|
+
packages/claude/plugins/live-canvas-marketplace/setup.sh)
|
|
102
|
+
(literal form: claude --dangerously-load-development-channels plugin:live-canvas-channel@live-canvas-marketplace)
|
|
103
|
+
4. In that NEW session, run /live-canvas and pick Live.
|
|
104
|
+
|
|
105
|
+
The lab files are written to disk in the project's `.claude-design/lab/`,
|
|
106
|
+
so any session in the right cwd can pick up where another left off.
|
|
107
|
+
|
|
108
|
+
Or pick JSON now to stay in this session — feedback gets written to a file
|
|
109
|
+
you paste back here. No relaunch needed.
|
|
110
|
+
```
|
|
113
111
|
|
|
114
|
-
|
|
112
|
+
**Case C — first-time setup block:**
|
|
115
113
|
|
|
116
|
-
Tip: alias for future sessions:
|
|
117
|
-
alias claude-live='claude --dangerously-load-development-channels plugin:live-canvas-channel@live-canvas-marketplace'
|
|
118
114
|
```
|
|
115
|
+
Live mode needs a one-time install. Two steps:
|
|
119
116
|
|
|
120
|
-
|
|
117
|
+
1. From this repo's root (or wherever liteagents lives):
|
|
118
|
+
bash packages/claude/plugins/live-canvas-marketplace/setup.sh
|
|
119
|
+
This copies the marketplace into ~/.claude/plugins/ and runs npm install.
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
2. In any Claude session, register and install the plugin:
|
|
122
|
+
/plugin marketplace add ~/.claude/plugins/live-canvas-marketplace
|
|
123
|
+
/plugin install live-canvas-channel@live-canvas-marketplace
|
|
123
124
|
|
|
124
|
-
|
|
125
|
+
That's it — once the plugin is installed, /live-canvas in any session can
|
|
126
|
+
claim the channel. Re-run /live-canvas and pick Live.
|
|
127
|
+
```
|
|
125
128
|
|
|
126
|
-
|
|
127
|
-
1.
|
|
129
|
+
Do not try to run any of these commands yourself. Three reasons:
|
|
130
|
+
1. The `/plugin` steps are Claude Code slash commands — not doable from inside a running session.
|
|
128
131
|
2. Accepting the research-preview safety prompt must be the user's explicit act.
|
|
129
132
|
3. If something goes wrong mid-install, the user needs to see each step's output to diagnose.
|
|
130
133
|
|
|
@@ -403,12 +406,6 @@ Create all files under `.claude-design/`:
|
|
|
403
406
|
│ │ └── VariantE.tsx
|
|
404
407
|
│ ├── components/
|
|
405
408
|
│ │ └── LabShell.tsx # Lab layout wrapper
|
|
406
|
-
│ ├── feedback/ # Interactive feedback system
|
|
407
|
-
│ │ ├── types.ts # TypeScript interfaces
|
|
408
|
-
│ │ ├── selector-utils.ts # Element identification
|
|
409
|
-
│ │ ├── format-utils.ts # Feedback formatting
|
|
410
|
-
│ │ ├── FeedbackOverlay.tsx # Main overlay component
|
|
411
|
-
│ │ └── index.ts # Module exports
|
|
412
409
|
│ └── data/
|
|
413
410
|
│ └── fixtures.ts # Shared mock data
|
|
414
411
|
├── design-brief.json
|
|
@@ -419,61 +416,54 @@ Create all files under `.claude-design/`:
|
|
|
419
416
|
|
|
420
417
|
**The overlay is the PRIMARY feature of Live Canvas.** Without it, users cannot provide interactive feedback. NEVER generate a lab without the overlay.
|
|
421
418
|
|
|
422
|
-
###
|
|
423
|
-
|
|
424
|
-
The skill ships two overlay templates under `~/.claude/skills/live-canvas/templates/`:
|
|
419
|
+
### The overlay
|
|
425
420
|
|
|
426
|
-
|
|
427
|
-
|---|---|
|
|
428
|
-
| `feedback-react/FeedbackOverlay.tsx` | React / Next.js / Vite-React projects — integrates via JSX |
|
|
429
|
-
| `overlay-vanilla.js` | Everything else: vanilla JS, Vue, Svelte, Rails, Django, Phoenix, plain HTML, Go templates, etc. One script tag, zero dependencies. |
|
|
430
|
-
|
|
431
|
-
Detect the host framework in Phase 0 and copy the matching template into the route directory. The vanilla template is the safer default when in doubt — it works in every context the React one does, plus more.
|
|
432
|
-
|
|
433
|
-
### Required files in the route directory
|
|
434
|
-
|
|
435
|
-
For **React-based** projects:
|
|
436
|
-
```
|
|
437
|
-
app/live-canvas/ # or app/__live_canvas/
|
|
438
|
-
├── page.tsx # Main lab page with variants + overlay import
|
|
439
|
-
└── FeedbackOverlay.tsx # Copy of feedback-react/FeedbackOverlay.tsx
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
Import: `import { FeedbackOverlay } from './FeedbackOverlay'`
|
|
443
|
-
|
|
444
|
-
For **non-React** projects:
|
|
445
|
-
```
|
|
446
|
-
<static-dir>/__live_canvas/
|
|
447
|
-
├── index.html # Or framework-appropriate entry point
|
|
448
|
-
└── overlay-vanilla.js # Copy of templates/overlay-vanilla.js
|
|
449
|
-
```
|
|
421
|
+
**One template, every framework:** `~/.claude/skills/live-canvas/templates/overlay-vanilla.js`. Single file, zero dependencies, plain DOM. Works in vanilla JS, Vue, Svelte, Rails, Django, Phoenix, plain HTML, Next.js, Vite-React, Remix — anywhere a `<script>` tag runs.
|
|
450
422
|
|
|
451
|
-
|
|
423
|
+
Copy it into a directory served by the dev server (e.g. `public/overlay-vanilla.js` for Next.js, `static/overlay-vanilla.js` for Vite, the public dir for Rails/Django). Reference it from the lab page.
|
|
452
424
|
|
|
453
425
|
### Wiring the overlay
|
|
454
426
|
|
|
455
|
-
|
|
427
|
+
The overlay needs one `init()` call with `target`, `channelUrl` (Live only), and optionally `batchEndpoint`.
|
|
456
428
|
|
|
457
|
-
**
|
|
429
|
+
**Server-rendered / vanilla HTML:**
|
|
458
430
|
|
|
459
431
|
```html
|
|
460
|
-
<script src="
|
|
432
|
+
<script src="/overlay-vanilla.js"></script>
|
|
461
433
|
<script>
|
|
462
434
|
LiveCanvas.init({
|
|
463
435
|
target: '<ComponentOrPageName>',
|
|
464
|
-
// Only include channelUrl when
|
|
465
|
-
//
|
|
436
|
+
// Only include channelUrl when the user picked Live and the probe succeeded.
|
|
437
|
+
// In JSON mode, OMIT channelUrl so the overlay skips the probe.
|
|
466
438
|
channelUrl: 'http://localhost:8788',
|
|
467
|
-
// Optional: where to POST
|
|
468
|
-
// When omitted,
|
|
439
|
+
// Optional: where to POST JSON payloads when channelUrl is missing.
|
|
440
|
+
// When omitted, Submit downloads a JSON file instead.
|
|
469
441
|
batchEndpoint: '/__live_canvas/feedback',
|
|
470
442
|
});
|
|
471
443
|
</script>
|
|
472
444
|
```
|
|
473
445
|
|
|
474
|
-
**React
|
|
446
|
+
**React / Next.js / Vite-React:** load the script with the framework's mechanism and init in a `useEffect`:
|
|
475
447
|
|
|
476
|
-
|
|
448
|
+
```tsx
|
|
449
|
+
import Script from 'next/script';
|
|
450
|
+
import { useEffect } from 'react';
|
|
451
|
+
|
|
452
|
+
export default function Lab() {
|
|
453
|
+
useEffect(() => {
|
|
454
|
+
(window as any).LiveCanvas?.init({
|
|
455
|
+
target: 'PostCard',
|
|
456
|
+
channelUrl: 'http://localhost:8788', // omit in JSON mode
|
|
457
|
+
});
|
|
458
|
+
}, []);
|
|
459
|
+
return (<>
|
|
460
|
+
<Script src="/overlay-vanilla.js" strategy="afterInteractive" />
|
|
461
|
+
{/* variants ... */}
|
|
462
|
+
</>);
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
Vite-React: use `<script>` in `index.html` or `useEffect` with a dynamic `import()`. Same `LiveCanvas.init({...})` call.
|
|
477
467
|
|
|
478
468
|
### Why the templates live in the route directory
|
|
479
469
|
|
|
@@ -555,6 +545,7 @@ The Live Canvas page must include:
|
|
|
555
545
|
1. **Header** with:
|
|
556
546
|
- Design Brief summary (target, scope, key requirements)
|
|
557
547
|
- Instructions for reviewing
|
|
548
|
+
- **Lab banner (REQUIRED)** — paste `~/.claude/skills/live-canvas/templates/lab-banner.html` at the top of the lab page. Same text in any mode. For React/TSX labs, translate the inline style to a JS object: camelCase keys, string values. E.g. `style="border-radius:8px; padding:10px 14px; font-size:13px"` → `style={{ borderRadius: '8px', padding: '10px 14px', fontSize: '13px' }}`. Keep the text and `role="note"`.
|
|
558
549
|
|
|
559
550
|
2. **Variant Grid** with:
|
|
560
551
|
- Clear labels (A, B, C, D, E)
|
|
@@ -575,43 +566,13 @@ The Live Canvas page must include:
|
|
|
575
566
|
|
|
576
567
|
⚠️ **THIS IS THE MOST IMPORTANT REQUIREMENT** ⚠️
|
|
577
568
|
|
|
578
|
-
The
|
|
579
|
-
|
|
580
|
-
- Create `FeedbackOverlay.tsx` in the SAME directory as `page.tsx`
|
|
581
|
-
- Import with relative path: `import { FeedbackOverlay } from './FeedbackOverlay'`
|
|
582
|
-
- Render at the END of the page, after all variants
|
|
583
|
-
- Pass `targetName` prop with the component/page name
|
|
569
|
+
The overlay (`overlay-vanilla.js`) enables users to click on elements and leave comments. Without it, the Live Canvas is just a static page with no way to collect structured feedback.
|
|
584
570
|
|
|
585
|
-
|
|
571
|
+
- Copy `~/.claude/skills/live-canvas/templates/overlay-vanilla.js` into a directory served by the dev server (e.g. `public/`, `static/`, or wherever the framework serves static assets).
|
|
572
|
+
- Reference it from the lab page via `<script>` tag and call `LiveCanvas.init({...})` once with `target`, `channelUrl` (Live mode), and optional `batchEndpoint`. See "Wiring the overlay" above for the exact snippets per framework.
|
|
573
|
+
- Every variant container in the lab page MUST have a `data-variant="X"` attribute (A, B, C, D, E, or F). The overlay uses this to route comments to the right variant file.
|
|
586
574
|
|
|
587
|
-
|
|
588
|
-
import { FeedbackOverlay } from './FeedbackOverlay'; // Relative import - always works
|
|
589
|
-
|
|
590
|
-
export default function DesignLabPage() {
|
|
591
|
-
return (
|
|
592
|
-
<div className="min-h-screen bg-background">
|
|
593
|
-
<header>...</header>
|
|
594
|
-
|
|
595
|
-
<main>
|
|
596
|
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
597
|
-
<div data-variant="A">
|
|
598
|
-
<VariantA />
|
|
599
|
-
</div>
|
|
600
|
-
<div data-variant="B">
|
|
601
|
-
<VariantB />
|
|
602
|
-
</div>
|
|
603
|
-
{/* ... more variants */}
|
|
604
|
-
</div>
|
|
605
|
-
</main>
|
|
606
|
-
|
|
607
|
-
{/* CRITICAL: FeedbackOverlay must be included */}
|
|
608
|
-
<FeedbackOverlay targetName="ComponentName" />
|
|
609
|
-
</div>
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
**If you forget the FeedbackOverlay, the user CANNOT provide feedback.** This defeats the entire purpose of the Live Canvas.
|
|
575
|
+
**If you forget to wire up the overlay, the user CANNOT provide feedback.** This defeats the entire purpose of the Live Canvas.
|
|
615
576
|
|
|
616
577
|
### Code Quality
|
|
617
578
|
|
|
@@ -665,17 +626,17 @@ Make sure your dev server is running, then:
|
|
|
665
626
|
4. Keep going, or tell me "done" whenever you're ready to synthesize a winner
|
|
666
627
|
```
|
|
667
628
|
|
|
668
|
-
**If
|
|
629
|
+
**If JSON mode:**
|
|
669
630
|
|
|
670
631
|
```
|
|
671
|
-
📝 Live Canvas ready —
|
|
632
|
+
📝 Live Canvas ready — JSON mode
|
|
672
633
|
|
|
673
634
|
Variants are at: http://localhost:3000/__live_canvas
|
|
674
635
|
|
|
675
636
|
Click "Add Feedback" (bottom-right), comment on elements, fill "Overall Direction", click Submit.
|
|
676
637
|
Then paste the JSON/markdown here, or just tell me your feedback in plain English.
|
|
677
638
|
|
|
678
|
-
(To
|
|
639
|
+
(To use Live mode next time: relaunch with `live-claude` and pick Live when /live-canvas asks.)
|
|
679
640
|
```
|
|
680
641
|
|
|
681
642
|
### Then proceed to Phase 5
|
|
@@ -717,7 +678,7 @@ make this more prominent
|
|
|
717
678
|
|
|
718
679
|
If multiple `<channel>` tags arrive together, batch the acknowledgments but do each edit one at a time so the user's dev server hot-reloads visibly between changes.
|
|
719
680
|
|
|
720
|
-
###
|
|
681
|
+
### JSON mode — interactive or pasted
|
|
721
682
|
|
|
722
683
|
The Live Canvas includes a Figma-like feedback overlay. When presenting the lab, include these instructions:
|
|
723
684
|
|
|
@@ -910,6 +871,7 @@ When abort is detected:
|
|
|
910
871
|
- "Are you sure you want to cancel? This will delete all the Live Canvas files I created."
|
|
911
872
|
|
|
912
873
|
2. **If confirmed, clean up immediately:**
|
|
874
|
+
- If Live mode was active, call `mcp__live-canvas__channel_close` to release port 8788.
|
|
913
875
|
- Delete `.claude-design/` directory entirely
|
|
914
876
|
- Delete temporary route files (`app/__live_canvas/`, etc.)
|
|
915
877
|
- Do NOT generate any implementation plan
|
|
@@ -926,6 +888,8 @@ When user confirms (selected "Yes, finalize it"):
|
|
|
926
888
|
|
|
927
889
|
### 8.1: Cleanup
|
|
928
890
|
|
|
891
|
+
If Live mode was active, call `mcp__live-canvas__channel_close` to release port 8788 so another session can claim it.
|
|
892
|
+
|
|
929
893
|
Delete all temporary files:
|
|
930
894
|
- Remove `.claude-design/` directory entirely
|
|
931
895
|
- Remove temporary route files:
|
|
@@ -79,6 +79,9 @@
|
|
|
79
79
|
<header>
|
|
80
80
|
<h1>Live Canvas — Post card demo</h1>
|
|
81
81
|
<p>5 variations of a social post (likes, retweets, comments). Click <b>Add Feedback</b> bottom-right → click any element → leave a comment. Right-click the pill to submit.</p>
|
|
82
|
+
<div style="background:#fef3c7;border:1px solid #fbbf24;border-radius:8px;padding:10px 14px;margin-top:12px;font-size:13px;color:#78350f;">
|
|
83
|
+
<b>This is an overlay-only demo.</b> Feedback events transit through the Live channel (or JSON file, with <code>?json=1</code>) so you can verify the UI works — but there are no <code>.claude-design/lab/variants/</code> files behind these cards, so the Claude session receiving events <em>cannot</em> edit anything. For the full lifecycle, run <code>/live-canvas</code> in a real project.
|
|
84
|
+
</div>
|
|
82
85
|
</header>
|
|
83
86
|
|
|
84
87
|
<main>
|
|
@@ -193,12 +196,14 @@
|
|
|
193
196
|
|
|
194
197
|
</main>
|
|
195
198
|
|
|
196
|
-
<!-- Overlay (
|
|
197
|
-
<script src="../overlay-vanilla.js"></script>
|
|
199
|
+
<!-- Overlay (served from sibling templates/ dir; works under any static server rooted at the skill dir) -->
|
|
200
|
+
<script src="../templates/overlay-vanilla.js"></script>
|
|
198
201
|
<script>
|
|
202
|
+
// ?json=1 forces JSON mode (skip channel probe); default tries Live first.
|
|
203
|
+
const forceJson = new URLSearchParams(location.search).has('json');
|
|
199
204
|
LiveCanvas.init({
|
|
200
205
|
target: 'PostCard',
|
|
201
|
-
channelUrl: 'http://localhost:8788',
|
|
206
|
+
...(forceJson ? {} : { channelUrl: 'http://localhost:8788' }),
|
|
202
207
|
});
|
|
203
208
|
</script>
|
|
204
209
|
</body>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<div role="note" style="background:#fefce8;border:1px solid #facc15;border-radius:8px;padding:10px 14px;margin:12px 0;font-size:13px;line-height:1.5;color:#854d0e;">
|
|
2
|
+
<b>This is a temporary design lab.</b> Click any element → leave a comment → Save.
|
|
3
|
+
Your feedback goes to Claude; the lab is deleted on Finish. The overlay
|
|
4
|
+
badge (bottom-right) tells you whether feedback is streaming live or being
|
|
5
|
+
collected as JSON.
|
|
6
|
+
</div>
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Batch — saves accumulate locally; Submit All POSTs JSONL to batchEndpoint
|
|
24
24
|
* (or downloads the file if no endpoint configured)
|
|
25
25
|
*
|
|
26
|
-
* Payload schema: v1.0
|
|
26
|
+
* Payload schema: v1.0 (see live-canvas-channel/schema.json).
|
|
27
27
|
*/
|
|
28
28
|
(function () {
|
|
29
29
|
'use strict';
|
|
@@ -38,11 +38,16 @@
|
|
|
38
38
|
batchEndpoint: null,
|
|
39
39
|
active: false,
|
|
40
40
|
picking: false,
|
|
41
|
+
minimized: false, // collapsed to a single bubble?
|
|
41
42
|
comments: [], // Comment[] — only items pending batch submit
|
|
42
43
|
overall: '',
|
|
43
44
|
pinCounts: Object.create(null), // `${variant}|${selector}` → placed-pin count
|
|
44
45
|
};
|
|
45
46
|
|
|
47
|
+
// Persist collapse state across hot reloads / variant switches.
|
|
48
|
+
const MIN_KEY = 'lc-minimized';
|
|
49
|
+
try { state.minimized = sessionStorage.getItem(MIN_KEY) === '1'; } catch (_) {}
|
|
50
|
+
|
|
46
51
|
// ---------- utilities ----------
|
|
47
52
|
|
|
48
53
|
const uid = () => `c-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
@@ -134,7 +139,8 @@
|
|
|
134
139
|
const css = `
|
|
135
140
|
[${DATA_OVERLAY}] { font-family: system-ui, sans-serif; box-sizing: border-box; }
|
|
136
141
|
.${PFX}-bar { position: fixed; right: 16px; bottom: 16px; z-index: 2147483646;
|
|
137
|
-
display: flex; gap: 8px; }
|
|
142
|
+
display: flex; gap: 8px; align-items: center; }
|
|
143
|
+
.${PFX}-bar[data-hidden='1'] { display: none; }
|
|
138
144
|
.${PFX}-btn { border: 0; border-radius: 999px; padding: 10px 16px;
|
|
139
145
|
font-weight: 600; font-size: 13px; cursor: pointer;
|
|
140
146
|
box-shadow: 0 4px 12px rgba(0,0,0,.25); font-family: inherit; }
|
|
@@ -146,9 +152,22 @@
|
|
|
146
152
|
.${PFX}-submit .${PFX}-count { display: inline-block; background: #d946ef; color: #fff;
|
|
147
153
|
border-radius: 999px; min-width: 18px; padding: 0 6px; margin-left: 6px;
|
|
148
154
|
font-size: 11px; line-height: 18px; text-align: center; }
|
|
155
|
+
.${PFX}-min { width: 32px; height: 32px; padding: 0; border-radius: 50%;
|
|
156
|
+
background: #fff; color: #111; border: 1px solid #e4e4e7; font-size: 16px;
|
|
157
|
+
line-height: 1; display: flex; align-items: center; justify-content: center; }
|
|
158
|
+
.${PFX}-bubble { position: fixed; right: 16px; bottom: 16px; z-index: 2147483646;
|
|
159
|
+
width: 36px; height: 36px; border-radius: 50%; border: 0; cursor: pointer;
|
|
160
|
+
background: #111; color: #fff; font-size: 14px; font-weight: 700;
|
|
161
|
+
box-shadow: 0 4px 12px rgba(0,0,0,.25); display: none; }
|
|
162
|
+
.${PFX}-bubble[data-show='1'] { display: flex; align-items: center; justify-content: center; }
|
|
149
163
|
.${PFX}-mode { position: fixed; right: 16px; bottom: 60px; z-index: 2147483646;
|
|
150
164
|
background: rgba(0,0,0,.75); color: #fff; font-size: 11px;
|
|
151
165
|
padding: 4px 8px; border-radius: 4px; pointer-events: none; }
|
|
166
|
+
.${PFX}-mode[data-hidden='1'] { display: none; }
|
|
167
|
+
@media (max-width: 640px) {
|
|
168
|
+
.${PFX}-popup { left: 8px !important; right: 8px; width: auto !important; max-width: none; }
|
|
169
|
+
.${PFX}-submit-card { width: 100% !important; max-width: calc(100vw - 24px); }
|
|
170
|
+
}
|
|
152
171
|
.${PFX}-picking { cursor: crosshair !important; }
|
|
153
172
|
.${PFX}-hover-outline { outline: 2px solid #d946ef !important; outline-offset: 2px; }
|
|
154
173
|
.${PFX}-pin { position: absolute; z-index: 2147483645; width: 24px; height: 24px;
|
|
@@ -235,9 +254,33 @@
|
|
|
235
254
|
|
|
236
255
|
// ---------- UI ----------
|
|
237
256
|
|
|
238
|
-
let toggleBtn, submitBtn, modeBadge, toast, popupNode;
|
|
257
|
+
let toggleBtn, submitBtn, minBtn, bubbleBtn, barNode, modeBadge, toast, popupNode;
|
|
239
258
|
let hoverEl = null;
|
|
240
259
|
|
|
260
|
+
const applyMinimized = () => {
|
|
261
|
+
if (!barNode) return;
|
|
262
|
+
barNode.setAttribute('data-hidden', state.minimized ? '1' : '0');
|
|
263
|
+
modeBadge.setAttribute('data-hidden', state.minimized ? '1' : '0');
|
|
264
|
+
bubbleBtn.setAttribute('data-show', state.minimized ? '1' : '0');
|
|
265
|
+
// state.mode can flip live → batch mid-session if a push fails; refresh
|
|
266
|
+
// the badge each time we re-show it so it doesn't lie.
|
|
267
|
+
if (!state.minimized) {
|
|
268
|
+
modeBadge.textContent = `${state.mode === 'live' ? 'LIVE' : 'JSON'} mode`;
|
|
269
|
+
}
|
|
270
|
+
// Cancel an active pick when collapsing — otherwise clicks land on the page.
|
|
271
|
+
if (state.minimized && state.picking) {
|
|
272
|
+
state.picking = false;
|
|
273
|
+
setPickingCursor(false);
|
|
274
|
+
clearHover();
|
|
275
|
+
toggleBtn.setAttribute('data-active', '0');
|
|
276
|
+
toggleBtn.textContent = 'Add Feedback';
|
|
277
|
+
}
|
|
278
|
+
closePopup();
|
|
279
|
+
try { sessionStorage.setItem(MIN_KEY, state.minimized ? '1' : '0'); } catch (_) {}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const setMinimized = (v) => { state.minimized = !!v; applyMinimized(); };
|
|
283
|
+
|
|
241
284
|
const pendingCount = () => state.comments.filter(c => !c.delivered).length;
|
|
242
285
|
|
|
243
286
|
const refreshSubmitBtn = () => {
|
|
@@ -442,14 +485,29 @@
|
|
|
442
485
|
submitBtn = el('button', { class: `${PFX}-btn ${PFX}-submit`, on: {
|
|
443
486
|
click: openSubmitModal,
|
|
444
487
|
}});
|
|
488
|
+
minBtn = el('button', {
|
|
489
|
+
class: `${PFX}-btn ${PFX}-min`,
|
|
490
|
+
title: 'Hide overlay',
|
|
491
|
+
'aria-label': 'Hide overlay',
|
|
492
|
+
on: { click: () => setMinimized(true) },
|
|
493
|
+
}, '−');
|
|
445
494
|
refreshSubmitBtn();
|
|
446
|
-
|
|
447
|
-
|
|
495
|
+
barNode = el('div', { class: `${PFX}-bar` }, [minBtn, submitBtn, toggleBtn]);
|
|
496
|
+
bubbleBtn = el('button', {
|
|
497
|
+
class: `${PFX}-bubble`,
|
|
498
|
+
title: 'Show feedback overlay',
|
|
499
|
+
'aria-label': 'Show feedback overlay',
|
|
500
|
+
on: { click: () => setMinimized(false) },
|
|
501
|
+
}, '◐');
|
|
502
|
+
modeBadge = el('div', { class: `${PFX}-mode` }, `${state.mode === 'live' ? 'LIVE' : 'JSON'} mode`);
|
|
448
503
|
toast = el('div', { class: `${PFX}-toast` });
|
|
449
|
-
document.body.appendChild(
|
|
504
|
+
document.body.appendChild(barNode);
|
|
505
|
+
document.body.appendChild(bubbleBtn);
|
|
450
506
|
document.body.appendChild(modeBadge);
|
|
451
507
|
document.body.appendChild(toast);
|
|
452
508
|
|
|
509
|
+
applyMinimized();
|
|
510
|
+
|
|
453
511
|
document.addEventListener('mousemove', onMouseMove, true);
|
|
454
512
|
document.addEventListener('click', onClick, true);
|
|
455
513
|
};
|