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.
Files changed (57) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/LICENSE +202 -21
  3. package/README.md +6 -4
  4. package/installer/cli.js +4 -1
  5. package/package.json +2 -2
  6. package/packages/ampcode/commands/live-canvas/README.md +38 -47
  7. package/packages/{claude/skills/live-canvas/templates/demo → ampcode/commands/live-canvas/dev}/post-variants.html +8 -3
  8. package/packages/ampcode/commands/live-canvas/templates/lab-banner.html +6 -0
  9. package/packages/ampcode/commands/live-canvas/templates/overlay-vanilla.js +64 -6
  10. package/packages/ampcode/commands/live-canvas.md +140 -161
  11. package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/.claude-plugin/plugin.json +1 -1
  12. package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/README.md +2 -2
  13. package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/package-lock.json +13 -13
  14. package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/package.json +1 -1
  15. package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/schema.json +1 -1
  16. package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/server.js +320 -27
  17. package/packages/claude/plugins/live-canvas-marketplace/setup.sh +83 -24
  18. package/packages/claude/skills/live-canvas/README.md +53 -57
  19. package/packages/claude/skills/live-canvas/SKILL.md +122 -158
  20. package/packages/{ampcode/commands/live-canvas/templates/demo → claude/skills/live-canvas/dev}/post-variants.html +8 -3
  21. package/packages/claude/skills/live-canvas/templates/lab-banner.html +6 -0
  22. package/packages/claude/skills/live-canvas/templates/overlay-vanilla.js +64 -6
  23. package/packages/droid/commands/live-canvas/README.md +38 -47
  24. package/packages/droid/commands/live-canvas/{templates/demo → dev}/post-variants.html +8 -3
  25. package/packages/droid/commands/live-canvas/templates/lab-banner.html +6 -0
  26. package/packages/droid/commands/live-canvas/templates/overlay-vanilla.js +64 -6
  27. package/packages/droid/commands/live-canvas.md +140 -161
  28. package/packages/opencode/command/live-canvas/README.md +38 -47
  29. package/packages/opencode/command/live-canvas/{templates/demo → dev}/post-variants.html +8 -3
  30. package/packages/opencode/command/live-canvas/templates/lab-banner.html +6 -0
  31. package/packages/opencode/command/live-canvas/templates/overlay-vanilla.js +64 -6
  32. package/packages/opencode/command/live-canvas.md +140 -161
  33. package/packages/ampcode/commands/live-canvas/templates/.claude/settings.local.json +0 -8
  34. package/packages/ampcode/commands/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +0 -1299
  35. package/packages/ampcode/commands/live-canvas/templates/feedback-react/format-utils.ts +0 -283
  36. package/packages/ampcode/commands/live-canvas/templates/feedback-react/index.ts +0 -62
  37. package/packages/ampcode/commands/live-canvas/templates/feedback-react/selector-utils.ts +0 -423
  38. package/packages/ampcode/commands/live-canvas/templates/feedback-react/types.ts +0 -118
  39. package/packages/claude/skills/live-canvas/INTEGRATION_NOTES.md +0 -210
  40. package/packages/claude/skills/live-canvas/templates/.claude/settings.local.json +0 -8
  41. package/packages/claude/skills/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +0 -1299
  42. package/packages/claude/skills/live-canvas/templates/feedback-react/format-utils.ts +0 -283
  43. package/packages/claude/skills/live-canvas/templates/feedback-react/index.ts +0 -62
  44. package/packages/claude/skills/live-canvas/templates/feedback-react/selector-utils.ts +0 -423
  45. package/packages/claude/skills/live-canvas/templates/feedback-react/types.ts +0 -118
  46. package/packages/droid/commands/live-canvas/templates/.claude/settings.local.json +0 -8
  47. package/packages/droid/commands/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +0 -1299
  48. package/packages/droid/commands/live-canvas/templates/feedback-react/format-utils.ts +0 -283
  49. package/packages/droid/commands/live-canvas/templates/feedback-react/index.ts +0 -62
  50. package/packages/droid/commands/live-canvas/templates/feedback-react/selector-utils.ts +0 -423
  51. package/packages/droid/commands/live-canvas/templates/feedback-react/types.ts +0 -118
  52. package/packages/opencode/command/live-canvas/templates/.claude/settings.local.json +0 -8
  53. package/packages/opencode/command/live-canvas/templates/feedback-react/FeedbackOverlay.tsx +0 -1299
  54. package/packages/opencode/command/live-canvas/templates/feedback-react/format-utils.ts +0 -283
  55. package/packages/opencode/command/live-canvas/templates/feedback-react/index.ts +0 -62
  56. package/packages/opencode/command/live-canvas/templates/feedback-react/selector-utils.ts +0 -423
  57. 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 (host-tool aware)
20
+ ## Feedback Modes always ask the user
21
21
 
22
- Live Canvas supports two feedback transports. The skill auto-selects at runtimethe user never toggles modes manually.
22
+ Live Canvas supports two feedback transports. **The user picks every time** — never auto-select.
23
23
 
24
- - **Mode A — Batch (universal, works everywhere):** each Save writes to `.claude-design/feedback.jsonl`. User types "check" (or any message) to have the assistant read and act on the batch. Works in Claude Code, Droid, Amp, and Opencode identically.
25
- - **Mode B — Live (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. Edits land without the user switching windows.
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
- **Host-tool guidancefollow exactly:**
27
+ ### Host detectiondo this first
28
28
 
29
- | Host | Modes available | What to do |
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
- ### Channel activation run this BEFORE starting the interview
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
- Users invoke `/live-canvas` from an ordinary Claude Code session most of the time. They won't have started with the dev-channels flag unless they remembered. The skill's job is to figure out what state they're in and guide them without making them read docs.
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
- **Step A Probe the channel:**
39
+ ### Mode selection (Claude Code only)
39
40
 
40
- ```bash
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
- **Step C Act on the case.**
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
- ### Case 1 Live ready
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
- Announce briefly and proceed to the interview:
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
- No decision needed. Skip to Phase 1.
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
- ### Case 2 Plugin installed but session not in dev mode
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
- This is the common case for returning users who forgot the dev flag. Use `AskUserQuestion`:
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
- > **Question: How do you want to run this session?**
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
- If they pick "Restart for Live mode", print:
72
+ Substitute the actual `holder_pid` from the tool response into the message below.
73
73
 
74
74
  ```
75
- Close this Claude session, then run:
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
- When it reopens, confirm the safety prompt, then run /live-canvas again — I'll be in Live mode.
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
- Tip: save an alias so you don't retype this every time:
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
- Then exit the skill cleanly do not start the interview. The user is going to close this session.
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 Drelaunch block (no channels flag):**
98
87
 
99
88
  ```
100
- One-time setup for Live mode:
101
-
102
- 1. Install channel plugin dependencies (run in your terminal):
103
- bash ~/.claude/plugins/live-canvas-marketplace/setup.sh
104
-
105
- This runs `npm install` in the plugin dir.
106
-
107
- 2. Inside Claude Code, register and install the plugin:
108
- /plugin marketplace add ~/.claude/plugins/live-canvas-marketplace
109
- /plugin install live-canvas-channel@live-canvas-marketplace
110
-
111
- 3. Close this session and reopen with the dev-channels flag:
112
- claude --dangerously-load-development-channels plugin:live-canvas-channel@live-canvas-marketplace
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
- 4. Accept the safety prompt, then run /live-canvas again.
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
- Exit the skill — don't start the interview. The user has a multi-step setup to do.
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
- If they pick Batch, announce Batch mode and proceed to Phase 1 normally.
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
- ### Why not auto-run the setup commands?
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
- **Do not try to run any of these commands yourself.** Three reasons:
127
- 1. Steps 2 and 3 require Claude Code slash commands and a session restart you can't do either from inside a running session.
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
- ### Choose the right overlay template
423
-
424
- The skill ships two overlay templates under `~/.claude/skills/live-canvas/templates/`:
419
+ ### The overlay
425
420
 
426
- | Template | When to use |
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
- HTML: `<script src="overlay-vanilla.js"></script>` plus an init script that wires up mode + target (see "Wiring the overlay" below).
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
- Every page that renders the lab must initialize the overlay once. Behavior depends on whether Live mode was detected in Phase 0.
427
+ The overlay needs one `init()` call with `target`, `channelUrl` (Live only), and optionally `batchEndpoint`.
456
428
 
457
- **Vanilla (`overlay-vanilla.js`):**
429
+ **Server-rendered / vanilla HTML:**
458
430
 
459
431
  ```html
460
- <script src="./overlay-vanilla.js"></script>
432
+ <script src="/overlay-vanilla.js"></script>
461
433
  <script>
462
434
  LiveCanvas.init({
463
435
  target: '<ComponentOrPageName>',
464
- // Only include channelUrl when Phase 0 detected a live channel.
465
- // If Batch mode, OMIT channelUrl so the overlay skips the probe.
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 batch payloads when channelUrl is missing.
468
- // When omitted, a batch Submit downloads a JSON file instead.
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 (`FeedbackOverlay.tsx`):**
446
+ **React / Next.js / Vite-React:** load the script with the framework's mechanism and init in a `useEffect`:
475
447
 
476
- Pass the same `targetName` prop plus the mode-appropriate endpoints via its props. Render `<FeedbackOverlay />` at the end of the lab page.
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 FeedbackOverlay 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.
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
- **Example integration:**
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
- ```tsx
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 BATCH mode:**
629
+ **If JSON mode:**
669
630
 
670
631
  ```
671
- 📝 Live Canvas ready — Batch mode
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 enable Live mode next time, see the one-time setup printed at the top.)
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
- ### Batch mode — interactive or pasted
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 (relative path works with file://) -->
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, compatible with the upstream React FeedbackOverlay.
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
- const bar = el('div', { class: `${PFX}-bar` }, [submitBtn, toggleBtn]);
447
- modeBadge = el('div', { class: `${PFX}-mode` }, `${state.mode === 'live' ? 'LIVE' : 'BATCH'} mode`);
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(bar);
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
  };