关于 design-polish
用于优化 Flutter 移动应用界面的工作流技能,强调沿用现有视觉风格。它指导开发者通过模拟器观察、针对性修改和独立评估来迭代界面。
主要功能
- 01依据参考界面确定视觉基调
- 02通过 Android 模拟器检查界面
- 03诊断具体 UI 问题
- 04针对性修改 Dart 组件
- 05依据独立评估结果迭代
适用场景
- 01改善 Flutter 界面的视觉层级
- 02通过模拟器检查不同界面状态
- 03根据评估反馈迭代视觉修改
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ chunkytofustudios/ flutter-skills --skill design-polish安装后在 Claude Code 中输入/design-polish确认已加载。
详细介绍
设计润色(Flutter)
为 Flutter 移动应用润色屏幕,改善视觉层级、可读性和分区清晰度,让用户一眼就知道如何使用应用。工作以明确的设计主张为导向、有证据支撑且范围清晰:每一轮都以独立评估者的评判结束,而不是由你自行评估。
设置
如果用户没有指定屏幕,请询问:
- “你想润色哪些屏幕?请提供路由名称(例如
/settings、/profile)或lib/下的组件文件路径。”
应用必须在 Android 模拟器中运行。使用 android-emulator 技能——此工作流中的每张截图、每次点击和滑动,以及每次无障碍树转储,都必须通过它完成:
scripts/emu.sh health # confirm device, AVD, foreground app
scripts/emu.sh boot # if not running
scripts/emu.sh run # build & install in background
scripts/emu.sh wait-run # block until attached
确立设计基调
在处理任何屏幕之前,只做一次。 跳过这一步是造成设计不一致的最大原因——你的改动单独看起来没问题,放到应用其他部分旁边却显得格格不入。
- 找到一个参考屏幕。 按以下顺序尝试:
- 用户提到了一个设计完善的屏幕(“设置页很棒,把其他页面也润色成这样的风格”)。使用该屏幕。
- 首页:
lib/main.dart或路由配置(GoRouter、AutoRoute 等)中的MaterialApp.home、initialRoute,或BottomNavigationBar的第一个标签页。 - 文件名为
home_page.dart、home_screen.dart、dashboard.dart的文件。
- 阅读其源码。 打开该屏幕的 widget 文件,以及它从
lib/theme/、lib/widgets/导入的所有内容和任何自定义ThemeExtension。记录ColorScheme、TextTheme、间距常量、圆角值,以及任何共享布局基元。 - 在模拟器上截屏。 如有需要,使用
tap-label导航,然后运行scripts/emu.sh screenshot并读取输出的路径。滚动并截取每种状态。 - 用 3–5 条具体要点写出设计基调。 哪些特征让应用的屏幕一看就像这个应用,而不是通用的 Material 默认样式。选择真正能体现参考屏幕特点的维度——描述实际存在的设计,而不是你希望它具备的设计:
- 氛围——例如沉静克制、活泼有活力、大胆街机风、柔和温馨、复古、霓虹。
- 字体——使用哪些字体系列和字重,分别应用在哪里。固定字体列表。
- 色彩——完整描述
ColorScheme:配色克制还是富有表现力、纯色还是渐变、饱和度水平、语义令牌,以及任何ThemeExtension。 - 表面——卡片背景、边框、圆角半径、海拔高度/阴影、模糊效果。
- 层级手段——应用如何突出重要性:字重、颜色、间距、边框、强调色、插画,或这些手段的组合。
- 动效——无动效、细微的 Material 默认动效,或富有表现力的动效(自定义曲线、Hero 转场、Lottie/Rive)。
如果无法有把握地确立设计基调——没有明确的参考屏幕、候选屏幕看起来尚未完成,或代码库中的主题风格不一致——请停止并询问开发者:
“我无法根据代码库确定明确的设计基调。可以告诉我一个设计完善的参考屏幕吗(文件路径或路由名称)?我需要据此确保改动与现有风格一致。”
未确立设计基调前,不要继续。只有明确润色的目标风格,这套润色工作流才能奏效。
品牌与设计系统
将你上面确立的设计基调作为首要准则。从代码库中提取具体约束并遵循:
字体。 找出 theme.textTheme 中使用的字体系列(通常通过 google_fonts、flutter_fonts 或 pubspec.yaml 中打包的 .ttf 资源)。不要添加新字体。缺失的排版令牌(例如未使用的 labelSmall)必须通过 ThemeData 接入并保持一致地应用——不要使用内联的 TextStyle(...) 字面量。
颜色。 使用现有的 ColorScheme 令牌。你最多可以通过 ThemeExtension 添加 2 个新的语义令牌(例如 success、warning),并在本次会话中应用到你处理的每个屏幕。不要在各个 widget 中零散使用一次性的十六进制颜色字面量。
组件。 在 lib/widgets/ 或 lib/components/ 中已有自定义 widget 时,请重复使用。对于基于 Material 的应用,优先使用 SDK widget(FilledButton、Card、ListTile 等),而不是自己实现;对于拥有成熟自定义 widget 库的应用(常见于游戏和品牌风格浓厚的实用工具应用),应沿用现有模式,而不要引入不合时宜的标准 Material widget。可以使用小型实用工具包;不要在润色过程中引入新的组件库。
间距与圆角。 找出已有的间距刻度(通常是 lib/theme/ 下的 Spacing 扩展或 EdgeInsets 常量)以及圆角值。不要更改它们——即使单独来看某些选择有其道理,变化也会显得不一致。
工作流(逐个屏幕)
1. 观察
通过 android-emulator skill 操作屏幕:
scripts/emu.sh ui-list— 查看可操作的界面元素;默认优先使用此命令,而不是截屏。scripts/emu.sh tap-label "..."— 导航到目标屏幕。scripts/emu.sh screenshot— 截取初始状态。读取输出的路径。- 滚动(
swipe)、打开标签页、展开面板、关闭对话框(tap-label "Close")——像真实用户一样操作。为每个有意义的状态截屏。 - 阅读屏幕的 widget 源码,以及它组合使用的每个共享 widget 的源码。
2. 诊断
写出 3–7 个具体问题。每个问题都必须指出确切的 widget 和问题所在:
- "
TabBarView和侧边Drawer都使用surfaceContainer——两者之间没有明显的视觉边界。" - "所有正文都使用
bodyMedium和FontWeight.w400——无法区分主要数据和标签。"
以下说法不合格:“对比度不够”“感觉很杂乱”。
3. 修复
对 Dart 源码进行有针对性的 widget 修改,不要重写。一次只处理一个方面(先层级,再间距,最后颜色强调),不要一次性全部修改。
完成每一组逻辑相关的编辑后,重新连接并截屏验证:
scripts/emu.sh kill-run && scripts/emu.sh run && scripts/emu.sh wait-run
scripts/emu.sh screenshot
对于纯视觉改动的快速迭代,请用户在自己的终端中持续运行 flutter run(由 IDE 在保存时驱动热重载)——然后你只需截屏。默认的安全做法是结束运行再重新运行,但每轮会耗时 30–60 秒。
如果改动效果不好,请还原并尝试其他方案。不要在有问题的方向上不断叠加修复。
4. 评估(子 Agent)
再次与页面交互,截取“之后”的截图。然后使用 Agent 工具,采用最新的 Opus 模型,按以下提示启动一个评估子 Agent(填写 SCREEN_NAME 和 NAVIGATION_HINT):
评估提示词:
你是一名独立的设计评估者,与做出这些修改的 Agent 毫无关联。请以怀疑、严苛的态度进行评审。你正在评审 Flutter 移动应用中的一个屏幕。
应用已在 Android 模拟器中运行。使用 android-emulator 技能进行交互:
- 使用
scripts/emu.sh ui-list查看哪些元素可供操作 - 使用
scripts/emu.sh tap-label "..."导航至 SCREEN_NAME(NAVIGATION_HINT) - 使用
scripts/emu.sh screenshot截取每个状态的屏幕截图——读取输出的路径 - 滚动、点击每个标签页、展开面板、打开菜单——像真实用户一样进行交互。截取每个有意义状态的屏幕截图。
按以下标准分别打 1–10 分,并附上 2–3 句理由:
设计质量(权重高): 整体是否协调,还是仅仅由零散元素拼凑而成?颜色、字体、布局和间距能否共同营造出鲜明的氛围和风格?
原创性(权重高): 是否有经过深思熟虑的定制设计,而非 Material 默认样式和 AI 常见套路?AI 垃圾设计的迹象(闪光图标/✨、“AI 驱动”/“魔法”徽章、毫无意义的装饰图表、不符合整体视觉语言的装饰元素)= 自动不通过。
工艺(权重中): 字体层级、间距一致性、色彩协调、对比度、对齐。基础能力检查——未通过即说明基本功不过关。
功能性(权重中): 用户能否轻松找到操作、完成任务,并理解界面而无需猜测?点击目标是否 ≥ 48dp?文字在设备 DPI 下是否清晰可读?
评分标准:9–10 = 达到 Apple Design Award 水准,或同类别(游戏对工具类)的 App Store 榜单顶尖应用水准,几乎不给出这样的分数。7–8 = 专业扎实,无明显问题。5–6 = 普通、采用默认 Material 组件、缺乏特色。3–4 = 存在明显问题。1–2 = 无法正常使用。
任何一项得分 >7 时,都要指出一件资深设计师仍会提出的批评。如果想不出来,就降低分数。
用 3–5 条要点列出尚存问题的批评意见(指出具体控件,不要含糊其辞)。然后给出结论:PASS(全部 ≥7)、ITERATE(任一高权重项 <7)、FAIL(任一项 <5)。
格式:
DESIGN_QUALITY: X/10 — ...
ORIGINALITY: X/10 — ...
CRAFT: X/10 — ...
FUNCTIONALITY: X/10 — ...
CRITIQUE:
- ...
VERDICT: PASS/ITERATE/FAIL
5. 根据结论采取行动
- PASS: 继续处理下一个屏幕。
- ITERATE: 将评估者的批评作为新的诊断依据——不要从头重新诊断。返回步骤 3(修复)。
- FAIL: 考虑还原到“之前”的版本,并尝试完全不同的方案。
- 每个屏幕最多评估 3 轮。达到上限时,保留得分最高的版本。
层级工具包
根据布局需要灵活运用——不要在每个屏幕上都套用所有方法。以下令牌适用于 Material 3;如果应用使用 Cupertino、自定义主题类或经过大量主题定制的游戏控件库,请转换为应用对应的等效样式:
- 分隔线/边框用于区分各个区块(
Divider、OutlinedBorder、1pxcolorScheme.outlineVariant)。 - 背景对比度用于区分不同区域(
surface、surfaceContainer和surfaceContainerHighest)。 - 字体粗细/大小用于体现重要性(
titleLarge>titleMedium>bodyMedium>labelSmall)。 - 间距——相关项之间间距较小(
Gap(4)/Gap(8)),不相关项之间间距较大(Gap(24)/Gap(32))。 - 颜色作为强调标识——主色用于唯一的主要操作;用
onSurfaceVariant弱化次要内容。 - 关键卡片的左侧强调线(在
Container装饰中使用 2–3pxBorder(left: BorderSide(color: primary)))。 - 标签指示器——
TabBar的活动状态必须一目了然;非活动状态应通过unselectedLabelColor弱化。
反模式
偏离既定基调的情况(原创性评分 ≤ 4)
让屏幕看起来像 AI 生成的最快方法,就是添加不属于 这款 应用的视觉元素。渐变、动画、主视觉插图、装饰性模糊、StadiumBorder 胶囊形元素、自定义滚动条、粒子效果、视差、lottie——这些元素在合适的场景中各有用处,但放在不合适的场景里就成了视觉垃圾。参考标准是你前面确立的设计基调,而不是一套固定的审美规范。
原则:不要引入既定基调中尚不存在的视觉元素。 与现有设计保持一致。如果应用其他部分都是扁平风格,就不要添加渐变。如果应用其他部分都很平静,就不要添加粒子爆发效果。如果应用其他部分使用描边卡片,就不要引入玻璃拟态模糊层。
如果你认为问题出在基调本身,那就不是润色任务——请告知用户。朝着应用并不具备的基调润色,只会让屏幕看起来像是来自另一款应用。
通用危险信号(出现任意一项 = 原创性评分为 2)
无论是游戏、工具、效率应用还是其他类型,这些都属于视觉垃圾:
- 闪光/✨图标、“AI 驱动”/“魔法”/“智能”徽章,或其他作为装饰使用的产品内 AI 品牌元素
- 不代表真实数据、毫无意义的装饰性图表、迷你趋势图、仪表盘或曲线图
- 内部风格矛盾——整体扁平的设计中加入装饰性阴影、高浮起布局中硬塞一个扁平面板,或在一个所有界面都使用矩形元素的应用中,出现一个所有元素都带圆角的屏幕
- 背后没有真实异步等待过程的
Shimmer/骨架屏加载器 - 用户每天都会打开的屏幕上,突然出现“欢迎回来!”问候语、主视觉横幅或类似引导页的标题
- 功能变更——路由结构调整、移除功能或更改 Widget API(不在润色范围内;请标记出来,不要悄悄改动)
嗅探测试
- “该类别中荣获 Apple Design Award 的应用的设计师,会认为这是装饰性噪音吗?”
- “有人刷过这个界面时,会觉得它像是 AI 生成的吗?”
如果任一问题的答案是肯定的,就撤销改动。
注意事项
ThemeData和热重载并不总是配合得当。 对ThemeData、ColorScheme或TextTheme的修改经常无法通过热重载生效——Widget 会继续使用过时的颜色或排版,直到完整重启。如果主题变更“没有显示出来”,请先执行停止运行并重新启动的流程,再调试修改内容。google_fonts会静默回退。 如果没有网络连接或构建缓存尚未准备好,google_fonts会改用系统默认字体,导致排版看起来很普通。如果更改字体后文本突然看起来不对,请确认设备已联网并重新构建,然后再继续迭代。- 状态栏元素会干扰前后对比图。 不同截图中的时钟、电池和通知图标可能不同。请比较应用界面,而不是状态栏——判断变化时忽略状态栏像素。
- 内联
TextStyle(...)往往是“不一致”的罪魁祸首。 如果某个屏幕看起来与整体基调不符,在修改主题之前,先搜索 Widget 中的内联TextStyle、Color(0x...)和硬编码EdgeInsets字面值——主题通常没有问题,是 Widget 绕过了主题。
流程规则
- 一次处理一个屏幕。完成整个流程(观察 → 诊断 → 修复 → 评估)后再继续。
- 新增的
ColorScheme或TextTheme令牌必须应用到本次会话中修改的每个屏幕——不要造成局部不一致。 - 对共享 Widget 和
ThemeExtension:修复一次,然后为每个使用它们的屏幕重新截图,确认连带效果。 - 每修改完一个屏幕,都要运行
dart format .和flutter analyze(或fvm flutter analyze)。先修复 lint 问题再进行评估——它们往往会暴露真正的问题。 - 在宣布屏幕完成前运行
flutter test,以防 Widget 测试引用了你修改过的文本或结构。