关于 MotionLint
MotionLint 用于审计网页运行时的动画,并可通过视觉 LLM 审查多视口界面与用户流程,面向前端开发者和编码 Agent。它兼有无需 API 密钥的确定性检查,以及可在 CI 中使用的报告和 MCP 服务。
主要功能
- 01测量动画时长与缓动曲线
- 02检查减少动态效果支持
- 03多视口视觉设计审查
- 04录制用户流程动画帧
- 05生成 SARIF 与 HTML 报告
- 06提供 stdio MCP 服务
适用场景
- 01在合并前发现不合适的动效
- 02审查多视口页面体验
- 03分析注册流程中的动画表现
- 04在 CI 中阻止严重体验问题
MCP 相关
MotionLint 提供 stdio MCP 服务,可接入 Claude Code 和 Cursor。它将实时页面审查结果提供给编码工作流。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y motionlintANTHROPIC_API_KEY密钥Anthropic API key for vision-LLM review. Optional — the deterministic audit needs no key, and Ollama, OpenAI or Google can be used instead.OPENAI_API_KEY密钥OpenAI API key for vision-LLM review. Optional.GOOGLE_API_KEY密钥Google API key for vision-LLM review. Optional.OPENAI_BASE_URLOverride the OpenAI base URL to target an OpenAI-compatible endpoint. Optional.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
5收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | string | 是 | 要审查的 URL。 |
| model | string | 否 | 模型覆盖设置。 |
| format | enum | 否 | 输出格式(默认:md)。'html' 是精美且便于分享的报告。md | json | sarif | html |
| record | boolean | 否 | 录制捕获过程的视频。 |
| new_only | boolean | 否 | 仅报告同一 URL 之前运行中未发现的问题。 |
| provider | string | 否 | LLM 提供商覆盖设置(auto|ollama|anthropic|openai|google|mock)。 |
| wait_for | string | 否 | 捕获前等待的 CSS 选择器或 'networkidle'。 |
| viewports | array | 否 | 要捕获的视口(默认:mobile + desktop)。 |
| max_findings | number | 否 | 仅保留排名靠前的 N 条发现项,按严重程度排序(Agent 关注重点)。 |
| max_pr_annotations | number | 否 | 仅限 SARIF:每份报告最多输出 N 条结果,并按严重程度排序(避免审查者疲劳)。 |
详细介绍
MotionLint
只需一条命令,即可评估任意页面的动画质量。无需 API 密钥,无需配置。
npx motionlint audit http://localhost:3000 --open
结果确定——直接测量线上页面,不涉及大模型。一次性前置步骤:npx playwright install chromium。
MotionLint 会测量应用实际发布的动效——时长、缓动曲线、交错间隔、退出时机、减少动态效果支持等,并根据公开发布的动画标准进行评分。下拉菜单使用渐入缓动、600 ms 的模态框、从 0 开始缩放的卡片、触屏时触发的悬停动效:这些问题都会被发现,并附上测量值和具体修复方法。
审计免费且可离线运行。添加 API 密钥后,MotionLint 还可进行视觉大模型设计评审——生成多个视口的截图,并对真实用户旅程进行 50 ms 帧突发采集,由模型评估,再将排序后的问题反馈给编码 Agent。它可作为 MCP 服务在 Claude Code 和 Cursor 中运行。
为什么要做这个
AI 编码 Agent 会读取 JSX、HTML 和 CSS,却看不到用户实际看到、点击和观察到的动画效果。提示词中的规则会告诉 Agent 应该发生什么,却没有任何工具检查实际发生了什么。原本应该滑入的模态框却直接弹出;加载状态被遗漏;焦点环消失。这些问题都无法在合并前通过代码评审发现,因为它们在差异中不可见。
MotionLint 补上了这个闭环:它测量正在运行的应用,并将评估结果反馈回来。
有何不同
| MotionLint | 视觉回归工具(Percy、Chromatic、Playwright snapshots) | AI 设计生成器(v0、Galileo、Claude Design、Stitch) | |
|---|---|---|---|
| 确定性动效审计 | 13 项检查,直接测量线上页面——无需 API 密钥,$0 | ✗ | ✗ |
| 多视口 UX 评审 | 从 12 个维度排序列出问题 | 仅比较像素差异 | 根据提示词生成新布局 |
| 动画评审 | 通过 CDP screencast 采集 50 ms 帧突发 → 联系表 → 大模型 | ✗ | ✗ |
| 实时动画调优 | Shadow DOM 预览 + 滑块 + Claude Code 导出 | ✗ | 生成新动效,不会调优现有动效 |
| 原生 MCP 服务 | ✓ 面向 Claude Code / Cursor 的 stdio MCP | ✗ | 因工具而异 |
| CI 门禁 | ✓ 用于代码扫描的 SARIF + 退出码 | ✓ 图像差异阈值 | ✗ |
| 质量验证 | 在 5 个前沿模型上,通过 24 个测试样例的压力测试,召回率达 100% | 不适用 | 不适用 |
MotionLint 弥补的概念性差距是:视觉回归工具能发现哪些地方变了,却无法判断新像素是否足够好;AI 设计工具能从头生成设计,却不会评审正在运行的内容。MotionLint 使用视觉大模型评审实际运行中的行为,并将评估结果反馈到编码流程中。
从这里开始——无需 API 密钥
npx playwright install chromium # one-time per machine (~300MB)
npx motionlint audit http://localhost:3000 --open
审计所需的全部配置就这些。它基于确定性规则,可离线运行,完全免费,并适用于任何可访问的网址——开发服务器、预发布部署,或其他人的网站。需要 Node 18+。
检查规则已发布在 docs/STANDARDS.md 中——安装任何内容之前,请先阅读。
接下来:大模型设计评审
设置一个 API 密钥(ANTHROPIC_API_KEY、OPENAI_API_KEY 或 GOOGLE_API_KEY——也可以在本地免费运行 Ollama),再执行三条命令即可解锁更多功能:
npm install -g motionlint
# Multi-viewport UX review of a page → ranked findings across 12 dimensions.
motionlint review http://localhost:3000
# Animation review of a scripted user journey → frame contact sheet + report.
motionlint flow --spec flows/signup.json
# Interactive HTML tuner — every animation on the page, with live sliders.
motionlint tune http://localhost:3000
在 Claude Code / Cursor 中
claude mcp add motionlint -- npx -y motionlint mcp
完整标志选项 — CI 门禁、路由发现、Storybook、深色模式、基线
# CI mode — non-zero exit on critical issues, SARIF output for code scanning.
motionlint review https://staging.acme.dev --ci --threshold critical --format sarif -o ux.sarif
# Polished, shareable HTML review with embedded screenshots + before/after fixes.
motionlint review http://localhost:3000 --format html -o review.html
# Review every route the site knows about (sitemap.xml + Next.js app/ directory).
motionlint review http://localhost:3000 --discover-routes
# Storybook mode — discover stories from /index.json, review each story iframe as its own route.
motionlint review http://localhost:6006 --storybook
# Color-scheme sweep — light and dark modes, plus Windows High Contrast.
motionlint review http://localhost:3000 --schemes --forced-colors --format html -o review.html
# Interaction affordances — grid each element's default/hover/focus/active states.
motionlint review http://localhost:3000 --state-grid
# Agent focus — keep only the top 5 findings, and only ones not seen in prior runs.
motionlint review http://localhost:3000 --max-findings 5 --new-only
# Before/after comparison — PR preview vs. production baseline.
motionlint review https://pr-123.preview.example.com --against https://prod.example.com
# Reviewer focus — cap the SARIF upload at 10 annotations per report.
motionlint review https://staging.acme.dev --format sarif -o ux.sarif --max-pr-annotations 10
# Pick a provider explicitly (auto-detect picks the first reachable one).
motionlint review http://localhost:3000 --provider anthropic --model claude-sonnet-5
# Track provider quality across runs + teach the reviewer from eval misses.
motionlint eval --provider anthropic --evolve
npm 包:motionlint。
流程审查的终端输出示例:
$ motionlint flow --spec flows/signup.json --provider anthropic
→ Running flow "signup-happy-path" against http://localhost:3000/signup (11 steps, 50ms intervals × 750ms window)
provider: anthropic (claude-sonnet-5)
capturing flow…
✓ step 1: 16 frames ✓ step 2: 16 frames ✓ step 3: 16 frames …
captured 176 frames in 31s
contact sheet → .motionlint/flows/signup-happy-path-…png
analyzing flow…
report → .motionlint/flows/signup-happy-path.md
Score: 4/10 · 3 critical findings
[critical] interaction — input focus rings missing across steps 2/4/6
[critical] interaction — submit button has no pressed state
[critical] loading_state — 1.4s wait with no spinner during submit
试用演示
demo/ 中提供了一个多路由 TS 动画展示项目,涵盖 Motion One、GSAP、anime.js、@formkit/auto-animate 和 lottie-web,其中还包括一个以猫为主题的单页应用,可通过一个 URL 展示 MotionLint 的所有功能:
node demo/server.mjs # http://localhost:4173
motionlint review http://localhost:4173/cat --record --embed
motionlint flow --spec flows/signup.json
motionlint tune http://localhost:4173/dashboard
可用路由:/、/pricing、/signup、/dashboard、/loading、/cat。报告保存在 .motionlint/reports/,截图保存在 .motionlint/screenshots/,视频保存在 .motionlint/videos/。
设置
API 密钥
MotionLint 启动时会自动从工作目录加载 .env 文件:
# .env (gitignored)
ANTHROPIC_API_KEY=sk-ant-...
# or
OPENAI_API_KEY=sk-...
# or
GOOGLE_API_KEY=...
# or run a local Ollama (no key needed) — auto-detected on http://localhost:11434
真实环境变量的优先级高于 .env。如果未设置密钥且没有 Ollama 运行,MotionLint 会回退到确定性的模拟提供方,因此完整流程(捕获 → 分析 → 报告)仍可端到端运行,供冒烟测试使用。
提供方自动检测
MotionLint 按以下顺序自动检测:Ollama(本地)→ Anthropic → OpenAI → Google。首个具有可用 API 密钥(或正在运行的服务)的提供方将被选中。使用 --provider <name> 和 --model <id> 覆盖。各提供方的质量评分卡以及选择方法,请参阅深入了解提供方。
以下内容适合希望了解 MotionLint 的底层工作原理、为工作流选择合适提供方,或将其接入 CI 的读者。
各提供商均已验证的质量
我们对 flow-review 流水线进行了压力测试,覆盖 12 种常见的 Web 应用动画模式 × 2 个变体(共 24 个测试样例)——错峰入场、悬停/按压/聚焦、模态框入场、加载骨架屏、表单错误、Toast、计数器递增、多动画仪表板、带内容错峰动画的模态框、丰富的表单反馈(聚焦 + 按压 + 加载旋转图标 + 成功),以及滚动驱动动画(进度条 + IntersectionObserver 显示 + 视差)。
于 2026-07-27 使用各主要提供商当前的旗舰模型运行:
| 提供商 · 模型 | 召回率(检出的故障) | FPR(被标记的正常项) | 分数差距 | 耗时 |
|---|---|---|---|---|
| OpenAI · gpt-5.6-sol | 100% (12/12) | 0% (0/12) | +3.3 | 10.9 min |
| OpenAI · gpt-5.5 | 100% (12/12) | 0% (0/12) | +3.3 | 11.5 min |
| Anthropic · claude-opus-5 | 100% (12/12) | 8% (1/12) | +4.1 | 21.0 min |
| Google · gemini-3.6-flash | 100% (12/12) | 17% (2/12) | +5.1 | 4.9 min |
| Anthropic · claude-sonnet-5 | 100% (12/12) | 33% (4/12) | +3.1 | 10.8 min |
结论是:召回率已不再是区分因素。 所有当前旗舰模型都能检出全部 12 个植入的故障。这就是测试结果——一年前还做不到,而这意味着模型选择已不再决定 MotionLint 是否有效。根据成本和延迟来选择即可。
不要根据 FPR 列给这些模型排名。 单次 24 个测试样例的运行无法得出明确结论。在同一套测试中进行两次正常项测试,除采样外不做任何改动,各模型的 FPR 都会波动 1–2 个测试样例——gpt-5.5 从 1/12 变为 0/12,gpt-5.6-sol 从 2/12 变为 0/12,gemini-3.6-flash 从 3/12 变为 2/12。一个测试样例就相当于 8 个百分点,因此“0%”与“17%”之间的全部差距都处于噪声范围内。应将此列理解为*“这些模型偶尔都会误报正常项”*,而不是排名。
为什么表格历史中的旧数据有误
这套测试于 2026-07-27 首次运行时,claude-opus-5 的召回率只有 83%——在五个模型中排名最后;而这张表的 2026-04-29 版本则报告有几个模型的 FPR 为 0%。这两者都是 MotionLint 的 Bug 导致的,并非模型表现。
Anthropic 的 max_tokens 默认值为 4096。冗长的响应会在 JSON 输出到一半时达到上限,无法解析的结果会被计为 0/10, no issues found——与正常检查结果无法区分。Opus 5 的三次截断中有两次发生在存在故障的测试样例上,因此才产生了 83% 这个结果。
同一个 Bug 也导致各模型的 FPR 被低估:截断的检查不会报告任何内容,因此不会产生误报。历史上任何“0% FPR”的数据,都有一部分反映的是解析失败,而非模型精确度。此 Bug 已于 2026-07-27 修复,同时也修复了相关路径中将截断、拒绝回答和安全拦截的响应处理成看似正常结果的问题。
运行 scripts/run-all-benchmarks.mjs 后,可在 .motionlint/stress/ 查看各提供商的完整评分卡。使用 --only <provider>:<model> 可重新运行单个模型的测试。
深入了解各提供商
| 提供商 | 模型 | 设置 | 质量(24 个测试样例) | 每次审查成本¹ |
|---|---|---|---|---|
google | gemini-3.6-flash | GOOGLE_API_KEY=… | 100% 召回率 · 17% 误报率 · +5.1 差距 | $0.019 |
anthropic | claude-sonnet-5 | ANTHROPIC_API_KEY=… | 100% 召回率 · 33% 误报率 · +3.1 差距 | $0.089 |
openai | gpt-5.5 | OPENAI_API_KEY=… | 100% 召回率 · 0% 误报率 · +3.3 差距 | $0.248 |
openai | gpt-5.6-sol | OPENAI_API_KEY=… | 100% 召回率 · 0% 误报率 · +3.3 差距 | $0.265 |
anthropic | claude-opus-5 | ANTHROPIC_API_KEY=… | 100% 召回率 · 8% 误报率 · +4.1 差距 | $0.293 |
ollama | 任意视觉模型 | ollama serve + ollama pull <model> | 本次运行未进行基准测试 | $0 |
mock | 启发式存根 | (自动回退) | 不适用 — 用于 CI 冒烟测试的确定性存根 | $0 |
¹ 实测,而非估算 — 使用每个模型对演示应用运行一次真实的 motionlint review,采用默认的 2 个视口和整页模式,从各提供商的用量字段读取实际令牌数量,再乘以公布的标价。任何运行都可通过 formatUsageLine() 重现。Sonnet 5 使用入门价格(截至 2026-08-31);此后价格大约会上涨一半。流程审查会为每个流程发送一张合成图像,但联系表更大。动画调节器和 motionlint audit 不会调用大模型,因此没有任何费用。
输出令牌占主导。 五个模型的输入量相差不超过 2 倍;输出量则从 1,390(Gemini)到 10,219(Opus 5)不等。正是这 7 倍的差距,而非图像大小,让最贵的模型比最便宜的贵 15 倍。
如何选择
- 默认选择。 Google
gemini-3.6-flash— 召回率为 100%,比 Opus 5 便宜 13 倍,且在五个模型中速度最快(4.9 分钟)。既然每个模型都发现了所有问题,默认选择更贵的模型就没有质量上的理由。 - Anthropic 方案。
claude-sonnet-5,价格为 $0.089 — 比claude-opus-5便宜 3 倍,召回率却相同。Opus 5 更贵,耗时也多一倍(21.0 分钟,而 Sonnet 5 为 10.8 分钟),召回率却没有测得的优势;只有在你看重略高的分差(+4.1,而 Sonnet 5 为 +3.1)时才选择它。 - OpenAI 方案。
gpt-5.5和gpt-5.6-sol在所有测量指标上都无法区分,价格差异也在 7% 以内。选择你的账户已有的那个即可。 - 严格的 CI 门禁。 任选其一,依据召回率进行判断。不要依据误报率来选择——请参阅上文关于噪声底限的注意事项。如果误报会影响你的门禁,请运行自己的测试样例,而不要依赖我们这组仅有 24 个测试样例的单次运行结果。
- 本地 / 隔离环境。 任意 Ollama 视觉模型都可使用,但请确认它确实具备视觉能力:有些模型虽然能通过 API 接收图像,却会静默忽略图像,只根据提示词作答。本次运行未对任何此类模型进行基准测试。
切换提供商
每条命令都支持 --provider 和 --model:
motionlint review http://localhost:3000 --provider openai --model gpt-5.5
motionlint flow --spec flows/signup.json --provider google --model gemini-3.6-flash
motionlint review http://localhost:3000 --provider ollama --model llava:13b
对你自己的提供商进行基准测试
要将新的提供商与同一组 24 个测试样例压力测试进行比较:
node -e "
import('./dist/config/env.js').then(async ({ loadEnv }) => {
loadEnv();
const { runStress, renderStressMarkdown } = await import('./dist/flow/stress.js');
const { writeFile, mkdir } = await import('node:fs/promises');
const { resolve } = await import('node:path');
await mkdir('.motionlint/stress', { recursive: true });
const r = await runStress({
stressPath: resolve('eval/animation-stress.json'),
fixturesDir: resolve('eval/animation-fixtures'),
artifactDir: resolve('.motionlint/stress'),
provider: 'YOUR_PROVIDER', // 'openai' | 'google' | 'ollama'
});
await writeFile('.motionlint/stress/SCORECARD.md', renderStressMarkdown(r), 'utf8');
console.error('Recall:', (r.broken_recall*100).toFixed(0)+'%, FPR:', (r.good_false_positive_rate*100).toFixed(0)+'%, gap:', r.avg_score_gap.toFixed(1));
});
"
打开 .motionlint/stress/SCORECARD.md,查看各模式的详细评分。
motionlint flow 的工作原理
静态截图无法告诉你流程中的动画和交互状态是否正常运行——只能看出最终画面是否正确。motionlint flow 填补了这一空白。
给定一段脚本化的用户旅程,它会:
- 通过 Playwright 在无头 Chromium 中运行这段旅程——像用户一样点击、输入、悬停、滚动和按键。
- 在每次交互后,通过 CDP 屏幕录制(
Page.captureScreenshotJPEG,每张约 8ms)在 750ms 内连续捕获 16 帧(间隔 50ms)。50ms 是人类视觉检测阈值的一半,也低于业内常见的 100ms 动画间隔下限——100ms 按钮按压等短动画会捕获到 2 到 3 帧中间状态。每次交互的连续帧还会进行像素差异比较,以测量输入到反馈的延迟——在连续帧时间窗口内没有可见反馈的交互会被确定性地标记出来。 - 将完整的 Playwright 视频记录为可供之后拖动查看的产物。
- 将每组连续帧合成为带标签的联系表——每个步骤占一行,帧排列在子行中。
- 将联系表发送给视觉 LLM,并使用一套针对流程设计的评估标准,检查:动画缺失、动画故障或卡顿、加载状态缺失、感知性能、可供性与状态变化、编排、流畅度、意外闪烁、导航连续性,以及对减少动态效果设置的遵循情况。
- 生成 Markdown 报告,其中包含逐步轨迹、按优先级排序的发现,以及底部的 “给 Claude Code 的提示词” 区块——将其粘贴到 CC 中,它就会直接根据这些发现采取行动。
多动画处理
单次录制可以捕获并分析多个并发动画。已在以下场景中验证:
- 仪表板显示(3 个并发动画:卡片逐个出现 + 数字递增 + 图表柱升高)
- 模态框叠加(背景淡入 + 模态框滑入并淡入 + 内部内容逐个出现)
- 丰富的表单反馈(焦点环 + 按钮按压 + 加载旋转图标 + 成功卡片)
- 滚动驱动(滚动进度条 + IntersectionObserver 区块显示动画 + 视差主视觉区)
LLM 能正确识别哪些动画出现故障,而不会误报正常运行的动画——请参阅验证质量表。
滚动驱动动画
对于带有滚动联动动画的网站,scroll <px> 步骤会通过 requestAnimationFrame 在连续帧时间窗口内平滑滚动,让每一帧都显示逐步变化的滚动位置,从而使 LLM 能在页面滚动时观察动画时序。
流程示例
# Inline DSL — semicolon-separated steps
motionlint flow \
--url http://localhost:3000 \
--steps "navigate /signup; click input#email; type input#[email protected]; click button[type=submit]; wait 2000; capture \"post-submit\"" \
--name signup-happy-path
# Or load a structured spec with expected_animations[] hints
motionlint flow --spec flows/signup.json --provider anthropic
# Pass team motion preferences (philosophy + inspirations + accepted defaults)
# Embedded into the prompt AND the report's CC handoff block.
motionlint flow --spec flows/signup.json --preferences flows/preferences.md
# Tighten the interval below 50ms for fine-grained timing review
motionlint flow --spec flows/signup.json --interval 30 --burst-ms 600
# Auto-detect: scan the page's animations, pick an interval that captures
# the shortest one with 4 frames inside it (clamped to [20, 100]ms).
motionlint flow --spec flows/signup.json --auto-interval
内联 DSL 参考
| 操作 | 格式 | 说明 |
|---|---|---|
| 导航 | navigate /pricing | 路径或完整 URL |
| 点击 | click button#start | CSS 选择器 |
| 悬停 | hover .feature | CSS 选择器 |
| 输入 | type input#[email protected] | 选择器=值 |
| 按键 | press Enter | 键盘按键 |
| 滚动 | scroll 800 | 像素;在连续帧时间窗口内平滑滚动 |
| 等待 | wait 500 | 毫秒 |
| 捕获 | capture "post-submit" | 进行一次显式的连续帧捕获,可选标签 |
默认情况下,每次交互后都会捕获一组连续帧。传入 --no-implicit-bursts 可仅在显式的 capture 步骤中捕获连续帧。传入 --no-record 可跳过视频录制。
仓库中附带三个可直接运行的示例流程:flows/signup.json、flows/loading-state.json 和 flows/preferences.md。
Animation Tuner 的工作原理
大多数 AI 编码工具都会从头生成动画。Tuner 能让你实时调整页面上已经运行的动画,并将更改作为结构化提示词交给你的编码 Agent。
motionlint tune http://localhost:3000 --open
具体流程:
- 在无头 Chromium 中打开你的应用,并运行一个检测脚本,挂钩主要的 TS 动画库(Motion One、GSAP、anime.js、@formkit/auto-animate、lottie-web),以及页面上运行的所有 CSS 转场和
@keyframes。 - 捕获检测到的每个动画:元素选择器、源库、计时参数和边界框。
- 在
.motionlint/tuner/index.html生成一个独立的交互式 HTML 页面(使用--open时会自动打开):- 每个动画都有一个实时预览区域(Shadow DOM — 无 iframe、无闪烁,并与源页面主题一致)。
- 提供用于调整时长/延迟/交错间隔/速度的滑块。
- 缓动预设下拉菜单 — 首先列出 Emil Kowalski 的强劲曲线(ease-out、ease-in-out、iOS drawer),然后是更柔和/装饰性的选项。
- 内联标准检查 — 每张卡片都会标出动画偏离动作标准之处(严重性徽标、修复方法、建议值),并显示标题评分。
- 每个动画都有一个用于记录设计理由的评论框。
- 导出一个 Markdown 文件和一条可直接用于 Claude-Code 的提示词,其中包含结构化的
changes[]JSON 块。将其粘贴到 CC 中,它就会编辑你的代码库以应用新参数。
$ motionlint tune http://localhost:3000
→ Capturing animations on http://localhost:3000…
detected 15 animation(s)
tuner → /Users/you/proj/.motionlint/tuner/index.html
open with: file:///Users/you/proj/.motionlint/tuner/index.html
动画标准 — motionlint audit
MotionLint 将 Emil Kowalski 的设计工程标准编码为一个确定性检查器——无需视觉模型、API 密钥,也不会产生费用。motionlint audit 会检测页面、读取每个动画实际运行时的计时/缓动/变换值,并为其评分:
| 类别 | 检查内容 | 标准 |
|---|---|---|
| 缓动 | UI 中使用 ease-in;有意设计的入场动画使用效果较弱的内置曲线 | 入场/退出 → 使用强劲的 ease-out cubic-bezier(0.23, 1, 0.32, 1);绝不使用 ease-in |
| 时长 | UI 动效超过 300ms 上限(模态框/抽屉为 200–500ms) | 180ms 的转场比 400ms 更利落;退出动画快约 20% |
| 物理感 | 以 scale(0) 开始的入场动画 | 任何内容都不应凭空出现——从 scale(0.95) + opacity: 0 开始 |
| 性能 | transition: all、动画化布局属性、意外的无限循环 | 仅动画化 transform 和 opacity——它们不会触发布局/绘制 |
| 一致性 | 手写缓动曲线过多;交错间隔超出 30–80ms 范围 | 曲线和时长应作为共享令牌管理;分组入场动画之间的交错间隔应为 30–80ms |
| 时长(成对) | 退出动画没有比入场动画更快(fadeIn 300ms / fadeOut 300ms) | 退出动画应比对应的入场动画快约 20% |
motionlint audit http://localhost:3000 --open # polished HTML report, scored 0–100
motionlint audit http://localhost:3000 --json audit.json --ci # machine-readable; non-zero on critical
添加 --layout,还可根据实时 DOM 测量结果检查布局(点击目标、文本大小、对比度、溢出)——依然是确定性的,也无需 API 密钥。
添加 --watch [dir],即可在 [dir](默认为 cwd)下的文件发生变化时重新运行审计,并在每次运行后打印带有变化量的评分——方便你迭代时实时查看结果。递归监视需要 macOS、Windows 或 Linux,以及 Node 20+。
报告会为每项检查结果配上一个前后对比面板;缓动检查结果会呈现实时 cubic-bezier 曲线对比,让修复效果一目了然,而不只是文字说明。同一套标准也用于 flow 审查提示词(让视觉检查结果引用具体规则),并会内联显示在 Animation Tuner 中。
MCP 服务——工具、资源、部署
MotionLint 随附一个基于 stdio 的 MCP 服务,让大模型 Agent 能在聊天中直接驱动它。motionlint mcp 子命令会启动该服务;客户端会在调用工具时启动进程。
在 Claude Code 中安装
已发布到 npm 的版本(推荐):
claude mcp add motionlint -- npx -y motionlint mcp
本地检出(开发期间很方便):
claude mcp add motionlint -- node /absolute/path/to/motionlint/dist/index.js mcp
注册后:
- 确认它已显示:
claude mcp list——motionlint应显示为running或available。 - 确保可以访问 API 密钥。MCP 服务会继承启动它的环境变量。最简单的方式是在当前项目目录中放置一个
.env文件——MotionLint 会在启动时自动加载。 - 首次运行:如果尚未安装,请运行
npx playwright install chromium。
然后在 Claude Code 中:
“使用 motionlint 检查本地应用在移动端和桌面端的表现,并告诉我最需要修复的 3 个问题。”
“在
http://localhost:3000/signup上运行 motionlint review_flow,步骤为click input#email; type input#[email protected]; click button[type=submit]; wait 2000; capture,并检查动画。”“在
http://localhost:3000/pricing上运行 motionlint tune_animations——我想微调卡片的悬停动画。”
暴露的工具
| 工具 | 功能 |
|---|---|
review_url(url, viewports?, provider?, model?, wait_for?, record?, format?, max_findings?, max_pr_annotations?, new_only?) | 在多个视口下对 URL 进行静态 UX 检查。返回 Markdown / JSON / SARIF 报告。 |
review_routes(base_url, routes, viewports?, ..., max_findings?, max_pr_annotations?, new_only?) | 对同一应用的多个路由进行相同的检查。 |
review_flow(url, steps?|spec_path?, preferences_path?, provider?, ...) | 对脚本化用户流程进行动画/交互检查。返回包含结构化 CC 交接内容的流程报告。 |
tune_animations(url, viewport_*?, settle_ms?, output?) | 检测页面上的所有动画,并生成交互式 HTML 调节器。返回文件路径。 |
get_latest_report(format?) | 返回最近一次检查/流程报告的内容。 |
资源:motionlint://reports/latest——最近一次报告的内容。
部署检查清单
部署 MCP 服务或与其他用户共享之前:
- 构建已更新。 运行
npm run build,然后确认dist/index.js存在。否则,motionlint mcp将无法启动。 - 目标机器已安装 Playwright Chromium:
npx playwright install chromium。postinstall 钩子会提醒你,但不会强制安装(我们不会在npm install时自动下载 300 MB 的二进制文件)。 - 可以访问 API 密钥——通过 shell 环境变量,或在 MCP 客户端启动时所在的工作目录中放置
.env文件。 - 对 MCP 接口进行冒烟测试。
npm test包含 MCP 冒烟测试,会启动服务、列出工具,并断言预期的工具接口。 - 未提交任何密钥。
.env已被 git 忽略;.env.example应为占位文件。推送前最好最后运行一次git diff --cached | grep -i 'sk-\|api_key'。 - 使用
claude mcp list确认服务已显示,且启动时没有报错。
CI 集成
# .github/workflows/ux.yml
- run: npm ci
- run: npx playwright install chromium
- run: npx motionlint review $STAGING_URL --ci --threshold critical --format sarif -o ux.sarif
- uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: ux.sarif }
当严重问题超过配置阈值(failOnCritical)时,MotionLint 会以 1 退出——将其接入状态检查。
它捕获什么 · 分析什么
捕获内容:
- 在三个默认视口(移动设备 375 / 平板 768 / 桌面设备 1440)下截取整页截图。可通过配置覆盖。
- 使用
--no-full-page截取首屏。 - 使用
--record录制导航和捕获过程的视频(Playwright.webm)。 - 捕获前执行交互序列:
click、hover、type、scroll、wait。 - 身份验证状态:Cookie、
localStorage和beforeNavigate脚本——均可在.motionlintrc.json中配置。
motionlint flow 联系表——每次交互后捕获的带时间戳帧,正是视觉模型所看到的内容。
**分析内容:**每张截图都会发送给视觉模型,并使用一份针对 UX 审查的系统提示词,涵盖十二个维度(hierarchy、spacing、alignment、typography、color、contrast、responsiveness、interaction、content、navigation、consistency、loading_state)。对于每个问题,模型都会返回:
{
"category": "hierarchy",
"severity": "critical | warning | suggestion",
"location": "above-the-fold hero",
"issue": "Primary CTA blends into the background gradient.",
"why_it_matters": "Users miss the conversion path on first scroll.",
"fix": "Increase background contrast or use a solid surface behind the button."
}
使用 --rules path/to/your-design-rules.md 覆盖提示词,注入项目专属的启发式规则。
每次审查捕获还会获取DOM 快照:显著元素(标题、CTA、输入框)会获得稳定引用(E1、E2、…)和测量所得的像素矩形,并列在提示词中,以便模型使用 "element_ref": "E3" 为发现提供依据。引用的元素会解析回对应的矩形,并在 HTML 报告的截图上绘制按严重性着色的边界框(在 Markdown 中报告为 Where: E3 at (x, y) w×h)。页面未列出的引用会被丢弃——模型无法标注未向它展示的内容。
使用 --format html 时,发现会呈现为一份可分享的报告,其中包含评分环、各维度明细,以及每项发现对应的问题 → 修复面板和标注后的截图:
配置参考
在仓库根目录下放置 .motionlintrc.json(或使用 motionlint.config.js / package.json 中的 "motionlint" 键):
{
"provider": "auto",
"fallbackProvider": "anthropic",
"fallbackModel": "claude-sonnet-5",
"viewports": {
"mobile": { "width": 375, "height": 812 },
"tablet": { "width": 768, "height": 1024 },
"desktop": { "width": 1440, "height": 900 }
},
"defaultViewports": ["mobile", "desktop"],
"waitFor": "networkidle",
"waitTimeout": 10000,
"screenshotDir": ".motionlint/screenshots",
"videoDir": ".motionlint/videos",
"reportDir": ".motionlint/reports",
"rules": null,
"record": false,
"maxFindings": null,
"maxPrAnnotations": null,
"memory": {
"enabled": true,
"path": ".motionlint/memory.json",
"baseline": ".motionlintignore",
"newOnly": false
},
"resources": { "maxConcurrentReviews": null, "providerCallsPerMinute": null, "maxTokensPerRun": null },
"ci": { "threshold": "warning", "failOnCritical": true },
"auth": { "cookies": null, "localStorage": null, "beforeNavigate": null }
}
审查结果数量控制
对同一路由重复运行审查,过去每次都会显示相同的问题。以下两种机制可让输出更聚焦:
- 单次运行输出上限 —
--max-findings N(或配置中的maxFindings)只保留每次运行中按严重程度排序的前 N 个问题,让 Agent 优先处理最重要的问题。报告中的Omitted行会显示被限制的问题数量。 - PR 注释上限 —
--max-pr-annotations N(或配置中的maxPrAnnotations;仅适用于 SARIF)每份报告最多输出按严重程度排序的 N 个结果,避免代码扫描上传的注释淹没 PR。被舍弃的数量会记录在 SARIF 运行的omitted_by_pr_cap属性中。 - 资源上限 —
resources.maxConcurrentReviews限制单个进程中同时运行的审查数量(例如 MCP 服务同时服务多个正在执行的 Agent),resources.providerCallsPerMinute则设置进程级滑动窗口的视觉大模型调用上限(用于控制服务商配额和支出;也适用于flow审查,其中每个--consistency样本都会计数)。两项默认均不限量,且只能通过配置设置。请注意两者会叠加:占用并发名额的审查也会受速率限制器约束,因此两项都设置较严格时,延迟会成倍增加。 - 成本上限 — 每次服务商调用的 token 用量都会被记录,并按次运行汇总(报告中显示
Tokens:行,SARIF 运行属性中显示token_usage)。--max-tokens N(或配置中的resources.maxTokensPerRun)用于设置每次运行的 token 预算:累计用量超过上限后,将跳过剩余视口,并在报告的skipped_viewports下列出。未报告用量的服务商仍会计入调用次数,但不消耗预算。 - 跨运行记忆 — 每个问题都会获得一个稳定 ID(由类别、元素位置和规范化后的问题文本生成哈希)。重复检测不止依赖完全匹配的哈希:通过类别同义词兼容性和规范词元重叠(基于真实跨运行数据校准的阈值),即使视觉大模型在不同运行中对同一故障使用了不同措辞,也能识别出来。每个 URL 的发现记录都保存在
.motionlint/memory.json中;重复出现的问题会标注为此前已在 N 次运行中出现,而非被静默丢弃。使用--new-only可仅查看增量。若要永久忽略某个问题,请将其 ID 复制到.motionlintignore(每行一个哈希,可使用#注释和行尾备注)。使用--no-memory可禁用所有记忆功能。
SARIF 输出会将问题 ID 作为 partialFingerprint 携带,因此 GitHub 代码扫描可以原生地在不同运行和 PR 之间对同一问题去重。
对同一项目同时运行多个审查是安全的:记忆存储会在可检测过期状态的文件锁(memory.json.lock)保护下更新,因此并行运行不会覆盖彼此记录的问题。如果锁卡住,也不会导致审查失败——短暂等待后,运行会发出警告并在不使用锁的情况下继续。
使用场景
- 合并前的 UX 防护。 没有设计师的独立开发者或 2 人初创团队,可在 CI 中运行
motionlint review https://pr-123.preview.example.com --ci --threshold critical;达到警告级别或更严重的问题会阻止合并,直到你至少查看过这些问题。 - Claude Code 中的 MCP 设计同事。 将 MotionLint 添加为 MCP 服务,然后向 CC 提问:“检查本地应用的移动端和桌面端,并告诉我最值得修复的 3 个问题。” CC 会调用工具,并在同一对话中获取带注释的反馈。
- 持续质量监控。 安排每晚运行 cron(
motionlint review https://prod.example.com --format sarif -o ux.sarif),并在代码扫描仪表板中显示 SARIF,以便在生产环境出现回归后的第二天早上及时发现。 - 刚上线功能的动画 / 流程 QA。
motionlint flow会像真人一样通过 Playwright 执行脚本化用户旅程,在每次交互时捕获连续帧、录制视频,并请大模型检查所捕获帧之间的动画行为。 - 实时调整动画并交接给 Claude Code。 捕获页面上的每段动画,通过滑块实时调整时长 / 缓动 / 延迟,并导出 Claude Code 可直接处理的结构化提示词。
项目布局
src/
capture/ Playwright capture (screenshot, mosaic, DOM snapshot) + interaction sequences
providers/ Vision LLM providers (ollama, anthropic, openai, google, mock) + self-consistency wrapper
analysis/ Rubric-style UX prompt + JSON parser + rule injection
report/ Markdown / JSON / SARIF report generators
eval/ Tiered eval harness (L1/L2/L3 fixtures, scorer, runner, report)
flow/ Flow runner — spec parser, capture orchestrator, animation-aware report
tuner/ Animation Tuner — extractor, instrumentation script, Shadow-DOM render
mcp/ MCP server for Claude Code
cli/ Commander.js commands + terminal output
config/ cosmiconfig loader + .env loader
demo/ TS animation showcase used as a review target
flows/ Sample flow specs (signup, loading-state) for `motionlint flow`
eval/fixtures/ Labelled HTML pages with seeded UX faults at three complexity levels
test/ Node test runner unit + integration tests
路线图
v0.1(本次发布) — 已发布:
- 三个 CLI 命令:
review、flow、tune,以及 MCP 服务(motionlint mcp)。 - 五种视觉提供商:Anthropic、OpenAI、Google、Ollama、mock。
- 支持多视口静态审查,包括拼接图捕获、DOM 测量旁路通道、自一致性采样,以及基于同义词图的软关键词评分。
- 分层评估框架(L1 / L2 / L3),包含 21 个已标注样例,以及供下游大模型编码工具使用的结构化
next_actions[]JSON。 - 通过 CDP 屏幕录制,以帧间隔 50ms进行流程审查(连续帧突发采集:16 帧 × 750ms),支持多动画和滚动驱动的动画。
- 动画调节器支持 Shadow DOM 预览、实时滑块、缓动预设和 Claude Code 导出。
- 动画压力测试框架已验证,在 12 种模式的 24 个样例上达到 100% 召回率 / 0% 误报率。
- 团队动画偏好 Markdown(
--preferences)会嵌入大模型评分标准和 CC 交接块中。 - 自动间隔扫描(
--auto-interval)会根据页面上检测到的最短动画选择帧间隔。 - 支持 GitHub 代码扫描的 SARIF 输出。
v0.2(进行中) — 已发布内容:
- Token 用量统计 + 每次运行的成本上限(
--max-tokens/resources.maxTokensPerRun;每份报告中都包含Tokens:行)。 - 自动发现路由(
--discover-routes:sitemap.xml + Next.js 应用目录)。 - 带注释的边界框:在提示词中包含 DOM 元素引用,并在 HTML 报告的截图上绘制检查结果。
- 交互状态网格(
--state-grid:每个元素包含默认 / 悬停 / 聚焦 / 激活状态,呈现在一张带标签的图像中)。 - 提供商评分卡历史记录,支持按模型检测回归(
.motionlint/eval-history.json)。 - 基于评估
next_actions的闭环提示词演进(eval --evolve→ 在审查提示词中加入已学习的启发式规则)。 - 两条新增审查规则:交错间隔范围(30–80ms)和退出速度比进入快约 20%。
v0.2(接下来):
- GitHub Action 包装器(
motionlint-action)。
致谢
MotionLint 建立在他人的工作之上:
- Emil Kowalski —
motionlint audit背后的动画标准、调校器的缓动预设,以及流程审查准则,均提炼自他的设计工程文章和 animations.dev 课程。他的开源 UI 库——sonner(Toast 通知)和 vaul(抽屉)——是这些规则所描述动效的鲜活参考实现。MotionLint 是一个独立项目,与 Emil 无关联,也未获其认可。 - ctx(ctx.rs)——本地编码 Agent 历史搜索工具。开发跨运行记忆层时,我们用它研究如何让发现结果在 Agent 的多次运行间保留(或消失);这些实验直接影响了发现 ID 和基线设计。
许可证
MIT © Resila Technologies Inc.
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。