一键导入
iterating-visuals
Auto-screenshot design iteration loop with active feedback request. Use when making visual/style changes to components.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Auto-screenshot design iteration loop with active feedback request. Use when making visual/style changes to components.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Creative direction for AI image generation — distill a codebase's FEEL canon (taste tokens, TDRs, persona files) into prompt-ready material vocabulary, map product architecture to scene systems, and enforce visual discipline across banner sets and scene stacks.
Analyze feedback logs to detect design preference patterns. Auto-contributes HIGH confidence patterns upstream.
Motion design and animation patterns for UI based on Emil Kowalski's principles
Touch, keyboard, and form interaction patterns for accessible UI
Design physics system for UI interactions - sync strategies, timing, confirmations
Convert vague "feel" feedback into specific actionable fixes via decomposition questions
| name | iterating-visuals |
| description | Auto-screenshot design iteration loop with active feedback request. Use when making visual/style changes to components. |
| user-invocable | true |
| allowed-tools | Read, Write, Glob, Grep, Edit, Bash, AskUserQuestion |
Design iteration loop that automatically captures screenshots after visual changes and actively requests feedback.
/iterate-visual [component] # Start iteration on component
/iterate-visual --screenshot # Manual screenshot capture
Auto-trigger signals (skill activates automatically when detected):
.tsx, .jsx, .css, .scss files with style changesThis skill closes the visual feedback loop:
CHANGE → CAPTURE → ASK → RECEIVE → REFINE → COMPOUND → REPEAT
Without this loop, AI makes changes blindly and can't evaluate visual output.
npm install -g agent-browser && agent-browser installgrimoires/artisan/taste.md for grounded decisionsCheck if we're in a design iteration context:
Trigger Signals:
| Signal | Weight | Detection |
|---|---|---|
| Editing style files | High | .tsx, .jsx, .css, .scss changes |
| Tailwind class changes | High | className= modifications |
| Multiple edits on same component | High | >2 edits to same file |
| User mentions visuals | Medium | "looks", "visual", "screenshot" |
| Dev server running | Prerequisite | Check common ports |
Detection Logic:
# Check for dev server on common ports
for port in 3000 5173 8080 4000; do
if curl -s --max-time 1 "http://localhost:$port" > /dev/null 2>&1; then
DEV_SERVER="http://localhost:$port"
break
fi
done
If no dev server detected:
No dev server found on ports 3000, 5173, 8080, 4000.
Options:
1. Start your dev server (npm run dev / bun dev)
2. Specify custom port
3. Continue without screenshots
Execute the requested style/visual change:
grimoires/artisan/taste.md for context (if exists)grimoires/artisan/inspiration/direction.md for constraintsAfter style change, capture the visual result:
# Open dev server page
agent-browser open "$DEV_SERVER" --headed
# Wait for render
agent-browser wait --load networkidle
# Take screenshot
agent-browser screenshot grimoires/artisan/screenshots/{component}-{timestamp}.png
# Close browser
agent-browser close
Screenshot naming:
grimoires/artisan/screenshots/
├── Card-20260204-143022.png
├── Button-20260204-143045.png
└── Sidebar-20260204-143112.png
If agent-browser not installed:
agent-browser not found.
Install with: npm install -g agent-browser && agent-browser install
Or continue without screenshots (less effective iteration).
CRITICAL: Always ask for feedback after visual changes.
Present the screenshot and request feedback using AskUserQuestion:
{
"questions": [{
"question": "Here's the updated component. How does it look?",
"header": "Visual Check",
"multiSelect": false,
"options": [
{
"label": "Looks good",
"description": "Continue to next change"
},
{
"label": "Something's off",
"description": "I'll help you identify what"
},
{
"label": "Let me annotate",
"description": "Use Agentation to point precisely"
},
{
"label": "Show alternatives",
"description": "Generate variation ideas"
}
]
}]
}
Log every feedback interaction for pattern detection.
log_feedback() {
local feedback="$1"
local context_json="$2"
local resolution="${3:-}"
local log_dir="grimoires/artisan/feedback"
local log_file="${log_dir}/$(date +%Y-%m-%d).jsonl"
mkdir -p "$log_dir"
# Stable session_id across the session (persist to file)
if [[ -z "${ARTISAN_SESSION_ID:-}" ]]; then
local session_file="${log_dir}/.session_id"
if [[ -f "$session_file" ]]; then
ARTISAN_SESSION_ID="$(cat "$session_file")"
else
ARTISAN_SESSION_ID="$(date +%s%N | sha256sum | cut -c1-8)"
echo "$ARTISAN_SESSION_ID" > "$session_file"
fi
export ARTISAN_SESSION_ID
fi
# Validate/normalize context JSON
local context
context=$(printf '%s' "$context_json" | jq -ce . 2>/dev/null) || context="{}"
# Use jq for safe JSON construction
if [[ -n "$resolution" ]]; then
jq -cn \
--arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg session_id "$ARTISAN_SESSION_ID" \
--arg skill "iterating-visuals" \
--arg feedback "$feedback" \
--arg resolution "$resolution" \
--argjson context "$context" \
'{ts:$ts,session_id:$session_id,skill:$skill,feedback:$feedback,context:$context,resolution:$resolution}' \
>> "$log_file"
else
jq -cn \
--arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg session_id "$ARTISAN_SESSION_ID" \
--arg skill "iterating-visuals" \
--arg feedback "$feedback" \
--argjson context "$context" \
'{ts:$ts,session_id:$session_id,skill:$skill,feedback:$feedback,context:$context}' \
>> "$log_file"
fi
}
Log after each feedback response:
# After "Looks good"
log_feedback "looks_good" "{\"change\":\"${change}\",\"component\":\"${component}\"}"
# After "Something's off"
log_feedback "something_off" "{\"component\":\"${component}\"}"
# After resolution applied
log_feedback "resolved" "{\"component\":\"${component}\"}" "${old_value}→${new_value}"
Based on user response:
log_feedback "looks_good" ...Let me help identify what's off.
Is it:
1. The spacing? (padding, margins, gaps)
2. The color? (palette, contrast)
3. The hierarchy? (typography, weight)
4. The motion? (animation, transitions)
5. The density? (too much/little info)
Agentation v2 (MCP) — If agentation MCP server is available:
I'll check Agentation for your annotations...
agentation_get_pending to retrieve annotationsagentation_resolve after applying fixesAgentation v1 (Fallback) — If MCP unavailable:
To annotate precisely:
1. If not installed: npm install agentation -D
2. Add <Agentation /> to your app
3. Click the bottom-right UI to activate
4. Click/highlight the problematic element
5. Copy the markdown output
6. Paste it here
I'll parse the selectors and map to code.
Alternatives based on your direction.md:
A) More Stripe-like:
- Increase padding to p-6
- Reduce shadow to shadow-sm
- Add subtle border
B) More Linear-like:
- Tighten padding to p-3
- Remove shadow entirely
- Use border-subtle
C) Middle ground:
- Keep current padding
- Adjust shadow to shadow-xs
Which direction feels closer?
Apply the fix based on feedback, then return to Phase 2 (capture screenshot).
Loop continues until user says "Looks good" or explicitly ends iteration.
After iteration completes, check for taste learning opportunities:
During this session, I noticed you:
- Preferred shadow-sm over shadow-md (3 times)
- Chose p-6 over p-4 (2 times)
Add these preferences to taste.md?
[Y]es - Update taste.md
[N]o - This was context-specific
If yes, update taste.md and create evolution snapshot.
┌─────────────────────────────────────────────────────────────────┐
│ DESIGN ITERATION LOOP │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. CHANGE ───► 2. CAPTURE ───► 3. ASK ───► 4. RECEIVE │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ [Edit code] [Screenshot] [Feedback [Process │
│ prompt] response] │
│ │ │
│ ▼ │
│ 7. COMPOUND ◄── 6. TASTE? ◄── 5. REFINE ◄──┘ │
│ │ │
│ │ Pattern If user says Apply fix │
│ │ emerges? "looks good" based on │
│ │ feedback │
│ ▼ │
│ [Update │
│ taste.md] │
│ │
└─────────────────────────────────────────────────────────────────┘
User: "Make the card feel more premium"
AI: [Reads direction.md: premium = spacious, subtle shadows]
AI: [Edits Card.tsx: p-4 → p-6, shadow-md → shadow-sm]
AI: [Runs agent-browser screenshot]
AI: "Here's the updated card. Added generous padding and subtle
shadow based on your 'premium' direction. How does it look?"
User: [Selects "Something's off"]
AI: "Is it the spacing, color, hierarchy, motion, or density?"
User: "The shadow is still too heavy"
AI: [Edits Card.tsx: shadow-sm → shadow-xs]
AI: [Takes another screenshot]
AI: "Reduced to shadow-xs. How about now?"
User: [Selects "Looks good"]
AI: "Great! I noticed you preferred shadow-xs over shadow-sm.
Add to taste.md as a preference?"
User: "Yes"
AI: [Updates taste.md, creates evolution snapshot]
═══════════════════════════════════════════════════════════════
DESIGN ITERATION: Card.tsx
═══════════════════════════════════════════════════════════════
Change #1:
├── Applied: p-4 → p-6 (premium spacing)
├── Applied: shadow-md → shadow-sm (subtle elevation)
├── Screenshot: grimoires/artisan/screenshots/Card-20260204-143022.png
└── Feedback: "Shadow still too heavy"
Change #2:
├── Applied: shadow-sm → shadow-xs
├── Screenshot: grimoires/artisan/screenshots/Card-20260204-143045.png
└── Feedback: "Looks good"
Session Summary:
├── Total iterations: 2
├── Taste learned: shadow-xs preferred over shadow-sm
└── taste.md updated: Yes
═══════════════════════════════════════════════════════════════
| Error | Resolution |
|---|---|
| No dev server | Prompt to start, or continue without screenshots |
| agent-browser not installed | Provide install command |
| Screenshot fails | Retry once, then continue with note |
| No direction.md | Use taste.md only, or proceed without constraints |
/synthesize - Extract taste from references/inscribe - Apply taste to components/decompose - Convert vague feedback to specifics (Sprint 3)Add to .loa.config.yaml:
artisan:
iterate_visuals:
auto_screenshot: true
dev_server_ports: [3000, 5173, 8080, 4000]
screenshot_dir: grimoires/artisan/screenshots
taste_learning: true