cuj-screenshots

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

CUJ Screenshots Skill

CUJ 截图技能

Automate visual documentation of web app user journeys using headless browser automation.
通过无头浏览器自动化实现Web应用用户旅程的视觉文档自动化。

When to Use This

适用场景

Always run CUJ captures after UI changes. This is part of the dev loop, not just documentation.
UI变更后务必运行CUJ捕获。 这是开发流程的一部分,而非仅用于文档记录。

Triggered By:

触发场景:

  • Any frontend component change
  • CSS/styling updates
  • New features that affect user flow
  • Bug fixes that change visible behavior
  • Before sharing work with humans ("here's what it looks like now")
  • 任何前端组件变更
  • CSS/样式更新
  • 影响用户流程的新功能
  • 改变可见行为的Bug修复
  • 与他人分享工作前("这是当前的效果")

The Loop:

流程循环:

Make UI change → Run CUJs → Review screenshots → 
  ├─ Looks good? → Update GIFs, commit, share link
  └─ Looks wrong? → Fix bug, repeat
Make UI change → Run CUJs → Review screenshots → 
  ├─ Looks good? → Update GIFs, commit, share link
  └─ Looks wrong? → Fix bug, repeat

Proactive Use:

主动使用方式:

When finishing UI work, don't just say "done" — capture CUJs, update the GIFs, and share:
"Updated the task card styling. Here's the new CUJ: https://github.com/user/repo/blob/main/docs/CUJs.md"
This gives your human instant visual feedback without them needing to run the app.
完成UI工作后,不要只说"完成了" —— 捕获CUJ,更新GIF并分享:
"更新了任务卡片样式。这是新的CUJ: https://github.com/user/repo/blob/main/docs/CUJs.md"
这样无需对方运行应用,就能立刻给他们提供直观的视觉反馈。

What It Does

功能说明

  1. Launches headless Chromium via Playwright
  2. Navigates through a defined user journey
  3. Captures screenshots at each step
  4. Stitches screenshots into an animated GIF
  5. Outputs to a docs folder for commit
  1. 通过Playwright启动无头Chromium
  2. 按照定义的用户旅程导航
  3. 在每个步骤捕获截图
  4. 将截图拼接为动画GIF
  5. 输出到docs文件夹以便提交

Requirements

环境要求

  • Playwright:
    uv run --with playwright python script.py
  • Chromium: Auto-installed by Playwright on first run
  • ImageMagick: For GIF creation (
    convert
    command)
Install Playwright browsers (one-time):
bash
uv run --with playwright playwright install chromium
  • Playwright:
    uv run --with playwright python script.py
  • Chromium: 首次运行时由Playwright自动安装
  • ImageMagick: 用于生成GIF(
    convert
    命令)
安装Playwright浏览器(仅需一次):
bash
uv run --with playwright playwright install chromium

Quick Start

快速开始

1. Define Your CUJ

1. 定义你的CUJ

Create a Python script for each journey:
python
import asyncio
from playwright.async_api import async_playwright
import os

async def capture_my_cuj():
    output_dir = "/tmp/cuj-screenshots/my-cuj"
    os.makedirs(output_dir, exist_ok=True)
    
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        context = await browser.new_context(
            viewport={"width": 390, "height": 844},  # Mobile
            device_scale_factor=2  # Retina
        )
        page = await context.new_page()
        
        # Step 1
        await page.goto("http://localhost:5173")
        await page.wait_for_timeout(1500)
        await page.screenshot(path=f"{output_dir}/01-initial.png")
        
        # Step 2: Interact
        await page.click("button:has-text('Submit')")
        await page.wait_for_timeout(1000)
        await page.screenshot(path=f"{output_dir}/02-submitted.png")
        
        # ... more steps
        
        await browser.close()

if __name__ == "__main__":
    asyncio.run(capture_my_cuj())
为每个用户旅程创建Python脚本:
python
import asyncio
from playwright.async_api import async_playwright
import os

async def capture_my_cuj():
    output_dir = "/tmp/cuj-screenshots/my-cuj"
    os.makedirs(output_dir, exist_ok=True)
    
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        context = await browser.new_context(
            viewport={"width": 390, "height": 844},  # Mobile
            device_scale_factor=2  # Retina
        )
        page = await context.new_page()
        
        # Step 1
        await page.goto("http://localhost:5173")
        await page.wait_for_timeout(1500)
        await page.screenshot(path=f"{output_dir}/01-initial.png")
        
        # Step 2: Interact
        await page.click("button:has-text('Submit')")
        await page.wait_for_timeout(1000)
        await page.screenshot(path=f"{output_dir}/02-submitted.png")
        
        # ... more steps
        
        await browser.close()

if __name__ == "__main__":
    asyncio.run(capture_my_cuj())

2. Run Capture

2. 运行捕获

bash
uv run --with playwright python my_cuj.py
bash
uv run --with playwright python my_cuj.py

3. Create GIF

3. 生成GIF

bash
convert -delay 150 -loop 0 /tmp/cuj-screenshots/my-cuj/*.png output.gif
  • -delay 150
    = 1.5 seconds per frame (hundredths of a second)
  • -loop 0
    = infinite loop
bash
convert -delay 150 -loop 0 /tmp/cuj-screenshots/my-cuj/*.png output.gif
  • -delay 150
    = 每帧1.5秒(单位:百分之一秒)
  • -loop 0
    = 无限循环

4. Commit & Share

4. 提交并分享

bash
mv output.gif docs/gifs/my-cuj.gif
git add docs/gifs/my-cuj.gif docs/CUJs.md
git commit -m "docs: add my-cuj GIF"
git push
bash
mv output.gif docs/gifs/my-cuj.gif
git add docs/gifs/my-cuj.gif docs/CUJs.md
git commit -m "docs: add my-cuj GIF"
git push

Viewport Presets

视口预设

DeviceWidthHeightScale
iPhone 12 Pro3908442
iPhone SE3756672
Pixel 53938512.75
Desktop12807201
Desktop HD192010801
设备宽度高度缩放比例
iPhone 12 Pro3908442
iPhone SE3756672
Pixel 53938512.75
Desktop12807201
Desktop HD192010801

Common Interactions

常见交互操作

python
undefined
python
undefined

Click button by text

Click button by text

await page.click("button:has-text('Submit')")
await page.click("button:has-text('Submit')")

Fill input

Fill input

await page.fill("input[name='email']", "test@example.com")
await page.fill("input[name='email']", "test@example.com")

Select dropdown

Select dropdown

await page.select_option("select#plan", "premium")
await page.select_option("select#plan", "premium")

Wait for element

Wait for element

await page.wait_for_selector(".success-message")
await page.wait_for_selector(".success-message")

Scroll

Scroll

await page.evaluate("window.scrollBy(0, 300)")
await page.evaluate("window.scrollBy(0, 300)")

Keyboard shortcut

Keyboard shortcut

await page.keyboard.press("Escape")
undefined
await page.keyboard.press("Escape")
undefined

Full Workflow Example

完整工作流示例

See
scripts/capture-cujs.py
for a complete example that:
  • Starts backend + frontend servers
  • Captures multiple CUJs
  • Generates GIFs
  • Updates CUJs.md
查看
scripts/capture-cujs.py
获取完整示例,该示例可以:
  • 启动后端+前端服务器
  • 捕获多个CUJs
  • 生成GIF
  • 更新CUJs.md

Tips

小贴士

  • Wait times: Use
    wait_for_timeout(1000)
    after interactions for animations
  • Selectors: Prefer
    text=
    or
    has-text()
    over fragile CSS selectors
  • Error handling: Wrap interactions in try/except, screenshot on error
  • Naming: Use numbered prefixes (
    01-
    ,
    02-
    ) for sort order
  • GIF size: Keep under 500KB for GitHub README display
  • 等待时间:交互后使用
    wait_for_timeout(1000)
    等待动画完成
  • 选择器:优先使用
    text=
    has-text()
    而非脆弱的CSS选择器
  • 错误处理:将交互操作包裹在try/except中,出错时捕获截图
  • 命名规范:使用数字前缀(
    01-
    ,
    02-
    )保证排序正确
  • GIF大小:保持在500KB以下以便在GitHub README中正常显示

CUJs.md Documentation

CUJs.md 文档规范

Create a
docs/CUJs.md
file to document each journey with embedded GIFs:
markdown
undefined
创建
docs/CUJs.md
文件,嵌入GIF来记录每个用户旅程:
markdown
undefined

Critical User Journeys (CUJs)

Critical User Journeys (CUJs)

CUJ 1: App Tour

CUJ 1: App Tour

Goal: Navigate the main app layout.
Steps:
  1. Open app → Activity tab
  2. Switch to Live tab
  3. Return to Activity
App Tour

Goal: Navigate the main app layout.
Steps:
  1. Open app → Activity tab
  2. Switch to Live tab
  3. Return to Activity
App Tour

CUJ 2: Create Task

CUJ 2: Create Task

Goal: Create a new plan and task.
Steps:
  1. Click "+ Plan"
  2. Enter name, submit
  3. Click "+ Task"
  4. Enter name, submit
Create Task

This serves as both documentation and visual regression baseline.
Goal: Create a new plan and task.
Steps:
  1. Click "+ Plan"
  2. Enter name, submit
  3. Click "+ Task"
  4. Enter name, submit
Create Task

这份文档既是使用说明,也是视觉回归测试的基准。

Verifying UI Changes

验证UI变更

After making UI changes:
  1. Run the CUJ capture scripts
  2. Review the new screenshots (you can read image files!)
  3. If they look correct, update GIFs and commit
  4. Update
    CUJs.md
    if steps changed
  5. If something's wrong, you caught a bug!
完成UI变更后:
  1. 运行CUJ捕获脚本
  2. 查看新截图(AI Agent可以识别这些图片!)
  3. 如果显示正常,更新GIF并提交
  4. 如果步骤有变化,更新
    CUJs.md
  5. 如果出现问题,说明你发现了一个Bug!

Full Workflow

完整工作流

bash
undefined
bash
undefined

1. Make UI changes

1. Make UI changes

2. Start servers

2. Start servers

3. Capture CUJs

3. Capture CUJs

uv run --with playwright python scripts/capture-cujs.py
uv run --with playwright python scripts/capture-cujs.py

4. Review screenshots (agent can view these)

4. Review screenshots (agent can view these)

5. Create GIFs

5. Create GIFs

convert -delay 150 -loop 0 /tmp/cuj-screenshots/cuj1/*.png docs/gifs/cuj1.gif
convert -delay 150 -loop 0 /tmp/cuj-screenshots/cuj1/*.png docs/gifs/cuj1.gif

6. Update CUJs.md with new steps/descriptions

6. Update CUJs.md with new steps/descriptions

7. Commit everything

7. Commit everything

git add docs/CUJs.md docs/gifs/ git commit -m "docs: update CUJ screenshots after UI changes" git push
undefined
git add docs/CUJs.md docs/gifs/ git commit -m "docs: update CUJ screenshots after UI changes" git push
undefined