Impeccable 原生端适配实战:adapt 命令的 native 变体如何把"放大手机 UI"变成跨设备、跨平台的重构
Impeccable 是一套为 AI 编程助手(Agent)提供设计能力的设计语言技能包,其中 adapt 命令负责把已有设计迁移到新的设备、屏幕或平台语境。本文聚焦其原生端参考手册 adapt.native.md(适配 iOS / Android / adaptive 项目),完整拆解它"评估挑战 → 选择策略 → 实现验证"的工作流,并结合仓库中的平台参考(ios.md / android.md)、命令路由规则与 context.mjs 脚本实现,说明这条 Playbook 是如何被技能系统自动选中和执行的。读完后你将掌握:原生适配的四类典型场景(手机→平板、横屏/折叠屏、iOS↔Android、Web→原生)的具体策略、可直接复用的平台惯用法对照表,以及"尺寸类驱动结构、硬件做真值验证"的落地原则。
adapt.native 手册在 Impeccable 技能中的定位
adapt 是 Impeccable 技能 Commands 表中的一条 Fix 类命令,官方描述为 "Adapt for different devices and screen sizes",并明确分成两套参考手册:Web 版 adapt.md 与原生版 adapt.native.md(.agents/skills/impeccable/reference/ 下的文件是同一内容的分发包副本,见 adapt.native.md)。技能的路由规则写在 SKILL.src.md 中:
- 无参数调用
$impeccable时读取 routing.md 呈现上下文感知菜单,绝不自动执行命令; - 显式或可推断的命令(如"把这个 iOS 界面做成 iPad 版")则加载对应参考文件,且原生平台上加载 native 变体;
adapt命令头部声明了执行前必须补齐的上下文:目标平台/设备与使用场景(> Additional context needed: target platforms/devices and usage contexts)。
手册开篇即给出整条 Playbook 的核心断言:
Adapt an existing native design (
ios/android/adaptive) to a different context: another device class, orientation, platform, or origin. The trap is treating adaptation as scaling. The job is rethinking the experience for the new context, inside the platform conventions of ios.md / android.md.
即:适配的陷阱是把"适配"当成"缩放"(scaling)。真正的工作是为新语境重新思考体验,并且必须约束在目标平台的约定之内——这也是为什么手册要求在执行前,如果 Setup 阶段尚未读取过目标平台参考(ios.md 或 android.md),必须先读。
技能系统如何知道该走 native 分支
平台判定来自项目根目录 PRODUCT.md 的 ## Platform 字段,合法取值为 web / ios / android / adaptive(跨平台,同时面向两个原生端;写成 ios, android 两个目标也会被解析为 adaptive)。解析逻辑在 context.mjs 中,当字段值无法识别时会输出警告并把项目按 web 处理。随后 Setup 阶段的 context.mjs 会按平台加载对应的平台参考文件,核心实现是 loadNativePlatformReferences:
function loadNativePlatformReferences(platform) {
const names = platform === 'adaptive'
? ['ios', 'android'] // adaptive 项目两份平台参考都要读
: platform === 'ios' || platform === 'android'
? [platform]
: [];
// ...读取 SKILL_REFERENCE_DIR 下对应的 <name>.md 并注入会话上下文
}
从源码结构看,adaptive 项目会同时注入 ios.md 与 android.md 两份平台规则,这解释了为什么跨平台应用(Flutter、React Native、Expo)做平台迁移时,Agent 已经同时持有两套平台的"规则书"。
还有一个容易被忽略的事实:原生项目不适用 Impeccable 的浏览器侧工具。routing.md 明确指出 live 与 detect.mjs 是 web-only;context.mjs 的 automaticHookMode 对 ios / android / adaptive 平台直接返回 'none'(设计检测钩子不启用),appendDetectorFallback 也注释了 "The detector reads HTML and CSS, so native projects get nothing"。换句话说,原生端的质量把关不靠 HTML 规则引擎扫描,而是靠本文后面讲的平台 slop 测试 + 真机验证这条人工/Agent 复核路径。
第一步:评估适配挑战(Assess Adaptation Challenge)
手册把适配前的调研压缩成三个问题,分别回答"从哪里来、到哪里去、哪里会坏":
- Source context(源语境):它原本是为谁设计的、做了哪些假设?只面向手机?只面向竖屏?只用了某一个平台的惯用法?还是一套网站改过来的?
- Target context(目标语境):目标设备类(手机、平板、折叠屏)、屏幕方向、平台,以及使用姿态——是"单手持机在路上"还是"双手持握在固定场景"?
- What breaks(什么会坏):哪些导航放不进目标设备?哪些布局只会"被拉长"而不会"重新组织"?哪些手势或控件在目标平台上根本不存在?
这三问对应了原生适配最常见的三类失败:把 iOS 的 Tab bar 原样搬到 Android、把竖屏单列布局在横屏上直接拉伸、把 Web 的 hover 交互留在触屏上。评估阶段不写任何代码,它的产出是一张"断裂点清单",决定后续从哪几个策略入手。
四类适配策略
策略一:Phone → Tablet(手机 → iPad / 大屏)
手册的第一原则是 Restructure, don't stretch(重构结构,而不是拉伸布局)——"平板上的放大版手机 UI"是明确的失败模式。具体做法:
- 用尺寸类切换结构:iOS 用 size classes、Android 用 window size classes,根据窗口尺寸类切换整体结构,而不是判断具体机型;
- 导航形态随之改变:iOS 的 Tab bar 在 iPad 上保留或转为侧边栏(sidebar);Android 的 Navigation bar 在展开宽度(expanded width)下变为导航导轨(rail)或抽屉(drawer);
- 用满宽度:手机上的单列表格/全屏 sheet,在平板上变成分栏(split view / master-detail,列表+详情并排)、多列网格;手机用 bottom sheet 的场景,平板上可以改为 popover;
- 多任务是一种尺寸,不是边角情况:iPad Split View 与 Android 多窗口随时会把一个"手机宽度"的窗口塞给平板应用。以尺寸类驱动的布局天然同时覆盖"全窗平板"与"分屏手机宽度"两种形态,无需特判。
这一点与 android.md 的硬规则一致:"Never ship a phone bottom-bar untouched on a tablet"(绝不把手机底部导航栏原封不动地发到平板上)。
策略二:Orientation & Foldables(横屏与折叠屏)
- 横屏要重构,不是裁剪:并排面板(side-by-side panes)、控件重新定位(repositioned controls);永远不做裁剪(clip)或加黑边(letterbox);只有当任务本身确实要求时才锁定屏幕方向。
- 折叠屏(Android)以姿态和铰链为响应信号:通过 window size classes 感知设备处于折叠(folded)、展开(unfolded)还是支架(tabletop)形态。测试矩阵必须覆盖这三种状态。
策略三:Platform → Platform(iOS ↔ Android 互迁)
核心原则一句话:Translate idioms, never transplant(翻译惯用法,绝不移植控件)。手册给出了一张完整的 iOS ↔ Android 惯用法对照表,这是本手册信息密度最高的部分:
| iOS | Android |
|---|---|
| Tab bar | Navigation bar / rail / drawer |
| 边缘左滑返回、返回箭头(back chevron) | 预测式返回手势(Predictive Back gesture)/ 返回按钮 |
| Switch、分段控件、系统选择器 | Material 开关、chips、Material 选择器 |
| Action sheet | Bottom sheet / Material dialog |
| SF Symbols、SF Pro、Dynamic Type | Material Symbols、Roboto、sp 缩放 |
| 语义系统色、materials(材质) | Material 颜色角色(color roles)、色调化 elevation(tonal elevation) |
| 系统 push / sheet 转场 | Container transform、shared-axis、fade-through |
迁移的正确姿势是:用目标平台的词汇重建导航与控件,然后把品牌的表达层——配色意图(palette intent)、字体强调(type accent)、动势个性(motion personality)——通过目标平台的主题系统带过去。这与两份平台参考的立场完全一致:ios.md 说品牌通过 "tint、type、motion、content" 这层平台留给你的空间表达;android.md 说品牌通过 Material 的 theming(color roles、type scale、shape、motion)表达,且"穿着 Android 皮肤的 iOS 应用"(bottom-only 导航、无视系统返回手势的返回箭头、Cupertino 风格的开关和弹窗)是最典型的 Android slop。
策略四:Web → Native(把网站或 Web App 移植到原生)
原则是 Reconform, don't reflow(重新定型,而不是重新流式排版),做四组替换:
- Web 导航(顶栏、侧栏、面包屑)→ 平台的导航模型(iOS 的 Tab bar + 导航栈 / Android 的 Navigation bar + 顶层应用栏);
- HTML 形态的控件(div 按钮、自定义下拉)→ 平台控件(见上表);
- Hover 依赖的交互 → 触摸优先的交互(原生没有可靠的 hover);
- px 字号 → Dynamic Type(iOS)/ sp 单位(Android),让文本跟随系统字号设置。
移植完成后,整份目标平台参考就是验收标准:ios.md 的 "iOS slop test"(一个熟练 iPhone 用户会不会在不符合规范的控件上停顿?典型破绽是"从网站搬来的":自造导航栏、自定义返回手势、Web 形状的按钮、hover 依赖的交互)与 android.md 的 "Android slop test" 就是移植结果的及格线。
第二步:实现与验证(Implement & Verify)
手册给出三条实现约束和一条验证矩阵:
- 结构由尺寸类驱动,禁止机型判断——"Drive structure from size classes / window size classes, never from device-model checks"。按
iPad Pro 13"之类机型分支的布局无法覆盖分屏、外接显示、未来新设备;尺寸类是平台提供的稳定抽象。 - 每种新形态都要尊重安全区与窗口内边距:刘海/灵动岛(notch)、折叠屏铰链(hinge)、状态栏、键盘(IME)都会吃掉屏幕边缘。对应到平台规则:ios.md 要求所有布局落在 safe-area insets 内、任何控件不得压在刘海/圆角之下;android.md 要求 edge-to-edge 模式下应用 status bar / navigation bar / display cutout / IME 四类 insets。
- 模拟器给广度,真机给真值:模拟器上跑广度(breadth),真机上要真值(truth)。最低验证矩阵是每个交付平台各一台手机 + 一台平板、两种方向、支持分屏的分屏形态;折叠屏再加折叠/展开/支架三态。
两份平台参考还把"真值验证"落实到了可执行命令上,可直接复制使用:
-
iOS(见 ios.md 的 "Verifying the build"):截图一律来自模拟器而非浏览器,构建运行后用
xcrun simctl io booted screenshot <path>抓取(多台设备同时运行时用
xcrun simctl list devices booted取目标 UDID 替换booted,显示名可能撞车,UDID 不会);Dark Mode 与 Dynamic Type 必须进验证路径,xcrun simctl ui booted appearance dark切换外观,再在大号 Dynamic Type 下检查固定布局会隐藏的截断问题。 -
Android(见 android.md 的 "Verifying the build"):
adb exec-out screencap -p > <path> # 多设备时用 adb -s <serial> 指定 adb shell cmd uimode night yes # 切换深色主题 adb shell settings put system font_scale 1.3 # 放大字号(完事后改回 1.0)字号放大一步能抓出固定布局隐藏的标签截断。
-
两份参考都以同一句话收尾:Simulators/Emulators give breadth; posture, gestures, and performance need hardware(模拟器给广度;姿态、手势、性能要靠硬件),并要求在产出证据时说明是哪类设备生成的。
验证通过、"适配在每种语境下都显得原生"之后,手册的交棒指令是:hand off to $impeccable polish for the final pass(交给 polish 命令 做上线前最后一轮质量收尾)。注意分工:adapt 负责"语境正确性"(结构、导航、平台惯用法),polish 负责"最后打磨",两者不是同一个环节。
五条 NEVER:原生适配的绝对禁令
手册结尾的禁令列表(原文语义完整保留):
- 不要把拉伸的手机布局发到平板上(Ship a stretched phone layout on a tablet);
- 不要把一个平台的控件或导航移植到另一个平台(Port one platform's controls or navigation onto the other);
- 不要在小尺寸设备上隐藏核心功能——如果功能重要,就让它可用(if it matters, make it work);
- 不要靠锁定屏幕方向来逃避布局 bug(Lock orientation to dodge a layout bug);
- 不要只信模拟器——姿态、手势和性能需要真机验证(posture, gestures, and performance need hardware)。
这五条禁令与评估阶段的"What breaks"三问、策略阶段的"never transplant"形成闭环:评估找断裂点,策略防惯性移植,禁令兜底防捷径。
延伸阅读:手册与仓库源码的对应关系
| 环节 | 文档/代码位置 |
|---|---|
| native 适配 Playbook(本文主体) | adapt.native.md(分发副本 adapt.native.md) |
| Web 版 adapt(对照) | adapt.md |
| iOS 平台规则(slop test、安全区、Dynamic Type、simctl 验证命令) | ios.md |
| Android 平台规则(Material 3、48dp 目标、adb 验证命令) | android.md |
| 命令表与 native 变体路由 | SKILL.src.md |
| 无参数时的上下文菜单与 web-only 工具边界 | routing.md |
平台解析(## Platform 字段、adaptive 判定) |
context.mjs |
| 按平台加载平台参考(adaptive 加载双端) | context.mjs |
| 原生平台禁用设计检测钩子 / 手动检测回退 | context.mjs、context.mjs |
适用前提与限制:本手册面向的是 PRODUCT.md 中 ## Platform 声明为 ios / android / adaptive 的原生项目(SwiftUI/UIKit/Compose/Views/React Native/Expo/Flutter 等),不涉及 Web 响应式适配(那是 adapt.md 的范围);其验证环节依赖 Xcode 模拟器与 adb 环境,xcrun simctl 与 adb 命令分别要求 macOS 开发环境与已连接的 Android 设备/模拟器。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00