native-feel-skill: 跨平台原生质感桌面应用的 Agent Skill
> 一句话版本: yetone(avante.nvim 作者)把 Raycast 2.0 的技术架构和反编译结果打包成了一个 Agent Skill —— 任何 AI 编程助手装上后就知道怎么写出"感觉像原生"的跨平台桌面应用。不是 Electron 加皮肤,是真·四层架构。
- 来源: https://github.com/yetone/native-feel-skill
- 日期: 2026-05-14(Raycast 2.0 公开 Beta 发布同日)
- 作者: yetone(中国开发者,avante.nvim、avante-css 作者)
- 安装方式:
npx skills add yetone/native-feel-skill -g - 许可: MIT
背景:Raycast 2.0 的架构革命
Raycast 昨天(2026-05-14)刚刚发布了 2.0 公开测试版,这是它有史以来最大的更新 —— 从纯 macOS 原生 AppKit 应用,彻底重写成了 macOS + Windows 跨平台应用。
技术栈:TypeScript + Swift + C# + Rust + Node + React。
yetone 在发布的当天就反编译了 Raycast Beta.app v0.60.0,和 Raycast 官方的技术博文对照,提炼出了这个 Skill。
内容结构
native-feel-skill/
├── SKILL.md # Agent 入口
├── references/
│ ├── 01-philosophy.md # 8 条架构原则
│ ├── 02-architecture.md # 四层架构详解
│ ├── 03-webview-survival.md # WebKit/WebView2 坑和修复(最高密度文件)
│ ├── 04-ipc-contract.md # 跨语言类型化 IPC
│ ├── 05-memory-truths.md # 为什么 Activity Monitor 骗了你
│ ├── 06-native-conventions.md # 70+ 原生质感检查项
│ └── 07-evidence-raycast.md # 反编译 Raycast Beta 的证据
└── checklists/
├── decision-tree.md # 你的项目该不该用这个架构?
└── ship-readiness.md # 75 项上线检查清单
八条架构原则
| # | 原则 | 核心思想 |
|---|---|---|
| T1 | **把接缝放在渲染层** | 跨平台边界画在 WebView 表面:下面是原生(窗口、热键、材料),上面是共享(React、业务逻辑) |
| T2 | **一套 schema,多种语言** | 多语言系统通过统一 IDL + codegen 通信,手写 marshalling 是禁止的 |
| T3 | **拥抱平台,别和它竞争** | 系统的模糊效果比你的快,系统的滚动条比你的对。不要重新发明平台功能 |
| T4 | **性能是感知问题** | Activity Monitor 的数字不是用户体验。用户感知到的是"点没点开",不是"多少 MB" |
| T5 | **短迭代循环就是产品** | 原生 UI 编译 30s vs React HMR 200ms —— 150 倍差距,一年下来就是"感觉做完了"和"感觉没做完"的差距 |
| T6 | **有意图地跨越边界** | 每次 IPC 都是设计决策。批量化、缓存化、可观测化。禁止意外热循环 |
| T7 | **身份认同是肌肉记忆** | 重写时可以改一切,但不能改用户习惯的快捷键和操作流。这些才是"那个 App" |
| T8 | **分离基线和边际成本** | 空 WebView 的 50MB 是租金,付了就认了。优化精力花在你的脏页上,别花在平台头上 |
四层架构
┌──────────────────────────────────────────────┐
│ 🏠 原生 Shell │
│ macOS: Swift/AppKit │
│ Windows: C#/.NET 8/WPF │
│ 负责:窗口、热键、菜单栏、系统托盘、全局快捷键 │
├──────────────────────────────────────────────┤
│ 🌐 系统 WebView │
│ macOS: WKWebView │
│ Windows: WebView2 (Chromium) │
│ 运行 React + TypeScript UI │
├──────────────────────────────────────────────┤
│ ⚙️ Node 后端 │
│ 单一长驻进程 │
│ 负责:数据库、扩展运行时、AI 服务 │
├──────────────────────────────────────────────┤
│ 🦀 Rust 核心 │
│ UniFFI 桥接,可分享给 iOS 和服务器 │
│ 文件索引器、云同步、高性能计算 │
└──────────────────────────────────────────────┘
关键创新: 四层之间通过一套类型化 IPC schema 通信,codegen 为每一层生成类型安全的客户端。改 schema 会导致所有语言编译失败 —— 从根本上杜绝类型漂移。
决策树:该不该用这个架构?
| 问题 | 如果... | 结论 |
|---|---|---|
| OS 目标 | 仅 macOS 或仅 Windows | ❌ 纯原生 |
| 原生质感 | "够好就行" | ❌ 用 Electron |
| 冷启动预算 | <100ms | ❌ 纯原生 |
| 内存预算 | <150MB | ❌ 纯原生 |
| 研发周期 | <3 个月上线 | ❌ 先用 Electron |
| ✅ 最适合 | 生产力启动器、笔记应用、AI 桌面端、开发工具 | ✅ 推荐 |
WebView 生存指南(最有价值的部分)
这份 Skill 的反向工程揭示了一系列 WebKit 的具体坑和修复方案:
| 问题 | 原因 | 修复 |
|---|---|---|
| WebKit 隐藏后卡动画 | 系统认为 WebView 不可见时 throttle requestAnimationFrame | alphaValue=0 保持窗口可见 + 禁用 occlusion 检测 |
| 窗口展开时空白帧 | WebKit throttle 视口外区域 | WebView frame 一直保持展开尺寸,窗口再缩放 |
| 窗口缩放卡顿 | WebKit 在动画期间暂停绘制 | 用 Core Animation 替代系统动画 |
| 打开窗口闪烁 | 绘制未完成时显示窗口 | `_doAfterNextPresentationUpdate` 回调 |
| Emoji 渲染慢 | 字体回落链太长 | 启动时预加载 emoji font |
| 内存测量误导 | macOS 双倍计数共享框架 | 看 dirty pages 和 compressed,不看 resident |
实用场景
场景 1:已有的 Electron 应用太"网页味"
→ 跑 75 项检查清单,通常 6-8 个问题是常见的:
- cursor:pointer 出现在不该出现的地方
- Web 风格模态框替代原生 sheet
- 硬编码品牌色而非系统强调色
- 页面淡入淡出过渡
- 不透明窗口背景替代平台材料
- WebKit 右键菜单还在触发
场景 2:新建跨平台原生质感应用
→ 先跑决策树,符合条件后:
1. 确定 IPC 契约(最重要,后面改成本最高)
2. WebView 生存配置
3. 内存卫生
评分
| 维度 | 评分 | 说明 |
|---|---|---|
| 实战价值 | ★★★★★ | 不是理论论文,是经过 Raycast 验证、反编译确认的可执行知识 |
| 内容密度 | ★★★★★ | 7 个参考文件 + 2 个清单,75 项检查清单,全是干货 |
| 唯一性 | ★★★★☆ | 市面上几乎没有把"原生质感"系统化成 Agent Skill 的同类项目 |
| 时效性 | ★★★★★ | Raycast 2.0 昨天发布,这个 Skill 今天就有了 |
| 易用性 | ★★★★★ | 一句 `npx skills add` 安装,Agent 自动匹配触发 |
一句话总结
> 如果你在做跨平台桌面应用(macOS + Windows),又不想被用户说"这玩意儿一股网页味",装上这个 Skill —— 你的 AI 助手就会变成 Raycast 架构师,告诉你每条线该画在哪里、每个坑该怎么填。