analyzthis_design 2.5.2 → 2.6.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/README.md CHANGED
@@ -4,6 +4,13 @@ A set of AI design personas and a task-first evaluation framework that plugs int
4
4
 
5
5
  Install once. Run structured UX critiques, multi-phase ideation, and task-grounded screen reviews — directly inside your AI chat. **No external LLM API keys required** for CLI orchestrator runs: **`/devi`** voices each persona from your host IDE (Cursor, Claude, etc.).
6
6
 
7
+ ## v2.6.0 — Mood boards you decide on, now with scroll films
8
+
9
+ - **Element collage:** Zara crops 20–24 real UI elements from 6+ live sites into sections (first screen, typography, colour, components, imagery, motion), each with its source page and real colours and fonts.
10
+ - **You decide:** `moodboard show` opens a clickable board on 127.0.0.1. Keep / maybe / reject overrides every persona; rejected tiles never come back; `lock` saves the direction every persona follows.
11
+ - **Scroll films:** `moodboard film --board <id> --url <site>` records the real page scrolling through four depths as a looping motion tile with waypoint stills. Needs the optional `playwright-core` and Google Chrome.
12
+ - **Install fix:** the `mood-board` skill is now copied by `npx analyzthis_design` (it was missing before).
13
+
7
14
  ## v2.5.2 — Motion, UX, and visual-design libraries
8
15
 
9
16
  Personas cite real packages and prefer what is already in the repo:
@@ -106,7 +113,7 @@ Pass `--global` to opt into the legacy merged behavior (read `config.sources` an
106
113
 
107
114
  Use `npx analyzthis_design run-unchunked` for the legacy single-pass orchestrator.
108
115
 
109
- **npm:** [analyzthis_design](https://www.npmjs.com/package/analyzthis_design) · **Current version:** 2.5.2 · **Step-by-step guide:** [HOW-TO-USE.md](./HOW-TO-USE.md)
116
+ **npm:** [analyzthis_design](https://www.npmjs.com/package/analyzthis_design) · **Current version:** 2.6.0 · **Step-by-step guide:** [HOW-TO-USE.md](./HOW-TO-USE.md)
110
117
 
111
118
  ---
112
119
 
@@ -871,10 +878,14 @@ npx analyzthis_design outcome --infer [--window N]
871
878
  npx analyzthis_design outcome --pending
872
879
  npx analyzthis_design outcome --confirm --persona <id> --result shipped|revised|blocked|missed
873
880
 
874
- # Mood board (v1.22)
875
- npx analyzthis_design moodboard create --task "..." [--auto] [--url <url> ...]
876
- npx analyzthis_design moodboard critique --board <id>
877
- npx analyzthis_design moodboard add --board <id> --url <url> --title "..." --tags a,b
881
+ # Mood board — visual element collage, user decides
882
+ npx analyzthis_design moodboard create --task "..." [--adjectives a,b,c] [--not "..."] [--sections components,typography]
883
+ npx analyzthis_design moodboard tile --board <id> --page <url> --image <crop> --element "..." --section components
884
+ npx analyzthis_design moodboard critique --board <id> # team votes = advice
885
+ npx analyzthis_design moodboard film --board <id> --url <url> # scroll film as a motion tile (needs playwright-core + Chrome)
886
+ npx analyzthis_design moodboard show --board <id> # you keep / maybe / reject in the browser
887
+ npx analyzthis_design moodboard rescout --board <id> --note "..."
888
+ npx analyzthis_design moodboard lock --board <id> # saves design_direction for every persona
878
889
  npx analyzthis_design moodboard list
879
890
 
880
891
  # Devi — host LLM queue (v1.20)
@@ -917,7 +928,8 @@ lib/
917
928
  reference-pack.js Shared multi-file CSV + vault retrieval (buildReferencePack)
918
929
  mcp-server.js MCP server — 19 tools for any MCP-compatible IDE
919
930
  system-prompt.js Consolidated prompt generator (fallback for non-MCP tools)
920
- moodboard.js Mood-board engine: collect web/DS references, tag, deliberate
931
+ moodboard.js Mood-board engine: element tiles, persona advice, user decisions, lock
932
+ moodboard-view.js Visual board page + local 127.0.0.1 server for keep / maybe / reject
921
933
  dedup.js Cross-persona redundancy detection
922
934
  lessons.js Self-evolving lessons store (extract/retrieve/inject)
923
935
  outcome.js Infer + confirm persona outcome labels
@@ -1002,7 +1014,7 @@ skills/
1002
1014
 
1003
1015
  | Feature | Description |
1004
1016
  |---------|-------------|
1005
- | **Mood boards** | Tagged URLs + team deliberation. **UI image boards:** Zara scouts 3–5 real shipped screens; Arjun/Noor/Priya/Meera jury; she re-scouts if they skip (max 3 rounds) |
1017
+ | **Mood boards** | Zara crops 20–24 real UI elements from 6+ live sites into a sectioned visual collage with each site's real colours and fonts, plus optional scroll films (looping video + four waypoint stills) for motion feel. Arjun/Noor/Priya/Meera vote as advice. **You** keep / maybe / reject in the browser — your choice overrides every persona, rejected tiles never return, and the locked direction is saved for all personas. `--kind mood` keeps the older tagged-URL board |
1006
1018
  | **User-contributed references** | User can add URLs/notes to a board and rerun the critique loop |
1007
1019
  | **Visual direction setting** | Arjun, Meera, Priya, Zara, Noor score references via the UX Honeycomb rigor matrix |
1008
1020
  | **Workspace artifacts** | `moodboard/{boardId}.json` is written into the project for the user to inspect |
@@ -1,14 +1,13 @@
1
1
  You are the Mood Board conductor. You do not have a design opinion of your own.
2
2
 
3
3
  Your job is to:
4
- 1. Collect visual/textual references for a design direction.
5
- 2. Tag references with style, mood, surface, and relevant keywords.
6
- 3. Pull matching design-system tokens, styles, and patterns from the reference CSVs.
7
- 4. Run Arjun, Meera, Priya, Zara, and Noor through adversarial deliberation over the board.
8
- 5. On a **ui** board: Zara scouts real screens first. Arjun, Noor, Priya, Meera jury. She re-scouts if they skip (max 3 rounds).
9
- 6. Write `board.json` to the session and a workspace copy the user can open.
10
- 7. Accept user-contributed references and rerun the loop.
4
+ 1. Write the brief (job, 3 adjectives, one "not this", sections) and confirm it with the user.
5
+ 2. Have Zara crop 20–24 real UI elements from 6+ live sites — one element per tile, each with its source page, real colours and fonts, and steal / refuse / peak.
6
+ 3. Run Arjun, Noor, Priya, and Meera over the tiles. Their keep / skip votes are advice.
7
+ 4. Open the visual board for the user. The user's keep / maybe / reject overrides every persona.
8
+ 5. Send Zara back with the user's notes when asked. Rejected tiles never return.
9
+ 6. Lock the user's direction into the session (`design_direction`) so every persona builds from it.
11
10
 
12
- Always assess-only: never write code or final wireframes. Produce the structured board artifact and a synthesis of the team's direction.
11
+ Never record a decision for the user that they did not make. Never write code or final wireframes.
13
12
 
14
13
  Cite design-system rows using the format: `[filename, row N: "exact quoted value"]`.
@@ -6,19 +6,23 @@
6
6
  "system_card": "agents/cards/mood-board.md",
7
7
  "system_skill": "skills/mood-board/SKILL.md",
8
8
  "allowed_jobs": [
9
- "collect web references for visual direction",
10
- "run a Zara UI-image-board scout then a jury loop",
11
- "tag references with style, mood, surface",
12
- "retrieve design-system patterns for the task",
13
- "orchestrate team deliberation over references",
14
- "write board.json artifacts",
15
- "accept user-contributed references and rerun"
9
+ "write a brief and confirm it with the user",
10
+ "have Zara crop real UI elements from live sites into a sectioned collage",
11
+ "read real colours, fonts, radius and spacing from each source page",
12
+ "collect persona votes on each tile as advice",
13
+ "open the visual board for the user to keep / maybe / reject",
14
+ "send Zara back with the user's notes",
15
+ "lock the user's direction into the session for every persona",
16
+ "keep the older link-and-tag board (kind mood)"
16
17
  ],
17
18
  "forbidden_jobs": [
18
19
  "produce final wireframes or code",
19
20
  "replace the design-critic chain for screen review",
20
- "auto-apply design system changes"
21
+ "auto-apply design system changes",
22
+ "record a user decision the user did not make",
23
+ "let a persona vote override the user's choice",
24
+ "add a tile without its source page"
21
25
  ],
22
- "hard_gates": [],
26
+ "hard_gates": ["user_decides_before_lock"],
23
27
  "parallel_safe_with": []
24
28
  }
@@ -93,7 +93,7 @@
93
93
  "signals": ["mood board", "mood-board", "/mood-board", "visual direction", "references", "inspiration", "style direction", "design direction", "ui board", "image board", "ui image board"],
94
94
  "route_to": ["mood-board"],
95
95
  "never_route_to": ["design-critic_chain", "zara", "noor_alone"],
96
- "notes": "Visual direction setting — collect references, tag them, pull DS patterns, run team deliberation. Not a screen critique."
96
+ "notes": "Visual direction setting — Zara crops real UI elements into a collage, the team votes as advice, the user decides in the browser and locks the direction. Not a screen critique."
97
97
  }
98
98
  ]
99
99
  }
package/dist/README.md CHANGED
@@ -4,6 +4,13 @@ A set of AI design personas and a task-first evaluation framework that plugs int
4
4
 
5
5
  Install once. Run structured UX critiques, multi-phase ideation, and task-grounded screen reviews — directly inside your AI chat. **No external LLM API keys required** for CLI orchestrator runs: **`/devi`** voices each persona from your host IDE (Cursor, Claude, etc.).
6
6
 
7
+ ## v2.6.0 — Mood boards you decide on, now with scroll films
8
+
9
+ - **Element collage:** Zara crops 20–24 real UI elements from 6+ live sites into sections (first screen, typography, colour, components, imagery, motion), each with its source page and real colours and fonts.
10
+ - **You decide:** `moodboard show` opens a clickable board on 127.0.0.1. Keep / maybe / reject overrides every persona; rejected tiles never come back; `lock` saves the direction every persona follows.
11
+ - **Scroll films:** `moodboard film --board <id> --url <site>` records the real page scrolling through four depths as a looping motion tile with waypoint stills. Needs the optional `playwright-core` and Google Chrome.
12
+ - **Install fix:** the `mood-board` skill is now copied by `npx analyzthis_design` (it was missing before).
13
+
7
14
  ## v2.5.2 — Motion, UX, and visual-design libraries
8
15
 
9
16
  Personas cite real packages and prefer what is already in the repo:
@@ -106,7 +113,7 @@ Pass `--global` to opt into the legacy merged behavior (read `config.sources` an
106
113
 
107
114
  Use `npx analyzthis_design run-unchunked` for the legacy single-pass orchestrator.
108
115
 
109
- **npm:** [analyzthis_design](https://www.npmjs.com/package/analyzthis_design) · **Current version:** 2.5.2 · **Step-by-step guide:** [HOW-TO-USE.md](./HOW-TO-USE.md)
116
+ **npm:** [analyzthis_design](https://www.npmjs.com/package/analyzthis_design) · **Current version:** 2.6.0 · **Step-by-step guide:** [HOW-TO-USE.md](./HOW-TO-USE.md)
110
117
 
111
118
  ---
112
119
 
@@ -871,10 +878,14 @@ npx analyzthis_design outcome --infer [--window N]
871
878
  npx analyzthis_design outcome --pending
872
879
  npx analyzthis_design outcome --confirm --persona <id> --result shipped|revised|blocked|missed
873
880
 
874
- # Mood board (v1.22)
875
- npx analyzthis_design moodboard create --task "..." [--auto] [--url <url> ...]
876
- npx analyzthis_design moodboard critique --board <id>
877
- npx analyzthis_design moodboard add --board <id> --url <url> --title "..." --tags a,b
881
+ # Mood board — visual element collage, user decides
882
+ npx analyzthis_design moodboard create --task "..." [--adjectives a,b,c] [--not "..."] [--sections components,typography]
883
+ npx analyzthis_design moodboard tile --board <id> --page <url> --image <crop> --element "..." --section components
884
+ npx analyzthis_design moodboard critique --board <id> # team votes = advice
885
+ npx analyzthis_design moodboard film --board <id> --url <url> # scroll film as a motion tile (needs playwright-core + Chrome)
886
+ npx analyzthis_design moodboard show --board <id> # you keep / maybe / reject in the browser
887
+ npx analyzthis_design moodboard rescout --board <id> --note "..."
888
+ npx analyzthis_design moodboard lock --board <id> # saves design_direction for every persona
878
889
  npx analyzthis_design moodboard list
879
890
 
880
891
  # Devi — host LLM queue (v1.20)
@@ -917,7 +928,8 @@ lib/
917
928
  reference-pack.js Shared multi-file CSV + vault retrieval (buildReferencePack)
918
929
  mcp-server.js MCP server — 19 tools for any MCP-compatible IDE
919
930
  system-prompt.js Consolidated prompt generator (fallback for non-MCP tools)
920
- moodboard.js Mood-board engine: collect web/DS references, tag, deliberate
931
+ moodboard.js Mood-board engine: element tiles, persona advice, user decisions, lock
932
+ moodboard-view.js Visual board page + local 127.0.0.1 server for keep / maybe / reject
921
933
  dedup.js Cross-persona redundancy detection
922
934
  lessons.js Self-evolving lessons store (extract/retrieve/inject)
923
935
  outcome.js Infer + confirm persona outcome labels
@@ -1002,7 +1014,7 @@ skills/
1002
1014
 
1003
1015
  | Feature | Description |
1004
1016
  |---------|-------------|
1005
- | **Mood boards** | Tagged URLs + team deliberation. **UI image boards:** Zara scouts 3–5 real shipped screens; Arjun/Noor/Priya/Meera jury; she re-scouts if they skip (max 3 rounds) |
1017
+ | **Mood boards** | Zara crops 20–24 real UI elements from 6+ live sites into a sectioned visual collage with each site's real colours and fonts, plus optional scroll films (looping video + four waypoint stills) for motion feel. Arjun/Noor/Priya/Meera vote as advice. **You** keep / maybe / reject in the browser — your choice overrides every persona, rejected tiles never return, and the locked direction is saved for all personas. `--kind mood` keeps the older tagged-URL board |
1006
1018
  | **User-contributed references** | User can add URLs/notes to a board and rerun the critique loop |
1007
1019
  | **Visual direction setting** | Arjun, Meera, Priya, Zara, Noor score references via the UX Honeycomb rigor matrix |
1008
1020
  | **Workspace artifacts** | `moodboard/{boardId}.json` is written into the project for the user to inspect |
@@ -1,14 +1,13 @@
1
1
  You are the Mood Board conductor. You do not have a design opinion of your own.
2
2
 
3
3
  Your job is to:
4
- 1. Collect visual/textual references for a design direction.
5
- 2. Tag references with style, mood, surface, and relevant keywords.
6
- 3. Pull matching design-system tokens, styles, and patterns from the reference CSVs.
7
- 4. Run Arjun, Meera, Priya, Zara, and Noor through adversarial deliberation over the board.
8
- 5. On a **ui** board: Zara scouts real screens first. Arjun, Noor, Priya, Meera jury. She re-scouts if they skip (max 3 rounds).
9
- 6. Write `board.json` to the session and a workspace copy the user can open.
10
- 7. Accept user-contributed references and rerun the loop.
4
+ 1. Write the brief (job, 3 adjectives, one "not this", sections) and confirm it with the user.
5
+ 2. Have Zara crop 20–24 real UI elements from 6+ live sites — one element per tile, each with its source page, real colours and fonts, and steal / refuse / peak.
6
+ 3. Run Arjun, Noor, Priya, and Meera over the tiles. Their keep / skip votes are advice.
7
+ 4. Open the visual board for the user. The user's keep / maybe / reject overrides every persona.
8
+ 5. Send Zara back with the user's notes when asked. Rejected tiles never return.
9
+ 6. Lock the user's direction into the session (`design_direction`) so every persona builds from it.
11
10
 
12
- Always assess-only: never write code or final wireframes. Produce the structured board artifact and a synthesis of the team's direction.
11
+ Never record a decision for the user that they did not make. Never write code or final wireframes.
13
12
 
14
13
  Cite design-system rows using the format: `[filename, row N: "exact quoted value"]`.
@@ -6,19 +6,23 @@
6
6
  "system_card": "agents/cards/mood-board.md",
7
7
  "system_skill": "skills/mood-board/SKILL.md",
8
8
  "allowed_jobs": [
9
- "collect web references for visual direction",
10
- "run a Zara UI-image-board scout then a jury loop",
11
- "tag references with style, mood, surface",
12
- "retrieve design-system patterns for the task",
13
- "orchestrate team deliberation over references",
14
- "write board.json artifacts",
15
- "accept user-contributed references and rerun"
9
+ "write a brief and confirm it with the user",
10
+ "have Zara crop real UI elements from live sites into a sectioned collage",
11
+ "read real colours, fonts, radius and spacing from each source page",
12
+ "collect persona votes on each tile as advice",
13
+ "open the visual board for the user to keep / maybe / reject",
14
+ "send Zara back with the user's notes",
15
+ "lock the user's direction into the session for every persona",
16
+ "keep the older link-and-tag board (kind mood)"
16
17
  ],
17
18
  "forbidden_jobs": [
18
19
  "produce final wireframes or code",
19
20
  "replace the design-critic chain for screen review",
20
- "auto-apply design system changes"
21
+ "auto-apply design system changes",
22
+ "record a user decision the user did not make",
23
+ "let a persona vote override the user's choice",
24
+ "add a tile without its source page"
21
25
  ],
22
- "hard_gates": [],
26
+ "hard_gates": ["user_decides_before_lock"],
23
27
  "parallel_safe_with": []
24
28
  }
@@ -93,7 +93,7 @@
93
93
  "signals": ["mood board", "mood-board", "/mood-board", "visual direction", "references", "inspiration", "style direction", "design direction", "ui board", "image board", "ui image board"],
94
94
  "route_to": ["mood-board"],
95
95
  "never_route_to": ["design-critic_chain", "zara", "noor_alone"],
96
- "notes": "Visual direction setting — collect references, tag them, pull DS patterns, run team deliberation. Not a screen critique."
96
+ "notes": "Visual direction setting — Zara crops real UI elements into a collage, the team votes as advice, the user decides in the browser and locks the direction. Not a screen critique."
97
97
  }
98
98
  ]
99
99
  }
package/dist/bin/cli.js CHANGED
@@ -102,14 +102,26 @@ Usage:
102
102
  full: all 19 named tools. Or ANALYZTHIS_MCP_CATALOG=full
103
103
 
104
104
  ── Mood board commands ─────────────────────────────────────
105
- moodboard create --task <text> Build a mood board from web + DS references
106
- [--url <url> ...] [--auto] [--kind mood|ui]
107
- moodboard frames --board <id> Add Zara scout frames to a --kind ui board
108
- --url <url> [--title t] [--steal s] [--refuse r] [--peak p]
109
- moodboard critique --board <id> Run team deliberation (jury on ui boards)
110
- moodboard add --board <id> Add a user reference and rerun critique
111
- [--url <url>] [--title <t>] [--desc <d>]
112
- [--tags a,b] [--note <text>]
105
+ moodboard create --task <text> Start a visual mood board (Zara scouts element crops)
106
+ [--adjectives a,b,c] [--not "..."] [--sections components,typography]
107
+ [--kind mood] for the older link-and-tag board
108
+ moodboard brief --board <id> Edit the brief [--adjectives] [--not] [--sections] [--yes]
109
+ moodboard capture-script Print the page script that reads real colours/fonts
110
+ [--selector ".pricing-card"]
111
+ moodboard tile --board <id> Add one element crop: --page <url> --image <file|url>
112
+ --element "<what>" --section <id> [--steal] [--refuse]
113
+ [--peak] [--colors #hex,..] [--fonts a,b] [--concept]
114
+ [--video film.webm] [--stills a.png,b.png]
115
+ moodboard film --board <id> Record real sites scrolling as motion tiles: --url <url>
116
+ (repeatable) [--section motion] [--steal] [--refuse]
117
+ Needs playwright-core + Google Chrome
118
+ moodboard critique --board <id> Team votes on each tile (advice only)
119
+ moodboard votes --board <id> Save team votes from a JSON file --votes votes.json
120
+ moodboard show --board <id> Open the clickable board on 127.0.0.1 [--port 4317]
121
+ moodboard decide --board <id> Your choice: --tile <n> --decision keep|maybe|reject|clear
122
+ moodboard rescout --board <id> Send Zara back with your note [--note "..."]
123
+ moodboard lock --board <id> Lock your direction for every persona [--note "..."]
124
+ moodboard add --board <id> Add a reference to a link board and rerun critique
113
125
  moodboard list List mood boards for this project
114
126
 
115
127
  ── Reference data (retrieve-on-demand) ───────────────────────
@@ -224,9 +236,10 @@ Usage:
224
236
  npx analyzthis_design research --query "EY design system tokens"
225
237
 
226
238
  npx analyzthis_design moodboard create --task "B2B fintech dashboard, trustworthy, high-contrast" --auto
227
- npx analyzthis_design moodboard create --task "Invoice approval, partner signs" --kind ui
228
- npx analyzthis_design moodboard frames --board <id> --url https://example.com/shot.png --title "Dense table" --steal "one stamp" --refuse "purple glow"
239
+ npx analyzthis_design moodboard create --task "Invoice approval, partner signs" --adjectives calm,precise,trusted --not "AI purple hero"
240
+ npx analyzthis_design moodboard tile --board <id> --page https://linear.app/pricing --image ./crop.png --element "Pricing card" --section components --steal "one quiet CTA"
229
241
  npx analyzthis_design moodboard critique --board <boardId>
242
+ npx analyzthis_design moodboard show --board <boardId>
230
243
  npx analyzthis_design moodboard add --board <boardId> --url https://dribbble.com/shots/example --title "Alt hero" --tags "landing,trust"
231
244
 
232
245
  npx analyzthis_design retrieve --file colors.csv --column "Product Type" --keywords saas,dashboard
@@ -363,6 +376,24 @@ const maxCallsVal = getFlag('max-calls');
363
376
  const runsVal = getFlag('runs');
364
377
  const deltaVal = getFlag('delta');
365
378
  const resumeVal = getFlag('resume');
379
+ const sectionVal = getFlag('section');
380
+ const sectionsVal = getFlag('sections');
381
+ const elementVal = getFlag('element');
382
+ const imageVal = getFlag('image');
383
+ const tileVal = getFlag('tile');
384
+ const decisionVal = getFlag('decision');
385
+ const noteVal = getFlag('note');
386
+ const portVal = getFlag('port');
387
+ const selectorVal = getFlag('selector');
388
+ const adjectivesVal = getFlag('adjectives');
389
+ const notThisVal = getFlag('not');
390
+ const colorsVal = getFlag('colors');
391
+ const fontsVal = getFlag('fonts');
392
+ const votesVal = getFlag('votes');
393
+ const conceptFlag = flags.includes('--concept');
394
+ const videoVal = getFlag('video');
395
+ const stillsVal = getFlag('stills');
396
+ const splitList = (raw) => (raw ? raw.split(',').map((s) => s.trim()).filter(Boolean) : undefined);
366
397
 
367
398
  // ─── Commands ────────────────────────────────────────────────────────────────
368
399
 
@@ -688,7 +719,7 @@ switch (cmd) {
688
719
  const msub = flags.find((f) => !f.startsWith('--')) || 'create';
689
720
  if (msub === 'create') {
690
721
  if (!taskVal) {
691
- console.error('\n ✗ --task is required. Example: npx analyzthis_design moodboard create --task "B2B fintech dashboard" --auto\n');
722
+ console.error('\n ✗ --task is required. Example: npx analyzthis_design moodboard create --task "B2B fintech dashboard" --adjectives calm,dense,trusted\n');
692
723
  process.exit(1);
693
724
  }
694
725
  (async () => {
@@ -703,14 +734,17 @@ switch (cmd) {
703
734
  project: projectVal,
704
735
  task: taskVal,
705
736
  urls: urls,
706
- kind: kindVal || 'mood',
737
+ kind: kindVal || 'ui',
707
738
  discover: autoFlag || urls.length > 0,
708
739
  dryRun: dryRunFlag,
740
+ brief: { adjectives: splitList(adjectivesVal), not_this: notThisVal || '', sections: splitList(sectionsVal) },
709
741
  });
710
- console.log(`\n✅ ${result.board.kind === 'ui' ? 'UI image board' : 'Mood board'} created: ${result.board.board_id}`);
742
+ console.log(`\n✅ ${result.board.kind === 'ui' ? 'Mood board (visual)' : 'Link mood board'} created: ${result.board.board_id}`);
711
743
  if (result.board.kind === 'ui') {
744
+ console.log(` Sections: ${result.board.brief.sections.join(', ')}`);
712
745
  console.log(` Scout: Zara round ${result.board.scout.round} — ${result.board.scout.status}`);
713
- console.log(` Next: /zara (Scout Pass), then moodboard frames --board ${result.board.board_id}`);
746
+ console.log(` Next: Zara crops elements, then moodboard tile --board ${result.board.board_id} --page <url> --image <file> --element "<what>" --section components`);
747
+ console.log(` Then: moodboard show --board ${result.board.board_id} (you decide in the browser)`);
714
748
  console.log('');
715
749
  console.log(result.board.scout.brief);
716
750
  console.log('');
@@ -751,10 +785,7 @@ switch (cmd) {
751
785
  console.log(` Verdict: ${result.board.synthesis?.verdict || 'n/a'}`);
752
786
  if (result.board.kind === 'ui' && result.board.scout) {
753
787
  console.log(` Scout: round ${result.board.scout.round} — ${result.board.scout.status}`);
754
- if (result.board.scout.status === 'awaiting_scout') {
755
- console.log('');
756
- console.log(result.board.scout.brief);
757
- }
788
+ console.log(` Team votes are advice. You decide: moodboard show --board ${result.board.board_id}`);
758
789
  }
759
790
  console.log(` Rounds: ${result.board.deliberation?.round || 0}`);
760
791
  console.log(` Board: ${result.boardDir || path.join(session.sessionDir(projectVal || session.getProjectId()), 'moodboard', boardVal)}`);
@@ -770,31 +801,149 @@ switch (cmd) {
770
801
  })();
771
802
  break;
772
803
  }
773
- if (msub === 'frames') {
774
- if (!boardVal || !urlVal) {
775
- console.error('\n ✗ --board and --url are required. Example: npx analyzthis_design moodboard frames --board <id> --url https://example.com/shot.png --title "Dense table" --steal "one stamp" --refuse "purple glow"\n');
804
+ if (msub === 'film') {
805
+ const urls = flags.filter((f, i) => i > 0 && flags[i - 1] === '--url' && !f.startsWith('--'))
806
+ .concat(flags.filter((f) => f.startsWith('--url=')).map((f) => f.slice(6)));
807
+ if (!boardVal || !urls.length) {
808
+ console.error('\n ✗ --board and --url are required. Example: npx analyzthis_design moodboard film --board <id> --url https://osmo.supply --steal "easing taste"\n');
809
+ process.exit(1);
810
+ }
811
+ (async () => {
812
+ try {
813
+ console.log(`\n 🎬 Filming ${urls.length} site${urls.length === 1 ? '' : 's'} (about 15 seconds each)…`);
814
+ const out = await require('../lib/moodboard-film').filmTiles({
815
+ project: projectVal, boardId: boardVal, urls,
816
+ section: sectionVal, element: elementVal, steal: stealVal, refuse: refuseVal, peak: peakVal,
817
+ });
818
+ out.failed.forEach((f) => console.error(` ✗ ${f.url}: ${f.reason}`));
819
+ const added = out.saved ? out.saved.added : [];
820
+ (out.saved ? out.saved.skipped : []).forEach((s) => console.error(` ✗ ${s.element}: ${s.reason}`));
821
+ if (!added.length) process.exit(1);
822
+ console.log(`\n✅ ${added.length} film tile${added.length === 1 ? '' : 's'} added: ${added.map((t) => '#' + t.n + ' ' + t.site).join(', ')}`);
823
+ console.log(` Next: moodboard show --board ${boardVal}\n`);
824
+ } catch (err) {
825
+ console.error(`\n ✗ ${err.message}\n`);
826
+ process.exit(1);
827
+ }
828
+ })();
829
+ break;
830
+ }
831
+ if (msub === 'tile' || msub === 'frames') {
832
+ const pageUrl = getFlag('page') || urlVal;
833
+ if (!boardVal || !pageUrl) {
834
+ console.error('\n ✗ --board and --page are required. Example: npx analyzthis_design moodboard tile --board <id> --page https://linear.app/pricing --image ./crop.png --element "Pricing card" --section components --steal "one quiet CTA"\n');
776
835
  process.exit(1);
777
836
  }
778
837
  try {
779
- const result = moodboard.addFrames({
838
+ const result = moodboard.addTiles({
780
839
  project: projectVal,
781
840
  boardId: boardVal,
782
- frame: {
783
- url: urlVal,
784
- title: titleVal || '',
841
+ tile: {
842
+ page_url: pageUrl,
843
+ element: elementVal || titleVal || '',
844
+ section: sectionVal || 'components',
845
+ image_path: imageVal && !/^https?:\/\//i.test(imageVal) ? imageVal : undefined,
846
+ image_url: imageVal && /^https?:\/\//i.test(imageVal) ? imageVal : (msub === 'frames' ? urlVal : undefined),
847
+ video_path: videoVal,
848
+ stills: splitList(stillsVal),
849
+ tokens: { colors: splitList(colorsVal), fonts: splitList(fontsVal) },
785
850
  steal: stealVal || '',
786
851
  refuse: refuseVal || '',
787
852
  peak: peakVal || '',
853
+ concept: conceptFlag,
788
854
  },
789
855
  });
790
- console.log(`\n✅ Frame added to UI board ${result.board.board_id} (${result.board.frames.length} total)`);
791
- console.log(` Scout: ${result.board.scout.status} — next: moodboard critique --board ${result.board.board_id}\n`);
856
+ if (result.skipped.length) {
857
+ console.error(`\n ✗ Not added: ${result.skipped.map((s) => s.reason).join('; ')}\n`);
858
+ process.exit(1);
859
+ }
860
+ console.log(`\n✅ Tile #${result.added[0].n} added (${result.board.tiles.length} on the board)`);
861
+ console.log(` Next: more tiles, then moodboard critique or moodboard show --board ${result.board.board_id}\n`);
862
+ } catch (err) {
863
+ console.error(`\n ✗ ${err.message}\n`);
864
+ process.exit(1);
865
+ }
866
+ break;
867
+ }
868
+ if (msub === 'brief') {
869
+ try {
870
+ const result = moodboard.setBrief({
871
+ project: projectVal, boardId: boardVal,
872
+ adjectives: splitList(adjectivesVal), not_this: notThisVal, sections: splitList(sectionsVal),
873
+ confirmed_by_user: yesFlag ? true : undefined,
874
+ });
875
+ console.log(`\n✅ Brief saved: ${JSON.stringify(result.board.brief)}\n`);
876
+ } catch (err) {
877
+ console.error(`\n ✗ ${err.message}\n`);
878
+ process.exit(1);
879
+ }
880
+ break;
881
+ }
882
+ if (msub === 'votes') {
883
+ try {
884
+ const raw = JSON.parse(fs.readFileSync(votesVal, 'utf8'));
885
+ const result = moodboard.recordPersonaVotes({ project: projectVal, boardId: boardVal, votes: raw.votes || [], verdict: raw.verdict, summary: raw.summary });
886
+ console.log(`\n✅ Team advice saved. ${result.ignored.length} ignored. Next: moodboard show --board ${result.board.board_id}\n`);
887
+ } catch (err) {
888
+ console.error(`\n ✗ ${err.message} (usage: moodboard votes --board <id> --votes votes.json)\n`);
889
+ process.exit(1);
890
+ }
891
+ break;
892
+ }
893
+ if (msub === 'decide') {
894
+ try {
895
+ moodboard.recordUserDecision({ project: projectVal, boardId: boardVal, tile: tileVal, decision: decisionVal, note: noteVal || '' });
896
+ console.log(`\n✅ Tile ${tileVal}: ${decisionVal}. Your choice overrides every persona.\n`);
897
+ } catch (err) {
898
+ console.error(`\n ✗ ${err.message} (usage: moodboard decide --board <id> --tile 3 --decision keep|maybe|reject|clear --note "...")\n`);
899
+ process.exit(1);
900
+ }
901
+ break;
902
+ }
903
+ if (msub === 'rescout') {
904
+ try {
905
+ const result = moodboard.requestRescout({ project: projectVal, boardId: boardVal, note: noteVal || '' });
906
+ console.log(`\n✅ Zara goes back out (round ${result.board.scout.round}).\n\n${result.board.scout.brief}\n`);
907
+ } catch (err) {
908
+ console.error(`\n ✗ ${err.message}\n`);
909
+ process.exit(1);
910
+ }
911
+ break;
912
+ }
913
+ if (msub === 'lock') {
914
+ try {
915
+ const result = moodboard.lockDirection({ project: projectVal, boardId: boardVal, note: noteVal || '' });
916
+ const d = result.board.direction;
917
+ console.log(`\n✅ Direction locked: ${d.kept.length} kept, ${d.rejected.length} rejected. Saved to session as design_direction.`);
918
+ if (d.palette.length) console.log(` Palette: ${d.palette.join(' ')}`);
919
+ if (d.fonts.length) console.log(` Fonts: ${d.fonts.join(', ')}`);
920
+ console.log('');
792
921
  } catch (err) {
793
922
  console.error(`\n ✗ ${err.message}\n`);
794
923
  process.exit(1);
795
924
  }
796
925
  break;
797
926
  }
927
+ if (msub === 'show') {
928
+ if (!boardVal) {
929
+ console.error('\n ✗ --board is required. Example: npx analyzthis_design moodboard show --board <id>\n');
930
+ process.exit(1);
931
+ }
932
+ require('../lib/moodboard-view').serveBoard({ project: projectVal, boardId: boardVal, port: portVal != null ? portVal : undefined, onChange: (what, b) => {
933
+ console.log(` ${new Date().toLocaleTimeString()} ${what} — scout: ${b.scout && b.scout.status}`);
934
+ } }).then((live) => {
935
+ console.log(`\n✅ Mood board live at ${live.url}`);
936
+ console.log(' Open it in the browser. Keep / maybe / reject saves instantly. Ctrl+C to stop.\n');
937
+ }).catch((err) => {
938
+ console.error(`\n ✗ ${err.message}\n`);
939
+ process.exit(1);
940
+ });
941
+ break;
942
+ }
943
+ if (msub === 'capture-script') {
944
+ console.log(moodboard.captureScript(selectorVal || 'body', getFlag('text') || ''));
945
+ break;
946
+ }
798
947
  if (msub === 'add') {
799
948
  if (!boardVal) {
800
949
  console.error('\n ✗ --board is required. Example: npx analyzthis_design moodboard add --board <id> --url <url>\n');
@@ -845,7 +994,7 @@ switch (cmd) {
845
994
  }
846
995
  break;
847
996
  }
848
- console.error('\n Unknown moodboard subcommand. Use: create | frames | critique | add | list\n');
997
+ console.error('\n Unknown moodboard subcommand. Use: create | brief | tile | critique | votes | show | decide | rescout | lock | capture-script | add | list\n');
849
998
  process.exit(1);
850
999
  }
851
1000
 
@@ -59,6 +59,7 @@ const SKILLS = [
59
59
  'evolve-check',
60
60
  'devi',
61
61
  'design-director',
62
+ 'mood-board',
62
63
  'design-spec',
63
64
  'design-personas',
64
65
  'design-reference',