feat: v4.1.0 - UI design workflow matrix mode refactoring

## Core Changes
- Pure matrix mode (style × layout combinations)
- Removed standard/creative mode selection
- Simplified parameters: --style-variants, --layout-variants
- Path corrections: standalone mode uses .workflow/.scratchpad/

## Modified Files
- auto.md: Simplified Phase 3, corrected paths
- generate.md: Complete rewrite for matrix-only mode
- consolidate.md: Path corrections for standalone mode
- extract.md: Path corrections for standalone mode

## New Files
- CHANGELOG-v4.1.0.md: Complete changelog
- _template-compare-matrix.html: Interactive visualization template

## Breaking Changes
- Deprecated: --variants, --creative-variants
- New: --style-variants, --layout-variants
- File naming: {page}-style-{s}-layout-{l}.html

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
catlog22
2025-10-09 10:52:34 +08:00
parent 56a3543031
commit b27708a7da
6 changed files with 1510 additions and 345 deletions

View File

@@ -0,0 +1,302 @@
# UI Design Workflow v4.1.0 - 纯矩阵模式 + 路径修正
## 📋 发布日期
2025-10-09
## 🎯 核心变更
### 1. 矩阵模式成为唯一模式
- ❌ 移除 standard/creative 模式选择
- ✅ 3×3 矩阵生成为默认且唯一模式
- ✅ 直接支持 `--style-variants``--layout-variants` 参数
### 2. 路径符合workflow架构
- ✅ 有session: `.workflow/WFS-{session_id}/runs/run-xxx/`
- ✅ 无session: `.workflow/.scratchpad/{session_id}/runs/run-xxx/`
- ✅ 模板移至全局: `~/.claude/workflows/_template-compare-matrix.html`
---
## 📝 文件修改清单
### 核心命令文件
| 文件 | 主要变更 | 状态 |
|------|---------|------|
| **auto.md** | 删除模式选择简化Phase 3修正路径 | ✅ 已完成 |
| **generate.md** | 完全重构为矩阵模式,集成模板 | ✅ 已完成 |
| **consolidate.md** | 修正standalone路径 | ✅ 已完成 |
| **extract.md** | 修正standalone路径 | ✅ 已完成 |
| **update.md** | 仅session模式无需修改 | ✅ 保持不变 |
### 新增文件
-`~/.claude/workflows/_template-compare-matrix.html` - 交互式矩阵可视化模板
---
## 🔄 参数变更
### 旧参数(废弃)
```bash
--variants <count> # 统一变种数
--creative-variants <count> # 创意变种数
--matrix-mode # 模式标志
```
### 新参数v4.1.0
```bash
--style-variants <count> # 风格变种数默认3
--layout-variants <count> # 布局变种数默认3
# 矩阵为默认模式,无需标志
```
---
## 🚀 工作流对比
### v4.0.x旧版
```bash
/workflow:ui-design:auto --variants 3 --creative-variants 4
# 问题:
# - 参数混淆variants vs creative-variants
# - 模式选择复杂
# - standalone输出到项目根目录
```
### v4.1.0(新版)
```bash
/workflow:ui-design:auto --style-variants 3 --layout-variants 3
# 优势:
# - 参数语义清晰
# - 唯一矩阵模式
# - 输出到 .workflow/.scratchpad/
# - 总计: 3×3×N 个原型
```
---
## 📊 路径架构
### Standalone模式无session
```
.workflow/.scratchpad/
└── design-session-20251009-101530/
└── runs/
├── run-20251009-101530/
│ └── .design/
│ ├── style-extraction/style-cards.json
│ ├── style-consolidation/
│ │ ├── style-1/design-tokens.json
│ │ ├── style-2/design-tokens.json
│ │ └── style-3/design-tokens.json
│ └── prototypes/
│ ├── compare.html (交互式3×3矩阵)
│ ├── index.html
│ └── {page}-style-{s}-layout-{l}.html
└── latest -> run-20251009-101530/
```
### 集成模式有session
```
.workflow/WFS-auth-system/
├── workflow-session.json
├── IMPL_PLAN.md
├── .brainstorming/synthesis-specification.md
└── runs/
├── run-20251009-101530/
│ └── .design/ (同上)
└── latest -> run-20251009-101530/
```
---
## 🔧 核心改进
### 1. 简化架构
- **auto.md Phase 3**: 从复杂并行Task循环简化为单一命令
```bash
# 旧方式30+行)
FOR style_id IN range(...):
Task(conceptual-planning-agent): "..."
# 新方式3行
command = "/workflow:ui-design:generate --style-variants {s} --layout-variants {l}"
SlashCommand(command=command)
```
### 2. 路径规范化
```bash
# auto.md - Phase 0b
IF --session:
base_path = ".workflow/WFS-{session_id}/runs/${run_id}"
ELSE:
base_path = ".workflow/.scratchpad/${session_id}/runs/${run_id}"
# generate/consolidate/extract
base_path = find_latest_design_session(".workflow/.scratchpad/")
```
### 3. 可视化增强
- 集成高级 `_template-compare-matrix.html` 模板
- 3×3 网格矩阵视图
- 同步滚动 + 缩放控制
- 全屏模式 + 选择导出
---
## ⚠️ 破坏性变更
### 1. 参数废弃
```bash
# ❌ 不再支持
--variants <count>
--creative-variants <count>
# ✅ 必须使用
--style-variants <count>
--layout-variants <count>
```
### 2. 文件命名强制统一
```bash
# ❌ 旧格式不再生成
{page}-variant-{n}.html
{page}-creative-variant-{n}.html
# ✅ 强制新格式
{page}-style-{s}-layout-{l}.html
```
### 3. Standalone路径变更
```bash
# ❌ v4.0.x
./design-session-xxx/ (项目根目录)
# ✅ v4.1.0
.workflow/.scratchpad/design-session-xxx/
```
---
## 📖 迁移指南
### 从 v4.0.x 迁移
#### 1. 更新命令参数
```bash
# 旧方式
/workflow:ui-design:auto --variants 3 --creative-variants 4
# 新方式
/workflow:ui-design:auto --style-variants 3 --layout-variants 4
# 或依赖智能解析
/workflow:ui-design:auto --prompt "Generate 3 styles with 4 layouts"
```
#### 2. 更新路径引用
```bash
# 旧standalone输出
./design-session-xxx/
# 新standalone输出
.workflow/.scratchpad/design-session-xxx/
# 迁移建议: 手动移动旧目录或保留为历史
mv ./design-session-* .workflow/.scratchpad/
```
#### 3. 预览文件
```bash
# 保持不变
{base_path}/.design/prototypes/compare.html
{base_path}/.design/prototypes/index.html
```
---
## ✅ 向后兼容性
### 完全兼容
-`--session` 参数
-`--pages` 参数
-`--prompt` 参数
-`--images` 参数
-`--batch-plan` 标志
- ✅ 智能prompt解析
### 不兼容
- ❌ standard/creative 模式选择
- ❌ 旧参数 `--variants`, `--creative-variants`
- ❌ 旧文件命名格式
---
## 🧪 测试清单
### 功能测试
- [ ] 默认3×3矩阵生成
- [ ] 自定义矩阵2×2, 4×3等
- [ ] 智能prompt解析
- [ ] 文件命名正确性
- [ ] compare.html 可视化
### 路径测试
- [ ] Standalone输出到 `.scratchpad`
- [ ] Session输出到 `WFS-{id}`
- [ ] latest symlink正确
- [ ] 跨命令路径传递
### 集成测试
- [ ] auto → extract → consolidate → generate → update
- [ ] 模板正确加载
- [ ] 设计token引用正确
---
## 📚 相关文档
- **workflow-architecture.md**: Workflow系统架构标准
- **_run-manager.md**: Run-based文件管理文档如果需要
- **~/.claude/workflows/_template-compare-matrix.html**: 可视化模板
---
## 🔮 未来增强
### 计划中
- [ ] 自定义布局策略(覆盖默认 Classic/Modern/Minimal
- [ ] compare.html 运行历史对比
- [ ] Scratchpad自动清理策略
- [ ] Session升级工作流scratchpad → WFS
### 待讨论
- [ ] 非矩形矩阵支持2×3
- [ ] 恢复 creative 模式(可选)
- [ ] 更多布局变种(>5
---
## 📝 总结
**v4.1.0 核心价值**:
1. **极简哲学**: 移除模式选择,矩阵为唯一模式
2. **清晰参数**: `--style-variants``--layout-variants` 语义明确
3. **架构规范**: 严格遵循 workflow-architecture.md 标准
4. **集中管理**: 所有输出在 `.workflow/`
5. **可视化增强**: 高级交互式矩阵界面
**升级理由**:
- ✅ 系统化设计探索(风格×布局矩阵)
- ✅ 简化工作流、减少参数困惑
- ✅ 符合workflow架构标准
- ✅ 避免项目根目录污染
---
**发布者**: Claude Code
**版本**: v4.1.0
**类型**: Major Refactoring + Path Corrections
**日期**: 2025-10-09

View File

@@ -1,14 +1,14 @@
--- ---
name: auto name: auto
description: Fully autonomous UI design workflow with style extraction, consolidation, prototype generation, and design system integration description: Fully autonomous UI design workflow with style extraction, consolidation, prototype generation (3×3 matrix), and design system integration
usage: /workflow:ui-design:auto [--prompt "<desc>"] [--images "<glob>"] [--pages "<list>"] [--session <id>] [--variants <count>] [--creative-variants <count>] [--batch-plan] usage: /workflow:ui-design:auto [--prompt "<desc>"] [--images "<glob>"] [--pages "<list>"] [--session <id>] [--style-variants <count>] [--layout-variants <count>] [--batch-plan]
argument-hint: "[--prompt \"Modern SaaS\"] [--images \"refs/*.png\"] [--pages \"dashboard,auth\"] [--session WFS-xxx] [--variants 3] [--creative-variants 3]" argument-hint: "[--prompt \"Modern SaaS with 3 styles\"] [--images \"refs/*.png\"] [--pages \"dashboard,auth\"] [--session WFS-xxx] [--style-variants 3] [--layout-variants 3]"
examples: examples:
- /workflow:ui-design:auto --prompt "Modern blog with home, article and author pages, dark theme" - /workflow:ui-design:auto --prompt "Generate 3 style variants for modern blog: home, article, author"
- /workflow:ui-design:auto --prompt "SaaS dashboard and settings" --variants 3 --creative-variants 3 - /workflow:ui-design:auto --prompt "SaaS dashboard and settings with 2 layout options"
- /workflow:ui-design:auto --images "refs/*.png" --prompt "E-commerce site: home, product, cart" - /workflow:ui-design:auto --images "refs/*.png" --prompt "E-commerce: home, product, cart" --style-variants 3 --layout-variants 3
- /workflow:ui-design:auto --session WFS-auth --images "refs/*.png" --variants 2 - /workflow:ui-design:auto --session WFS-auth --images "refs/*.png"
allowed-tools: SlashCommand(*), TodoWrite(*), Read(*), Bash(*), Glob(*), Task(conceptual-planning-agent) allowed-tools: SlashCommand(*), TodoWrite(*), Read(*), Bash(*), Glob(*), Write(*), Task(conceptual-planning-agent)
--- ---
# UI Design Auto Workflow Command # UI Design Auto Workflow Command
@@ -50,34 +50,114 @@ This workflow runs **fully autonomously** from start to finish:
- `--pages "<page_list>"`: Pages to generate (if omitted, inferred from prompt/session) - `--pages "<page_list>"`: Pages to generate (if omitted, inferred from prompt/session)
- `--session <session_id>`: Workflow session ID (if omitted, runs in standalone mode) - `--session <session_id>`: Workflow session ID (if omitted, runs in standalone mode)
- `--images "<glob_pattern>"`: Reference image paths (default: `design-refs/*`) - `--images "<glob_pattern>"`: Reference image paths (default: `design-refs/*`)
- `--prompt "<description>"`: Text description of design style and pages - `--prompt "<description>"`: Text description of design style and pages (supports intelligent parsing)
- `--variants <count>`: Number of style variants (Phase 1) or UI variants (Phase 3, standard mode) to generate (default: 1, range: 1-5) - `--style-variants <count>`: Number of style variants to generate (default: inferred from prompt or 3, range: 1-5)
- `--creative-variants <count>`: Number of **parallel agents** to launch for creative UI generation (Phase 3 only). This enables Creative Mode for layout exploration - `--layout-variants <count>`: Number of layout variants per style (default: inferred from prompt or 3, range: 1-5)
- `--batch-plan`: Auto-generate implementation tasks after design-update (integrated mode only) - `--batch-plan`: Auto-generate implementation tasks after design-update (integrated mode only)
**Input Source Rules**: **Input Source Rules**:
- Must provide at least one of: `--images` or `--prompt` - Must provide at least one of: `--images` or `--prompt`
- Both can be combined for guided style analysis - Both can be combined for guided style analysis
**Intelligent Prompt Parsing**:
The workflow extracts variant counts from natural language:
- "Generate **3 style variants**" → `--style-variants 3`
- "**2 layout options**" → `--layout-variants 2`
- "Create **4 styles** with **2 layouts each**" → `--style-variants 4 --layout-variants 2`
- Explicit flags override prompt inference
## Execution Modes ## Execution Modes
### Standard Mode (Default) ### Matrix Mode (Default and Only)
- Executes all phases sequentially - Generates `style_variants × layout_variants × pages` prototypes in 3×3 matrix pattern
- **Phase 1 (Style Extraction)**: Generates multiple style options using the `--variants` parameter in a single execution - **Phase 1 (Style Extraction)**: Generates `style_variants` style options
- **Phase 3 (UI Generation)**: Generates multiple UI prototypes using the `--variants` parameter in a single execution - **Phase 2 (Style Consolidation)**: Creates `style_variants` independent design systems
- **Phase 3 (Matrix Generation)**: Generates `style_variants × layout_variants` prototypes per page
### Creative Mode (with `--creative-variants`) - This is the only supported mode - focused on systematic design exploration
- Triggered by the `--creative-variants` parameter for **Phase 3 (UI Generation) only**
- Launches multiple, parallel `Task(conceptual-planning-agent)` instances to explore diverse UI layouts
- Each agent generates a single prototype for a single page, resulting in `N pages * M creative-variants` total prototypes
- This mode is ideal for initial UI exploration where a wide range of layout ideas is desired
### Integrated vs. Standalone Mode ### Integrated vs. Standalone Mode
- `--session` flag determines if the workflow is integrated with a larger session or runs standalone - `--session` flag determines if the workflow is integrated with a larger session or runs standalone
## 5-Phase Execution ## 6-Phase Execution
### Phase 0: Page Inference ### Phase 0a: Intelligent Prompt Parsing
```bash
# Extract variant counts from prompt if not explicitly provided
IF --prompt provided AND (NOT --style-variants OR NOT --layout-variants):
prompt_text = {--prompt value}
# Parse style variants: "3 style variants", "generate 4 styles", etc.
style_match = regex_search(prompt_text, r"(\d+)\s*(style\s*variants?|styles?)")
IF style_match AND NOT --style-variants:
style_variants = int(style_match.group(1))
ELSE:
style_variants = --style-variants OR 3 # Default to 3
# Parse layout variants: "2 layout options", "3 layouts each", etc.
layout_match = regex_search(prompt_text, r"(\d+)\s*(layout\s*(variants?|options?)|layouts?)")
IF layout_match AND NOT --layout-variants:
layout_variants = int(layout_match.group(1))
ELSE:
layout_variants = --layout-variants OR 3 # Default to 3
ELSE:
style_variants = --style-variants OR 3
layout_variants = --layout-variants OR 3
VALIDATE: 1 <= style_variants <= 5
VALIDATE: 1 <= layout_variants <= 5
STORE: style_variants, layout_variants # For Phase 1 and Phase 3
```
### Phase 0b: Run Initialization & Directory Setup
```bash
# Generate run ID with timestamp
run_id = "run-$(date +%Y%m%d-%H%M%S)"
# Determine base path
IF --session:
session_id = {provided_session}
base_path = ".workflow/WFS-{session_id}/runs/${run_id}"
ELSE:
# Standalone mode: use scratchpad
session_id = "design-session-$(date +%Y%m%d-%H%M%S)"
base_path = ".workflow/.scratchpad/${session_id}/runs/${run_id}"
# Create run directory structure
Bash(mkdir -p "${base_path}/.design/style-extraction")
Bash(mkdir -p "${base_path}/.design/style-consolidation")
Bash(mkdir -p "${base_path}/.design/prototypes")
# Initialize run metadata
Write({base_path}/.run-metadata.json):
{
"run_id": "${run_id}",
"session_id": "${session_id}",
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"workflow": "ui-design:auto",
"parameters": {
"style_variants": ${style_variants},
"layout_variants": ${layout_variants},
"pages": "${inferred_page_list}",
"prompt": "${prompt_text}",
"images": "${images_pattern}"
},
"status": "in_progress"
}
# Update "latest" symlink
IF --session:
Bash(rm -f ".workflow/WFS-{session_id}/latest")
Bash(ln -s "runs/${run_id}" ".workflow/WFS-{session_id}/latest")
ELSE:
# Standalone mode: create symlink in scratchpad session dir
Bash(rm -f ".workflow/.scratchpad/${session_id}/latest")
Bash(ln -s "runs/${run_id}" ".workflow/.scratchpad/${session_id}/latest")
STORE: run_id, base_path # Use throughout workflow
```
### Phase 0c: Page Inference
```bash ```bash
# Infer page list if not explicitly provided # Infer page list if not explicitly provided
IF --pages provided: IF --pages provided:
@@ -99,52 +179,57 @@ STORE: inferred_page_list = page_list # For Phase 3
```bash ```bash
images_flag = --images present ? "--images \"{image_glob}\"" : "" images_flag = --images present ? "--images \"{image_glob}\"" : ""
prompt_flag = --prompt present ? "--prompt \"{prompt_text}\"" : "" prompt_flag = --prompt present ? "--prompt \"{prompt_text}\"" : ""
session_flag = --session present ? "--session {session_id}" : ""
# Phase 1 always runs sequentially, using --variants to generate multiple style options # Use run-scoped base path
# --creative-variants does not apply to this phase run_base_flag = "--base-path \"{base_path}/.design\""
variants_flag = --variants present ? "--variants {variants_count}" : "--variants 1"
command = "/workflow:ui-design:extract {session_flag} {images_flag} {prompt_flag} {variants_flag}" # Use style_variants from Phase 0a
command = "/workflow:ui-design:extract {run_base_flag} {images_flag} {prompt_flag} --variants {style_variants}"
SlashCommand(command=command) SlashCommand(command=command)
``` ```
**Auto-Continue**: On completion, proceeds to Phase 2 **Auto-Continue**: On completion, proceeds to Phase 2
--- ---
### Phase 2: Style Consolidation (Auto-Triggered) ### Phase 2: Style Consolidation with Separation (Auto-Triggered)
**Action**: Consolidates all style variants generated in Phase 1 **Action**: Consolidates each style variant into separate design systems for matrix generation
**Command Construction**: **Command Construction**:
```bash ```bash
session_flag = --session present ? "--session {session_id}" : "" # Use run-scoped base path and keep styles separate
# The --variants flag will list ALL variants from Phase 1 (auto-select all) run_base_flag = "--base-path \"{base_path}/.design\""
variants_list = get_all_variant_ids_from_phase_1_output()
command = "/workflow:ui-design:consolidate {session_flag} --variants \"{variants_list}\"" # Use count-based parameter (automatically uses all style_variants)
command = "/workflow:ui-design:consolidate {run_base_flag} --variants {style_variants} --keep-separate"
``` ```
**Command**: `SlashCommand(command=command)` **Command**: `SlashCommand(command=command)`
**Note**: In auto mode, ALL style variants are consolidated automatically without user selection **Result**: Generates `style_variants` independent design systems:
- `.design/style-consolidation/style-1/design-tokens.json`
- `.design/style-consolidation/style-2/design-tokens.json`
- `.design/style-consolidation/style-3/design-tokens.json`
**Auto-Continue**: On completion, proceeds to Phase 3 **Auto-Continue**: On completion, proceeds to Phase 3
--- ---
### Phase 3: UI Generation (Auto-Triggered) ### Phase 3: Matrix UI Generation (Auto-Triggered)
**Action**: Generates UI prototypes based on the consolidated design system **Action**: Generates `style_variants × layout_variants × pages` prototypes using matrix mode
**Command Construction**: **Command Construction**:
```bash ```bash
session_flag = --session present ? "--session {session_id}" : "" run_base_flag = "--base-path \"{base_path}/.design\""
pages_flag = "--pages \"{inferred_page_list}\" " pages_flag = "--pages \"{inferred_page_list}\""
IF --creative-variants provided: # Matrix mode is default in generate.md, no mode flag needed
# Creative Mode: Launch N agents × M pages in parallel for diverse layouts command = "/workflow:ui-design:generate {run_base_flag} {pages_flag} --style-variants {style_variants} --layout-variants {layout_variants}"
command = "/workflow:ui-design:generate {session_flag} {pages_flag}--creative-variants {creative_variants_count}" SlashCommand(command=command)
ELSE:
# Standard Mode: Single execution generating N variants for all pages
variants_flag = --variants present ? "--variants {variants_count}" : "--variants 1"
command = "/workflow:ui-design:generate {session_flag} {pages_flag}{variants_flag}"
``` ```
**Command**: `SlashCommand(command=command)`
**Result**: Generates `style_variants × layout_variants × pages` prototypes:
- File naming: `{page}-style-{s}-layout-{l}.html`
- Total prototypes: `style_variants * layout_variants * len(inferred_page_list)`
- Matrix visualization: `compare.html` with interactive 3×3 grid
**Auto-Continue**: On completion, proceeds to Phase 4 **Auto-Continue**: On completion, proceeds to Phase 4
--- ---
@@ -221,37 +306,41 @@ The workflow acts as the bridge between brainstorming (`synthesis-specification.
## Example Execution Flows ## Example Execution Flows
### Example 1: Text Prompt Only (Standalone) ### Example 1: Default 3×3 Matrix (Prompt Inference)
```bash ```bash
/workflow:ui-design:auto --prompt "Modern minimalist blog with home, article, and author pages" /workflow:ui-design:auto --prompt "Modern minimalist blog with home, article, and author pages"
# Inferred: 3 style variants, 3 layout variants (default)
# Executes: # Executes:
# 1. /workflow:ui-design:extract --prompt "..." --variants 1 # 1. /workflow:ui-design:extract --base-path ".../run-xxx/.design" --prompt "..." --variants 3
# 2. /workflow:ui-design:consolidate --variants "variant-1" # 2. /workflow:ui-design:consolidate --base-path ".../run-xxx/.design" --variants 3 --keep-separate
# 3. /workflow:ui-design:generate --pages "home,article,author" --variants 1 # 3. /workflow:ui-design:generate --base-path ".../run-xxx/.design" --pages "home,article,author" --style-variants 3 --layout-variants 3
# 4. /workflow:ui-design:update # 4. /workflow:ui-design:update
# Total: 27 prototypes (3 styles × 3 layouts × 3 pages)
``` ```
### Example 2: Images + Prompt + Session (Integrated) ### Example 2: Custom 2×2 Matrix with Explicit Parameters
```bash ```bash
/workflow:ui-design:auto --session WFS-ecommerce --images "refs/*.png" --prompt "E-commerce with minimalist aesthetic" --variants 3 /workflow:ui-design:auto --session WFS-ecommerce --images "refs/*.png" --prompt "E-commerce" --style-variants 2 --layout-variants 2
# Executes: # Executes:
# 1. /workflow:ui-design:extract --session WFS-ecommerce --images "refs/*.png" --prompt "..." --variants 3 # 1. /workflow:ui-design:extract --base-path ".workflow/WFS-ecommerce/runs/run-xxx/.design" --images "refs/*.png" --variants 2
# 2. /workflow:ui-design:consolidate --session WFS-ecommerce --variants "variant-1,variant-2,variant-3" # 2. /workflow:ui-design:consolidate --base-path "..." --variants 2 --keep-separate
# 3. /workflow:ui-design:generate --session WFS-ecommerce --pages "{inferred_from_synthesis}" --variants 1 # 3. /workflow:ui-design:generate --base-path "..." --pages "{inferred}" --style-variants 2 --layout-variants 2
# 4. /workflow:ui-design:update --session WFS-ecommerce # 4. /workflow:ui-design:update --session WFS-ecommerce
# Total: 2×2×N prototypes
``` ```
### Example 3: Creative Mode with Batch Planning ### Example 3: Intelligent Parsing with Batch Planning
```bash ```bash
/workflow:ui-design:auto --session WFS-saas --prompt "SaaS dashboard and settings" --variants 2 --creative-variants 4 --batch-plan /workflow:ui-design:auto --session WFS-saas --prompt "Create 4 styles with 2 layouts for SaaS dashboard and settings" --batch-plan
# Parsed: --style-variants 4, --layout-variants 2
# Executes: # Executes:
# 1. /workflow:ui-design:extract --session WFS-saas --prompt "..." --variants 2 # 1. /workflow:ui-design:extract --variants 4
# 2. /workflow:ui-design:consolidate --session WFS-saas --variants "variant-1,variant-2" # 2. /workflow:ui-design:consolidate --variants 4 --keep-separate
# 3. /workflow:ui-design:generate --session WFS-saas --pages "dashboard,settings" --creative-variants 4 # 3. /workflow:ui-design:generate --pages "dashboard,settings" --style-variants 4 --layout-variants 2
# (launches 8 parallel agents: 2 pages × 4 creative variants) # (generates 16 prototypes: 4 styles × 2 layouts × 2 pages)
# 4. /workflow:ui-design:update --session WFS-saas # 4. /workflow:ui-design:update --session WFS-saas
# 5. /workflow:plan --agent "Implement dashboard page..." # 5. /workflow:plan --agent "Implement dashboard page..."
# /workflow:plan --agent "Implement settings page..." # /workflow:plan --agent "Implement settings page..."
@@ -262,19 +351,26 @@ The workflow acts as the bridge between brainstorming (`synthesis-specification.
``` ```
✅ UI Design Auto Workflow Complete! ✅ UI Design Auto Workflow Complete!
Run ID: {run_id}
Session: {session_id or "standalone"} Session: {session_id or "standalone"}
Mode: {standard|creative} Matrix: {style_variants}×{layout_variants} ({total_prototypes} total prototypes)
Input: {images and/or prompt summary} Input: {images and/or prompt summary}
Phase 1 - Style Extraction: {variants_count} style variants Phase 1 - Style Extraction: {style_variants} style variants
Phase 2 - Style Consolidation: Unified design system Phase 2 - Style Consolidation: {style_variants} independent design systems
Phase 3 - UI Generation: {total_prototypes} prototypes ({mode} mode) Phase 3 - Matrix Generation: {style_variants}×{layout_variants}×{pages_count} = {total_prototypes} prototypes
Phase 4 - Design Update: Brainstorming artifacts updated Phase 4 - Design Update: Brainstorming artifacts updated
{IF batch-plan: Phase 5 - Task Generation: {task_count} implementation tasks created} {IF batch-plan: Phase 5 - Task Generation: {task_count} implementation tasks created}
📂 Design System: {base_path}/.design/ 📂 Run Output: {base_path}/
📂 Prototypes: {base_path}/.design/prototypes/ ├── .design/style-consolidation/ ({style_variants} design systems)
🌐 Preview: Open {base_path}/.design/prototypes/index.html ├── .design/prototypes/ ({total_prototypes} HTML/CSS files)
└── .run-metadata.json (run configuration)
🌐 Interactive Preview: {base_path}/.design/prototypes/compare.html
- 3×3 matrix view with synchronized scrolling
- Zoom controls and fullscreen mode
- Selection export for implementation
{IF batch-plan: {IF batch-plan:
📋 Implementation Tasks: .workflow/WFS-{session}/.task/ 📋 Implementation Tasks: .workflow/WFS-{session}/.task/
@@ -282,8 +378,8 @@ Next: /workflow:execute to begin implementation
} }
{ELSE: {ELSE:
Next Steps: Next Steps:
1. Preview prototypes in browser 1. Open compare.html to preview all variants
2. Select preferred designs 2. Select preferred style×layout combinations
3. Run /workflow:plan to create implementation tasks 3. Run /workflow:plan to create implementation tasks
} }
``` ```

View File

@@ -1,12 +1,13 @@
--- ---
name: consolidate name: consolidate
description: Consolidate style variants into unified design system using Claude's synthesis description: Consolidate style variants into unified or separate design systems
usage: /workflow:ui-design:consolidate --session <session_id> [--variants "<ids>"] usage: /workflow:ui-design:consolidate [--base-path <path>] [--session <id>] [--variants <count>] [--keep-separate]
argument-hint: "--session WFS-session-id [--variants \"variant-1,variant-3\"]" argument-hint: "[--base-path \".workflow/WFS-xxx/runs/run-xxx/.design\"] [--variants 3] [--keep-separate]"
examples: examples:
- /workflow:ui-design:consolidate --session WFS-auth --variants "variant-1,variant-2,variant-3" - /workflow:ui-design:consolidate --base-path ".workflow/WFS-auth/latest/.design" --variants 3 --keep-separate
- /workflow:ui-design:consolidate --session WFS-dashboard --variants "variant-1,variant-3" - /workflow:ui-design:consolidate --session WFS-auth --variants 2
allowed-tools: TodoWrite(*), Read(*), Write(*) - /workflow:ui-design:consolidate --base-path "./design-session-xxx/.design"
allowed-tools: TodoWrite(*), Read(*), Write(*), Bash(*)
--- ---
# Style Consolidation Command # Style Consolidation Command
@@ -22,39 +23,46 @@ Consolidate user-selected style variants into a unified, production-ready design
## Execution Protocol ## Execution Protocol
### Phase 1: Session & Variant Loading ### Phase 1: Path Resolution & Variant Loading
```bash ```bash
# Validate session and load style cards # Determine base path
IF --session: IF --base-path provided:
base_path = {provided_base_path} # e.g., ".workflow/WFS-xxx/runs/run-xxx/.design"
ELSE IF --session provided:
session_id = {provided_session} session_id = {provided_session}
base_path = ".workflow/WFS-{session_id}/" base_path = ".workflow/WFS-{session_id}/latest/.design" # Use latest run
ELSE: ELSE:
ERROR: "Must provide --session parameter" # Standalone mode: search for most recent design-session in scratchpad
base_path = find_latest_design_session(".workflow/.scratchpad/")
# Verify extraction output exists # Verify extraction output exists
VERIFY: {base_path}/.design/style-extraction/style-cards.json exists style_cards_path = "{base_path}/style-extraction/style-cards.json"
VERIFY: exists(style_cards_path)
# Load style cards # Load style cards
style_cards = Read({base_path}/.design/style-extraction/style-cards.json) style_cards = Read(style_cards_path)
total_variants = len(style_cards.style_cards)
``` ```
### Phase 2: Variant Selection ### Phase 2: Variant Selection (Count-Based)
```bash ```bash
# Parse variant selection # Determine how many variants to consolidate
IF --variants provided: IF --variants provided:
variant_ids = parse_csv({--variants value}) variants_count = {provided_count}
VALIDATE: All variant_ids exist in style_cards.style_cards[] VALIDATE: 1 <= variants_count <= total_variants
ELSE: ELSE:
# Auto-select all variants when called from /workflow:ui-design:auto # Default to all variants
variant_ids = extract_all_ids(style_cards.style_cards) variants_count = total_variants
# Extract selected variants
selected_variants = []
FOR each id IN variant_ids:
variant = find_variant_by_id(style_cards, id)
selected_variants.push(variant)
# Select first N variants
selected_variants = style_cards.style_cards[0:variants_count]
VERIFY: selected_variants.length > 0 VERIFY: selected_variants.length > 0
# Determine consolidation mode
IF --keep-separate provided:
consolidation_mode = "separate" # Generate N independent design systems
ELSE:
consolidation_mode = "unified" # Merge into 1 design system
``` ```
### Phase 3: Load Design Context (Optional) ### Phase 3: Load Design Context (Optional)
@@ -67,8 +75,12 @@ ELSE IF exists({base_path}/.brainstorming/ui-designer/analysis.md):
design_context = Read({base_path}/.brainstorming/ui-designer/analysis.md) design_context = Read({base_path}/.brainstorming/ui-designer/analysis.md)
``` ```
### Phase 4: Unified Design System Synthesis (Claude) ### Phase 4: Design System Synthesis (Claude)
This is a single-pass synthesis that replaces all external tool calls.
**Route based on consolidation_mode**:
#### Mode A: Unified Consolidation (Default)
Merges all style variants into a single, cohesive design system.
**Synthesis Prompt Template**: **Synthesis Prompt Template**:
``` ```

View File

@@ -44,7 +44,7 @@ IF --session:
ELSE: ELSE:
session_mode = "standalone" session_mode = "standalone"
session_id = "design-session-" + timestamp() session_id = "design-session-" + timestamp()
base_path = "./{session_id}/" base_path = ".workflow/.scratchpad/{session_id}/"
# Set variant count # Set variant count
variants_count = --variants provided ? {count} : 1 variants_count = --variants provided ? {count} : 1

View File

@@ -1,116 +1,123 @@
--- ---
name: generate name: generate
description: Generate UI prototypes using consolidated design tokens description: Generate UI prototypes in matrix mode (style × layout combinations)
usage: /workflow:ui-design:generate [--pages "<list>"] [--session <id>] [--variants <count>] [--creative-variants <count>] usage: /workflow:ui-design:generate [--pages "<list>"] [--base-path <path>] [--session <id>] [--style-variants <count>] [--layout-variants <count>]
argument-hint: "[--pages \"dashboard,auth\"] [--session WFS-xxx] [--variants 3] [--creative-variants 3]" argument-hint: "[--pages \"dashboard,auth\"] [--base-path \".workflow/WFS-xxx/runs/run-xxx/.design\"] [--style-variants 3] [--layout-variants 3]"
examples: examples:
- /workflow:ui-design:generate --pages "home,pricing" --variants 2 - /workflow:ui-design:generate --base-path ".workflow/WFS-auth/runs/run-xxx/.design" --pages "dashboard,settings" --style-variants 3 --layout-variants 3
- /workflow:ui-design:generate --session WFS-auth --pages "dashboard" --creative-variants 4 - /workflow:ui-design:generate --session WFS-auth --pages "home,pricing" --style-variants 2 --layout-variants 2
- /workflow:ui-design:generate --session WFS-auth --variants 3 - /workflow:ui-design:generate --base-path "./design-session-xxx/.design" --style-variants 3 --layout-variants 3
allowed-tools: TodoWrite(*), Read(*), Write(*), Task(conceptual-planning-agent) allowed-tools: TodoWrite(*), Read(*), Write(*), Task(conceptual-planning-agent), Bash(*)
--- ---
# UI Generation Command # UI Generation Command (Matrix Mode)
## Overview ## Overview
Generate production-ready UI prototypes (HTML/CSS) strictly adhering to consolidated design tokens and synthesis specification requirements. Generate production-ready UI prototypes (HTML/CSS) in `style × layout` matrix mode, strictly adhering to consolidated design tokens from separate style design systems.
## Core Philosophy ## Core Philosophy
- **Dual-Mode Execution**: Standard (consistent) or Creative (exploratory) - **Matrix-Only**: Single mode generating `style_variants × layout_variants × pages` prototypes
- **Agent-Driven**: Uses `Task(conceptual-planning-agent)` exclusively - **Agent-Driven**: Uses `Task(conceptual-planning-agent)` for parallel generation
- **Token-Driven**: All styles reference design-tokens.json; no hardcoded values - **Token-Driven**: All styles reference per-style design-tokens.json; no hardcoded values
- **Production-Ready**: Semantic HTML5, ARIA attributes, responsive design - **Production-Ready**: Semantic HTML5, ARIA attributes, responsive design
## Execution Protocol ## Execution Protocol
### Phase 1: Mode Detection & Context Loading ### Phase 1: Path Resolution & Context Loading
```bash ```bash
# Detect execution mode # Determine base path
IF --creative-variants provided: IF --base-path provided:
mode = "creative" # Parallel agents for diverse layouts base_path = {provided_base_path} # e.g., ".workflow/WFS-xxx/runs/run-xxx/.design"
creative_count = {--creative-variants value} ELSE IF --session provided:
VALIDATE: 1 <= creative_count <= 10
ELSE:
mode = "standard" # Single agent, multiple variants
variants_count = --variants provided ? {count} : 1
VALIDATE: 1 <= variants_count <= 5
# Detect session mode
IF --session:
session_mode = "integrated"
session_id = {provided_session} session_id = {provided_session}
base_path = ".workflow/WFS-{session_id}/" base_path = ".workflow/WFS-{session_id}/latest/.design" # Use latest run
ELSE: ELSE:
session_mode = "standalone" # Standalone mode: search for most recent design-session in scratchpad
# Infer session_id from existing design-session-* directory base_path = find_latest_design_session(".workflow/.scratchpad/")
base_path = "./{detected_design_session}/"
# Determine style and layout variant counts
style_variants = --style-variants OR 3 # Default to 3
layout_variants = --layout-variants OR 3 # Default to 3
VALIDATE: 1 <= style_variants <= 5
VALIDATE: 1 <= layout_variants <= 5
# Infer page list if not provided # Infer page list if not provided
IF --pages provided: IF --pages provided:
page_list = {explicit_pages} page_list = parse_csv({--pages value})
ELSE IF session_mode == "integrated": ELSE IF --session:
# Read synthesis-specification.md to extract page requirements # Read synthesis-specification.md to extract page requirements
synthesis_spec = Read({base_path}/.brainstorming/synthesis-specification.md) synthesis_spec = Read(.workflow/WFS-{session}/.brainstorming/synthesis-specification.md)
page_list = extract_pages_from_synthesis(synthesis_spec) page_list = extract_pages_from_synthesis(synthesis_spec)
ELSE: ELSE:
# Infer from existing prototypes or default # Infer from existing prototypes or default
page_list = detect_from_prototypes({base_path}/.design/prototypes/) OR ["home"] page_list = detect_from_prototypes({base_path}/prototypes/) OR ["home"]
VALIDATE: page_list not empty VALIDATE: page_list not empty
# Load design system # Verify design systems exist for all styles
VERIFY: {base_path}/.design/style-consolidation/design-tokens.json exists FOR style_id IN range(1, style_variants + 1):
design_tokens = Read({base_path}/.design/style-consolidation/design-tokens.json) VERIFY: {base_path}/style-consolidation/style-{style_id}/design-tokens.json exists
style_guide = Read({base_path}/.design/style-consolidation/style-guide.md) VERIFY: {base_path}/style-consolidation/style-{style_id}/style-guide.md exists
# Load requirements (if integrated mode) # Load requirements (if integrated mode)
IF session_mode == "integrated": IF --session:
synthesis_spec = Read({base_path}/.brainstorming/synthesis-specification.md) synthesis_spec = Read(.workflow/WFS-{session}/.brainstorming/synthesis-specification.md)
``` ```
### Phase 2: UI Generation Execution ### Phase 2: Matrix UI Generation (Parallel)
Execute parallel agents to generate `style_variants × layout_variants × pages` prototypes.
**Route based on mode**:
#### A. Standard Mode (Default)
Execute if `mode == "standard"`. Single agent generates multiple variants with consistent layout strategy.
```bash ```bash
# Create output directory # Create output directory
CREATE: {base_path}/.design/prototypes/ CREATE: {base_path}/prototypes/
# Single agent call generates N variants for all pages # Launch style_variants parallel tasks
Task(conceptual-planning-agent): " FOR style_id IN range(1, style_variants + 1):
[UI_GENERATION] Task(conceptual-planning-agent): "
[UI_GENERATION_MATRIX]
Generate UI prototypes adhering to design tokens Generate {layout_variants} layout variants for style-{style_id}
## Context ## Context
SESSION: {session_id} STYLE_ID: {style_id}
MODE: standard LAYOUT_VARIANTS: {layout_variants}
PAGES: {page_list} PAGES: {page_list}
VARIANTS_PER_PAGE: {variants_count} BASE_PATH: {base_path}
OUTPUT: {base_path}/.design/prototypes/
## Input Files ## Input Files
- Design Tokens: {base_path}/.design/style-consolidation/design-tokens.json - Design Tokens: {base_path}/style-consolidation/style-{style_id}/design-tokens.json
- Style Guide: {base_path}/.design/style-consolidation/style-guide.md - Style Guide: {base_path}/style-consolidation/style-{style_id}/style-guide.md
{IF integrated: - Requirements: {base_path}/.brainstorming/synthesis-specification.md} {IF --session: - Requirements: .workflow/WFS-{session}/.brainstorming/synthesis-specification.md}
## Task ## Task
For each page in [{page_list}], generate {variants_count} variant(s): For each page in [{page_list}], generate {layout_variants} layout variants:
- {page}-variant-{n}.html (semantic HTML5) - {page}-style-{style_id}-layout-{j}.html (semantic HTML5)
- {page}-variant-{n}.css (token-driven, no hardcoded values) - {page}-style-{style_id}-layout-{j}.css (token-driven, no hardcoded values)
- {page}-variant-{n}-notes.md (implementation notes) - {page}-style-{style_id}-layout-{j}-notes.md (implementation notes)
## Layout Strategy ## Layout Diversity Strategy
Use a consistent, modern layout approach across all variants. Variants should differ in: Each layout variant (j=1 to {layout_variants}) should explore different:
- Component arrangement (e.g., sidebar left vs. right)
- Content density (spacious vs. compact)
- Navigation style (top-nav vs. side-nav)
## Token Usage Requirements **Layout 1: Classic Hierarchy**
- STRICT adherence to design-tokens.json - Traditional F-pattern reading flow
- Top navigation with sidebar
- Card-based content sections
**Layout 2: Modern Asymmetric**
- Z-pattern visual flow
- Split-screen hero sections
- Grid-based modular content
**Layout 3: Minimal Focus**
- Centered single-column content
- Floating navigation
- Generous whitespace and breathing room
Adapt these strategies to each page's purpose while maintaining consistency.
## Token Usage Requirements (STRICT)
- Load design tokens from: {base_path}/style-consolidation/style-{style_id}/design-tokens.json
- All colors: var(--color-brand-primary), var(--color-surface-background), etc. - All colors: var(--color-brand-primary), var(--color-surface-background), etc.
- All spacing: var(--spacing-4), var(--spacing-6), etc. - All spacing: var(--spacing-4), var(--spacing-6), etc.
- All typography: var(--font-family-heading), var(--font-size-lg), etc. - All typography: var(--font-family-heading), var(--font-size-lg), etc.
@@ -123,6 +130,7 @@ Task(conceptual-planning-agent): "
- Mobile-first responsive design - Mobile-first responsive design
## CSS Requirements ## CSS Requirements
- Link to design-tokens.css: <link rel=\"stylesheet\" href=\"../../design-tokens.css\">
- Use CSS custom properties from design-tokens.json - Use CSS custom properties from design-tokens.json
- Mobile-first media queries using token breakpoints - Mobile-first media queries using token breakpoints
- No inline styles - No inline styles
@@ -133,155 +141,194 @@ Task(conceptual-planning-agent): "
- Tablet: var(--breakpoint-md) (adapted layout) - Tablet: var(--breakpoint-md) (adapted layout)
- Desktop: var(--breakpoint-lg)+ (full layout) - Desktop: var(--breakpoint-lg)+ (full layout)
## Output Location
{base_path}/prototypes/
## Deliverables ## Deliverables
For each page-variant combination: For each page-style-layout combination:
1. HTML file with token-driven structure 1. HTML file with token-driven structure
2. CSS file with custom property references 2. CSS file with custom property references
3. Notes file with implementation details 3. Notes file with implementation details and layout rationale
Total files: {len(page_list) * variants_count * 3} Total files to generate: {len(page_list) * layout_variants * 3}
"
```
#### B. Creative Mode
Execute if `mode == "creative"`. Parallel agents explore diverse layout strategies.
```bash
# Define diverse layout strategies
layout_strategies = [
"F-Pattern: Traditional reading flow with strong visual hierarchy",
"Asymmetric Grid: Dynamic, modern layout with intentional imbalance",
"Card-Based Modular: Flexible card grid for content-heavy pages",
"Z-Pattern: Zigzag visual flow for conversion-focused layouts",
"Split-Screen: Dramatic 50/50 division for dual-focus content",
"Bento Box: Japanese-inspired grid with varied cell sizes",
"Full-Bleed Hero: Large hero section with scrolling content",
"Sidebar-First: Prominent sidebar navigation with content area"
]
# Launch N agents × M pages in parallel
CREATE: {base_path}/.design/prototypes/
FOR page IN page_list:
FOR i IN range(creative_count):
layout = layout_strategies[i % len(layout_strategies)]
Task(conceptual-planning-agent): "
[UI_GENERATION_CREATIVE]
Generate creative UI prototype: {page} (Variant {i+1})
## Context
PAGE: {page}
LAYOUT_STRATEGY: {layout}
VARIANT_NUMBER: {i+1}
OUTPUT: {base_path}/.design/prototypes/
## Input Files
- Design Tokens: {base_path}/.design/style-consolidation/design-tokens.json
- Style Guide: {base_path}/.design/style-consolidation/style-guide.md
{IF integrated: - Requirements: {base_path}/.brainstorming/synthesis-specification.md}
## Task
Generate a single prototype for {page} using '{layout}' layout:
- {page}-creative-variant-{i+1}.html
- {page}-creative-variant-{i+1}.css
- {page}-creative-variant-{i+1}-notes.md
## Layout Focus
This variant MUST follow '{layout}' layout strategy.
Be bold and exploratory - this is for design exploration.
## Token Usage Requirements (STRICT)
- All colors: var(--color-*) from design-tokens.json
- All spacing: var(--spacing-*) from design-tokens.json
- All typography: var(--font-*) from design-tokens.json
- NO hardcoded values allowed
## HTML/CSS/Accessibility Requirements
- Semantic HTML5 with ARIA attributes
- Mobile-first responsive design
- Token-driven styling only
- Unique layout interpretation of '{layout}' strategy
## Deliverables
1. HTML file embodying '{layout}' layout
2. CSS file with strict token usage
3. Notes explaining layout decisions
" "
# Wait for all {len(page_list) * creative_count} tasks to complete # Wait for all {style_variants} parallel tasks to complete
# Total prototypes: {style_variants * layout_variants * len(page_list)}
``` ```
### Phase 3: Generate Preview Files ### Phase 3: Generate Preview Files
```bash ```bash
# Generate preview utilities # Read matrix visualization template
Write({base_path}/.design/prototypes/index.html) # Master navigation template_content = Read("~/.claude/workflows/_template-compare-matrix.html")
Write({base_path}/.design/prototypes/compare.html) # Side-by-side comparison
Write({base_path}/.design/prototypes/PREVIEW.md) # Setup instructions
Write({base_path}/.design/prototypes/design-tokens.css) # CSS custom properties
```
**index.html Template**: # Prepare template variables
```html pages_json = JSON.stringify(page_list)
run_id = extract_run_id_from_base_path({base_path})
# Inject variables into template
injected_content = template_content
.replace("{{run_id}}", run_id)
.replace("{{style_variants}}", style_variants)
.replace("{{layout_variants}}", layout_variants)
.replace("{{pages_json}}", pages_json)
# Write interactive matrix comparison
Write({base_path}/prototypes/compare.html, injected_content)
# Generate design-tokens.css (unified CSS custom properties for all styles)
Write({base_path}/prototypes/design-tokens.css):
/* Auto-generated from all style design systems */
/* Note: Each prototype links to its specific style's tokens */
:root {
/* Fallback tokens - each HTML file should link to its style-specific tokens */
/* See style-consolidation/style-{n}/design-tokens.json for actual values */
}
# Generate simple index.html for quick navigation
Write({base_path}/prototypes/index.html):
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UI Prototypes Preview - {session_id}</title> <title>UI Prototypes - Matrix View</title>
<style> <style>
body { font-family: system-ui; max-width: 1200px; margin: 2rem auto; padding: 0 1rem; } body {
font-family: system-ui, sans-serif;
max-width: 800px;
margin: 2rem auto;
padding: 0 1rem;
}
h1 { color: #2563eb; } h1 { color: #2563eb; }
.prototype-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1.5rem; margin-top: 2rem; } .info {
.prototype-card { border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 1rem; transition: box-shadow 0.2s; } background: #f3f4f6;
.prototype-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.1); } padding: 1rem;
.prototype-card h3 { margin: 0 0 0.5rem; color: #1f2937; } border-radius: 0.5rem;
.prototype-card .meta { font-size: 0.875rem; color: #6b7280; margin-bottom: 1rem; } margin: 1rem 0;
.prototype-card a { display: inline-block; margin-right: 0.5rem; color: #2563eb; text-decoration: none; } }
.prototype-card a:hover { text-decoration: underline; } .cta {
display: inline-block;
background: #2563eb;
color: white;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
text-decoration: none;
font-weight: 600;
margin-top: 1rem;
}
.cta:hover { background: #1d4ed8; }
.stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin: 1.5rem 0;
}
.stat {
background: white;
border: 1px solid #e5e7eb;
padding: 1rem;
border-radius: 0.5rem;
text-align: center;
}
.stat-value {
font-size: 2rem;
font-weight: bold;
color: #2563eb;
}
.stat-label {
color: #6b7280;
font-size: 0.875rem;
margin-top: 0.25rem;
}
</style> </style>
</head> </head>
<body> <body>
<h1>🎨 UI Prototypes Preview</h1> <h1>🎨 UI Prototype Matrix</h1>
<p><strong>Session:</strong> {session_id} | <strong>Mode:</strong> {mode}</p>
<p><a href="compare.html">📊 Compare Variants</a> | <a href="PREVIEW.md">📖 Instructions</a></p>
<div class="prototype-grid"> <div class="info">
{FOR each generated file: <p><strong>Matrix Configuration:</strong> {style_variants} styles × {layout_variants} layouts × {len(page_list)} pages</p>
<div class="prototype-card"> <p><strong>Total Prototypes:</strong> {style_variants * layout_variants * len(page_list)}</p>
<h3>{page} - Variant {n}</h3>
<div class="meta">{mode} mode</div>
<a href="{filename}.html" target="_blank">View →</a>
<a href="{filename}-notes.md">Notes</a>
</div> </div>
<div class="stats">
<div class="stat">
<div class="stat-value">{style_variants}</div>
<div class="stat-label">Style Variants</div>
</div>
<div class="stat">
<div class="stat-value">{layout_variants}</div>
<div class="stat-label">Layout Options</div>
</div>
<div class="stat">
<div class="stat-value">{len(page_list)}</div>
<div class="stat-label">Pages</div>
</div>
</div>
<a href="compare.html" class="cta">🔍 Open Interactive Matrix Comparison →</a>
<h2>Features</h2>
<ul>
<li>3×3 matrix grid view with synchronized scrolling</li>
<li>Zoom controls (25%, 50%, 75%, 100%)</li>
<li>Fullscreen mode for individual prototypes</li>
<li>Selection system with export functionality</li>
<li>Page switcher for multi-page comparison</li>
</ul>
<h2>Generated Pages</h2>
<ul>
{FOR page IN page_list:
<li><strong>{page}</strong>: {style_variants × layout_variants} variants</li>
} }
</div> </ul>
</body> </body>
</html> </html>
```
**design-tokens.css Template**: # Generate PREVIEW.md with instructions
```css Write({base_path}/prototypes/PREVIEW.md):
/* Auto-generated from design-tokens.json */ # UI Prototype Preview Guide
:root {
/* Colors - Brand */
--color-brand-primary: {value};
--color-brand-secondary: {value};
--color-brand-accent: {value};
/* Colors - Surface */ ## Quick Start
--color-surface-background: {value}; 1. Open `compare.html` in a modern browser
--color-surface-elevated: {value}; 2. Use the page selector to switch between pages
--color-surface-overlay: {value}; 3. Interact with prototypes in the 3×3 matrix
/* Typography */ ## Matrix Configuration
--font-family-heading: {value}; - **Style Variants:** {style_variants}
--font-family-body: {value}; - **Layout Options:** {layout_variants}
--font-size-base: {value}; - **Pages:** {page_list}
/* ... all tokens as CSS custom properties ... */ - **Total Prototypes:** {style_variants * layout_variants * len(page_list)}
}
## File Naming Convention
`{page}-style-{s}-layout-{l}.html`
Example: `dashboard-style-1-layout-2.html`
- Page: dashboard
- Style: Design system 1
- Layout: Layout variant 2
## Interactive Features
- **Synchronized Scroll:** All prototypes scroll together
- **Zoom Controls:** Adjust viewport scale (25%-100%)
- **Fullscreen:** Click any prototype for detailed view
- **Selection:** Mark favorites for implementation
- **Export:** Save selections as JSON
## Design System References
Each prototype uses tokens from:
`../style-consolidation/style-{s}/design-tokens.json`
Refer to corresponding `style-guide.md` for design philosophy and usage guidelines.
## Next Steps
1. Review all variants in compare.html
2. Select preferred style×layout combinations
3. Export selections for implementation planning
4. Run `/workflow:ui-design:update` to integrate chosen designs
``` ```
### Phase 4: TodoWrite & Completion ### Phase 4: TodoWrite & Completion
@@ -289,33 +336,46 @@ Write({base_path}/.design/prototypes/design-tokens.css) # CSS custom properties
```javascript ```javascript
TodoWrite({ TodoWrite({
todos: [ todos: [
{content: "Detect mode and load design system", status: "completed", activeForm: "Loading design system"}, {content: "Resolve paths and load design systems", status: "completed", activeForm: "Loading design systems"},
{content: "Generate {total_count} UI prototypes", status: "completed", activeForm: "Generating prototypes"}, {content: `Generate ${style_variants}×${layout_variants}×${page_list.length} prototypes`, status: "completed", activeForm: "Generating matrix prototypes"},
{content: "Generate preview files", status: "completed", activeForm: "Generating preview"} {content: "Generate interactive preview files", status: "completed", activeForm: "Generating preview"}
] ]
}); });
``` ```
**Completion Message**: **Completion Message**:
``` ```
✅ UI generation complete for session: {session_id} Matrix UI generation complete!
Mode: {mode} Configuration:
Pages: {page_list} - Style Variants: {style_variants}
{IF standard: Variants per page: {variants_count}} - Layout Options: {layout_variants}
{IF creative: Creative variants per page: {creative_count}} - Pages: {page_list}
- Total Prototypes: {style_variants * layout_variants * len(page_list)}
Generated {total_count} prototypes: Generated Files:
{FOR each file: - {filename}} {FOR style_id IN range(1, style_variants + 1):
{FOR layout_id IN range(1, layout_variants + 1):
{FOR page IN page_list:
- {page}-style-{style_id}-layout-{layout_id}.html
}
}
}
📂 Location: {base_path}/.design/prototypes/ 📂 Location: {base_path}/prototypes/
🌐 Preview: 🌐 Interactive Preview:
1. Quick: Open index.html in browser 1. Matrix View: Open compare.html (recommended)
2. Server: cd prototypes && python -m http.server 8080 2. Quick Index: Open index.html
3. Compare: Open compare.html for side-by-side view 3. Instructions: See PREVIEW.md
Next: /workflow:ui-design:update --session {session_id} Features:
- 3×3 matrix grid with synchronized scrolling
- Zoom controls and fullscreen mode
- Selection export for implementation
- Per-page comparison
Next: /workflow:ui-design:update {--session flag if applicable}
Note: When called from /workflow:ui-design:auto, design-update is triggered automatically. Note: When called from /workflow:ui-design:auto, design-update is triggered automatically.
``` ```
@@ -323,22 +383,22 @@ Note: When called from /workflow:ui-design:auto, design-update is triggered auto
## Output Structure ## Output Structure
``` ```
.workflow/WFS-{session}/.design/prototypes/ {base_path}/prototypes/
├── index.html # Preview index (master navigation) ├── compare.html # Interactive matrix visualization
├── compare.html # Side-by-side comparison ├── index.html # Simple navigation page
├── PREVIEW.md # Preview instructions ├── PREVIEW.md # Preview instructions
├── design-tokens.css # CSS custom properties ├── design-tokens.css # CSS custom properties fallback
├── {page}-variant-{n}.html ├── {page}-style-{s}-layout-{l}.html # Matrix prototype files
├── {page}-variant-{n}.css ├── {page}-style-{s}-layout-{l}.css
├── {page}-variant-{n}-notes.md ├── {page}-style-{s}-layout-{l}-notes.md
└── ... (all generated prototypes) └── ... (all style×layout×page combinations)
``` ```
## Error Handling ## Error Handling
- **No design tokens found**: Run `/workflow:ui-design:consolidate` first - **No design systems found**: Run `/workflow:ui-design:consolidate --keep-separate` first
- **Invalid page names**: Extract from synthesis-specification.md or error - **Invalid page names**: Extract from synthesis-specification.md or error
- **Agent execution errors**: Report details, suggest retry - **Agent execution errors**: Report details, suggest retry
- **Missing requirements**: Continue with design tokens only - **Missing template**: Provide fallback or error with template path
## Quality Checks ## Quality Checks
After generation, ensure: After generation, ensure:
@@ -348,16 +408,19 @@ After generation, ensure:
- [ ] ARIA attributes present - [ ] ARIA attributes present
- [ ] Responsive design implemented - [ ] Responsive design implemented
- [ ] Mobile-first approach - [ ] Mobile-first approach
- [ ] File naming follows `{page}-style-{s}-layout-{l}` convention
- [ ] compare.html loads correctly with all prototypes
## Key Improvements Over Previous Version ## Key Features
1. **Unified Execution Model**: Only `Task(conceptual-planning-agent)` - no CLI tools 1. **Matrix-Only Mode**: Simplified, focused workflow
2. **Dual-Mode Simplicity**: Standard (consistent) or Creative (exploratory) 2. **Parallel Generation**: All style×layout combinations in parallel
3. **Explicit Layout Strategies**: Creative mode uses predefined layout patterns 3. **Interactive Visualization**: Full-featured compare.html from template
4. **Preview Enhancements**: index.html, compare.html, and design-tokens.css 4. **Per-Style Tokens**: Each prototype references its style's design system
5. **Streamlined**: Clear, consistent agent invocation patterns 5. **Systematic Exploration**: Consistent layout strategies across all styles
## Integration Points ## Integration Points
- **Input**: design-tokens.json, style-guide.md from `/workflow:ui-design:consolidate` - **Input**: Per-style design-tokens.json from `/workflow:ui-design:consolidate --keep-separate`
- **Output**: HTML/CSS prototypes for `/workflow:ui-design:update` - **Output**: Matrix HTML/CSS prototypes for `/workflow:ui-design:update`
- **Context**: synthesis-specification.md for page requirements and content guidance - **Template**: `~/.claude/workflows/_template-compare-matrix.html` (global)
- **Context**: synthesis-specification.md for page requirements (optional)

View File

@@ -0,0 +1,692 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UI Design Matrix Comparison - {{run_id}}</title>
<style>
:root {
--color-primary: #2563eb;
--color-bg: #f9fafb;
--color-surface: #ffffff;
--color-border: #e5e7eb;
--color-text: #1f2937;
--color-text-secondary: #6b7280;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: var(--color-bg);
color: var(--color-text);
line-height: 1.6;
}
.container {
max-width: 1600px;
margin: 0 auto;
padding: 2rem;
}
header {
background: var(--color-surface);
padding: 1.5rem 2rem;
border-radius: 0.5rem;
margin-bottom: 2rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
h1 {
color: var(--color-primary);
font-size: 1.875rem;
margin-bottom: 0.5rem;
}
.meta {
color: var(--color-text-secondary);
font-size: 0.875rem;
}
.controls {
background: var(--color-surface);
padding: 1.5rem;
border-radius: 0.5rem;
margin-bottom: 2rem;
display: flex;
gap: 1.5rem;
align-items: center;
flex-wrap: wrap;
}
.control-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
label {
font-size: 0.875rem;
font-weight: 500;
color: var(--color-text-secondary);
}
select, button {
padding: 0.5rem 1rem;
border: 1px solid var(--color-border);
border-radius: 0.375rem;
font-size: 0.875rem;
background: white;
cursor: pointer;
}
select:focus, button:focus {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
button {
background: var(--color-primary);
color: white;
border: none;
font-weight: 500;
transition: background 0.2s;
}
button:hover {
background: #1d4ed8;
}
.matrix-container {
background: var(--color-surface);
border-radius: 0.5rem;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.matrix-table {
width: 100%;
border-collapse: collapse;
}
.matrix-table th,
.matrix-table td {
border: 1px solid var(--color-border);
padding: 0.75rem;
text-align: center;
}
.matrix-table th {
background: #f3f4f6;
font-weight: 600;
color: var(--color-text);
}
.matrix-table thead th {
background: var(--color-primary);
color: white;
}
.matrix-table tbody th {
background: #f9fafb;
font-weight: 600;
}
.prototype-cell {
position: relative;
padding: 0;
height: 400px;
vertical-align: top;
}
.prototype-wrapper {
height: 100%;
display: flex;
flex-direction: column;
}
.prototype-header {
padding: 0.5rem;
background: #f9fafb;
border-bottom: 1px solid var(--color-border);
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
}
.prototype-title {
font-size: 0.75rem;
font-weight: 500;
color: var(--color-text-secondary);
}
.prototype-actions {
display: flex;
gap: 0.25rem;
}
.icon-btn {
width: 24px;
height: 24px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
color: var(--color-text-secondary);
cursor: pointer;
border-radius: 0.25rem;
}
.icon-btn:hover {
background: #e5e7eb;
color: var(--color-text);
}
.icon-btn.selected {
background: var(--color-primary);
color: white;
}
.prototype-iframe-container {
flex: 1;
position: relative;
overflow: hidden;
}
.prototype-iframe {
width: 100%;
height: 100%;
border: none;
transform-origin: top left;
}
.zoom-info {
position: absolute;
bottom: 0.5rem;
right: 0.5rem;
background: rgba(0,0,0,0.7);
color: white;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
pointer-events: none;
}
.tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
border-bottom: 2px solid var(--color-border);
}
.tab {
padding: 0.75rem 1.5rem;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
cursor: pointer;
font-weight: 500;
color: var(--color-text-secondary);
margin-bottom: -2px;
}
.tab.active {
color: var(--color-primary);
border-bottom-color: var(--color-primary);
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.fullscreen-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.95);
z-index: 1000;
padding: 2rem;
}
.fullscreen-overlay.active {
display: flex;
flex-direction: column;
}
.fullscreen-header {
color: white;
margin-bottom: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.fullscreen-iframe {
flex: 1;
border: none;
background: white;
border-radius: 0.5rem;
}
.close-btn {
background: rgba(255,255,255,0.2);
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
cursor: pointer;
}
.close-btn:hover {
background: rgba(255,255,255,0.3);
}
.selection-summary {
background: #fef3c7;
border-left: 4px solid #f59e0b;
padding: 1rem;
margin-bottom: 2rem;
border-radius: 0.375rem;
}
.selection-summary h3 {
color: #92400e;
margin-bottom: 0.5rem;
font-size: 1rem;
}
.selection-list {
list-style: none;
color: #78350f;
font-size: 0.875rem;
}
.selection-list li {
padding: 0.25rem 0;
}
@media (max-width: 1200px) {
.prototype-cell {
height: 300px;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>🎨 UI Design Matrix Comparison</h1>
<div class="meta">
<strong>Run ID:</strong> {{run_id}} |
<strong>Session:</strong> {{session_id}} |
<strong>Generated:</strong> {{timestamp}}
</div>
</header>
<div class="controls">
<div class="control-group">
<label for="page-select">Page:</label>
<select id="page-select">
<!-- Populated by JavaScript -->
</select>
</div>
<div class="control-group">
<label for="zoom-level">Zoom:</label>
<select id="zoom-level">
<option value="0.25">25%</option>
<option value="0.5">50%</option>
<option value="0.75">75%</option>
<option value="1" selected>100%</option>
</select>
</div>
<div class="control-group">
<label>&nbsp;</label>
<button id="sync-scroll-toggle">🔗 Sync Scroll: ON</button>
</div>
<div class="control-group">
<label>&nbsp;</label>
<button id="export-selection">📥 Export Selection</button>
</div>
</div>
<div id="selection-summary" class="selection-summary" style="display:none">
<h3>Selected Prototypes (<span id="selection-count">0</span>)</h3>
<ul id="selection-list" class="selection-list"></ul>
</div>
<div class="tabs">
<button class="tab active" data-tab="matrix">Matrix View</button>
<button class="tab" data-tab="comparison">Side-by-Side</button>
<button class="tab" data-tab="runs">Compare Runs</button>
</div>
<div class="tab-content active" data-content="matrix">
<div class="matrix-container">
<table class="matrix-table">
<thead>
<tr>
<th>Style ↓ / Layout →</th>
<th>Layout 1</th>
<th>Layout 2</th>
<th>Layout 3</th>
</tr>
</thead>
<tbody id="matrix-body">
<!-- Populated by JavaScript -->
</tbody>
</table>
</div>
</div>
<div class="tab-content" data-content="comparison">
<p>Select two prototypes from the matrix to compare side-by-side.</p>
<div id="comparison-view"></div>
</div>
<div class="tab-content" data-content="runs">
<p>Compare the same prototype across different runs.</p>
<div id="runs-comparison"></div>
</div>
</div>
<div id="fullscreen-overlay" class="fullscreen-overlay">
<div class="fullscreen-header">
<h2 id="fullscreen-title"></h2>
<button class="close-btn" onclick="closeFullscreen()">✕ Close</button>
</div>
<iframe id="fullscreen-iframe" class="fullscreen-iframe"></iframe>
</div>
<script>
// Configuration - Replace with actual values during generation
const CONFIG = {
runId: "{{run_id}}",
sessionId: "{{session_id}}",
styleVariants: {{style_variants}}, // e.g., 3
layoutVariants: {{layout_variants}}, // e.g., 3
pages: {{pages_json}}, // e.g., ["dashboard", "auth"]
basePath: "." // Relative path to prototypes
};
// State
let state = {
currentPage: CONFIG.pages[0],
zoomLevel: 1,
syncScroll: true,
selected: new Set(),
fullscreenSrc: null
};
// Initialize
document.addEventListener('DOMContentLoaded', () => {
populatePageSelect();
renderMatrix();
setupEventListeners();
loadSelectionFromStorage();
});
function populatePageSelect() {
const select = document.getElementById('page-select');
CONFIG.pages.forEach(page => {
const option = document.createElement('option');
option.value = page;
option.textContent = capitalize(page);
select.appendChild(option);
});
}
function renderMatrix() {
const tbody = document.getElementById('matrix-body');
tbody.innerHTML = '';
for (let s = 1; s <= CONFIG.styleVariants; s++) {
const row = document.createElement('tr');
// Style header cell
const headerCell = document.createElement('th');
headerCell.textContent = `Style ${s}`;
row.appendChild(headerCell);
// Prototype cells for each layout
for (let l = 1; l <= CONFIG.layoutVariants; l++) {
const cell = document.createElement('td');
cell.className = 'prototype-cell';
const filename = `${state.currentPage}-style-${s}-layout-${l}.html`;
const id = `${state.currentPage}-s${s}-l${l}`;
cell.innerHTML = `
<div class="prototype-wrapper">
<div class="prototype-header">
<span class="prototype-title">S${s}L${l}</span>
<div class="prototype-actions">
<button class="icon-btn select-btn" data-id="${id}" title="Select">
${state.selected.has(id) ? '★' : '☆'}
</button>
<button class="icon-btn" onclick="openFullscreen('${filename}', 'Style ${s} Layout ${l}')" title="Fullscreen">
</button>
<button class="icon-btn" onclick="openInNewTab('${filename}')" title="Open in new tab">
</button>
</div>
</div>
<div class="prototype-iframe-container">
<iframe
class="prototype-iframe"
src="${filename}"
data-cell="s${s}-l${l}"
style="transform: scale(${state.zoomLevel});"
></iframe>
<div class="zoom-info">${Math.round(state.zoomLevel * 100)}%</div>
</div>
</div>
`;
row.appendChild(cell);
}
tbody.appendChild(row);
}
// Re-attach selection event listeners
document.querySelectorAll('.select-btn').forEach(btn => {
btn.addEventListener('click', (e) => toggleSelection(e.target.dataset.id, e.target));
});
// Setup scroll sync
if (state.syncScroll) {
setupScrollSync();
}
}
function setupScrollSync() {
const iframes = document.querySelectorAll('.prototype-iframe');
let isScrolling = false;
iframes.forEach(iframe => {
iframe.addEventListener('load', () => {
const iframeWindow = iframe.contentWindow;
iframe.contentDocument.addEventListener('scroll', (e) => {
if (!state.syncScroll || isScrolling) return;
isScrolling = true;
const scrollTop = iframe.contentDocument.documentElement.scrollTop;
const scrollLeft = iframe.contentDocument.documentElement.scrollLeft;
iframes.forEach(otherIframe => {
if (otherIframe !== iframe && otherIframe.contentDocument) {
otherIframe.contentDocument.documentElement.scrollTop = scrollTop;
otherIframe.contentDocument.documentElement.scrollLeft = scrollLeft;
}
});
setTimeout(() => { isScrolling = false; }, 50);
});
});
});
}
function setupEventListeners() {
// Page selector
document.getElementById('page-select').addEventListener('change', (e) => {
state.currentPage = e.target.value;
renderMatrix();
});
// Zoom level
document.getElementById('zoom-level').addEventListener('change', (e) => {
state.zoomLevel = parseFloat(e.target.value);
renderMatrix();
});
// Sync scroll toggle
document.getElementById('sync-scroll-toggle').addEventListener('click', (e) => {
state.syncScroll = !state.syncScroll;
e.target.textContent = `🔗 Sync Scroll: ${state.syncScroll ? 'ON' : 'OFF'}`;
if (state.syncScroll) setupScrollSync();
});
// Export selection
document.getElementById('export-selection').addEventListener('click', exportSelection);
// Tab switching
document.querySelectorAll('.tab').forEach(tab => {
tab.addEventListener('click', (e) => {
const tabName = e.target.dataset.tab;
switchTab(tabName);
});
});
}
function toggleSelection(id, btn) {
if (state.selected.has(id)) {
state.selected.delete(id);
btn.textContent = '☆';
btn.classList.remove('selected');
} else {
state.selected.add(id);
btn.textContent = '★';
btn.classList.add('selected');
}
updateSelectionSummary();
saveSelectionToStorage();
}
function updateSelectionSummary() {
const summary = document.getElementById('selection-summary');
const count = document.getElementById('selection-count');
const list = document.getElementById('selection-list');
count.textContent = state.selected.size;
if (state.selected.size > 0) {
summary.style.display = 'block';
list.innerHTML = Array.from(state.selected)
.map(id => `<li>${id}</li>`)
.join('');
} else {
summary.style.display = 'none';
}
}
function saveSelectionToStorage() {
localStorage.setItem(`selection-${CONFIG.runId}`, JSON.stringify(Array.from(state.selected)));
}
function loadSelectionFromStorage() {
const stored = localStorage.getItem(`selection-${CONFIG.runId}`);
if (stored) {
state.selected = new Set(JSON.parse(stored));
updateSelectionSummary();
}
}
function exportSelection() {
const report = {
runId: CONFIG.runId,
sessionId: CONFIG.sessionId,
timestamp: new Date().toISOString(),
selections: Array.from(state.selected).map(id => ({
id,
file: `${id.replace(/-s(\d+)-l(\d+)/, '-style-$1-layout-$2')}.html`
}))
};
const blob = new Blob([JSON.stringify(report, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `selection-${CONFIG.runId}.json`;
a.click();
URL.revokeObjectURL(url);
alert(`Exported ${state.selected.size} selections to selection-${CONFIG.runId}.json`);
}
function openFullscreen(src, title) {
const overlay = document.getElementById('fullscreen-overlay');
const iframe = document.getElementById('fullscreen-iframe');
const titleEl = document.getElementById('fullscreen-title');
iframe.src = src;
titleEl.textContent = title;
overlay.classList.add('active');
state.fullscreenSrc = src;
}
function closeFullscreen() {
const overlay = document.getElementById('fullscreen-overlay');
const iframe = document.getElementById('fullscreen-iframe');
overlay.classList.remove('active');
iframe.src = '';
state.fullscreenSrc = null;
}
function openInNewTab(src) {
window.open(src, '_blank');
}
function switchTab(tabName) {
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.toggle('active', tab.dataset.tab === tabName);
});
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.toggle('active', content.dataset.content === tabName);
});
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
// Close fullscreen on ESC key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && state.fullscreenSrc) {
closeFullscreen();
}
});
</script>
</body>
</html>