我给 AI 造了一个原型工具:AIWireframeViewer V1

前言

这篇文章,其实是我那篇《玩Android×AI Coding:从产品到代码,完整跑通一套 AI 软件研发工作流》2.4「AI 不仅能使用工具,也能创造工具」 的展开篇。

在那一节里,我提到了一件事:

当 AI 已经能参与产品、UX、视觉和工程时,我真正缺的,可能已经不是某个现成工具,而是一个更适合 AI 理解、AI 消费、AI 接力 Coding 的中间层。

于是我没有继续折腾 Figma 的付费能力,也没有继续找 Axure、墨刀的平替。

我直接让 AI 和我一起,做了一个新的工具:

AIWireframeViewer。

它不是设计稿工具,也不是页面生成器。

它是一个 JSON 驱动的低保真原型查看器

它存在的目的只有一个:

给 AI 一种稳定的中间语言,让原型不再只是"图片"和"描述",而是一套可以被读取、校验、渲染、运行的数据。


1、为什么我要自己造这个工具

当时我已经有了这些东西:

  • API 文档
  • PRD
  • 信息架构
  • Wireframe 布局文档
  • 视觉规范
  • 组件映射思路

按正常流程,下一步似乎应该把这些东西继续塞给现有原型工具,生成一个可交互原型。

但我很快发现,现有工具都不是我真正想要的。

我想要的不是:

  • 一个只能给人看的高保真设计稿
  • 一个只能手工点击的原型链接
  • 一个和代码世界完全脱节的设计文件

我真正想要的是:

一个既能让人看懂页面结构,又能让程序消费页面结构,还能继续交给 AI Coding 往下生成工程实现的中间层。

换句话说,我需要的不是"更漂亮的原型",而是"更可计算的原型"。

这就是 AIWireframeViewer 存在的原因。


1.1 它到底是什么

AIWireframeViewer 目前是一个基于 React + Vite + TypeScript 做的 JSON 驱动低保真原型查看器。

当前 V1 已经具备两种模式:

  • Editor:看项目工作台、页面排布、页面列表
  • Runtime:从入口页开始运行交互、跳转、回退和历史栈

技术栈也比较克制:

  • React
  • Vite
  • TypeScript
  • React Router
  • AJV
  • Vitest
  • Playwright

它不是把页面直接写死在 React 组件里,而是通过这三类数据驱动起来:

  • project/manifest.json
  • wireframes/*.json
  • schema/*.json

也就是说,React 在这里更像一个容器。

真正描述"这个原型是什么"的,不是 JSX,而是 JSON。


1.2 我想解决的,不是"渲染页面",而是"定义中间语言"

如果只是想搞一个 Demo,其实很简单:

  1. 手写 8 个 React 页面
  2. 用路由拼起来
  3. 加几个按钮跳转
  4. 再做个侧边栏和工作台

这样当然也能演示。

但那样做出来的,充其量只是一个"原型长得像原型"的前端项目。

我想做的不是这个。

我更关心三个问题:

  • 原型结构能不能脱离代码独立存在?
  • 这些结构能不能被校验,而不是随便写个 JSON 就算数?
  • 这套结构能不能继续交给 AI,用作后续 Coding 的输入?

所以我一开始没有直接冲着"渲染器"去,而是先定义了一层中间语言。

这个中间语言,最终分成了两层:

  • Project Layer
  • Wireframe Layer

2、为什么要分成 Project Layer 和 Wireframe Layer

这是整个项目里,我最想先稳定下来的边界。

2.1 Project Layer:描述整个项目

Project Layer 负责的是项目级信息,比如:

  • 项目标识
  • 入口页
  • 页面引用列表
  • 默认视口
  • 编辑器状态
  • Schema 路径
  • Viewer 兼容信息

它的入口文件是 project/manifest.json

最小结构大概像这样:

json 复制代码
{
  "projectId": "ai-wireframe-viewer-demo",
  "entryPage": "home",
  "schema": {
    "project": "../schema/project.schema.json",
    "wireframe": "../schema/wireframe.schema.json"
  },
  "pages": [
    {
      "id": "home",
      "title": "首页",
      "file": "../wireframes/home.json",
      "canvasPosition": {
        "x": 0,
        "y": 0
      }
    }
  ]
}

这里有一个我刻意坚持的约束:

manifest 只保存引用,不复制页面内容。

也就是说,它负责回答的是:

  • 这个项目有哪几个页面?
  • 入口页是谁?
  • 页面文件在哪?
  • 工作台初始布局是什么?

而不是:

  • 页面里面有什么组件?
  • 卡片长什么样?
  • 点击后去哪?

这些属于下一层。

2.2 Wireframe Layer:描述单个页面

Wireframe Layer 负责单页内容,比如:

  • 页面标识
  • 页面视口
  • 元素树
  • 坐标和尺寸
  • 交互动作
  • 页面导航摘要
  • 元数据

这层数据放在 wireframes/*.json 里。

这样拆开的好处很直接:

  • 页面可以被多个项目复用
  • 项目级组织信息不会污染页面结构
  • 单个页面可以独立校验和加载
  • 后面想支持多项目、多入口时,结构不会塌

3、Wireframe 协议是怎么设计出来的

有了 Project Layer,接下来就轮到单页面协议。

我给每个页面定义了一份通用 JSON 结构。V1 没追求面面俱到,而是先满足"低保真原型可表达、可校验、可运行"。

顶层结构大概是这样:

json 复制代码
{
  "schemaVersion": "1.0.0",
  "page": {
    "id": "home",
    "title": "首页",
    "level": "primary"
  },
  "viewport": {
    "width": 360,
    "height": 800,
    "unit": "dp"
  },
  "canvasPosition": {
    "x": 0,
    "y": 0
  },
  "coordinateSpace": "page",
  "elements": [],
  "navigation": {},
  "metadata": {}
}

这里我做了几个比较关键的取舍。

3.1 坐标系统固定为 page

V1 里我明确规定:

  • coordinateSpace: "page"
  • 所有元素都用页面绝对坐标
  • 即使元素有 children,子元素坐标也仍然相对于页面左上角

这套规则不算"高级",但非常稳定。

因为低保真原型最怕的不是能力不够,而是坐标解释不一致。

我宁愿它朴素一点,也不要一开始就把相对坐标、嵌套坐标、自动布局全揉进去。

3.2 顶层只有两个 Layer

V1 的页面只允许两个根容器:

  • fixed-layer
  • scroll-layer

它们分别承载:

  • 固定区:状态栏、顶部栏、底部导航
  • 滚动区:正文内容

这其实是把"页面结构"显式写进协议里,而不是交给渲染器猜。

3.3 name 不再承担显示内容

这一点我后面专门补过协议修订。

我把字段职责拆开了:

  • name:给编辑器树和调试看
  • text:给 text 元素显示正文
  • label:给按钮、Tab、导航项、Chip 等短文本组件
  • placeholder:给输入组件提示文案

比如一个元素会长这样:

json 复制代码
{
  "id": "search-submit-text",
  "type": "text",
  "name": "搜索提交文本",
  "text": "搜索",
  "x": 300,
  "y": 44,
  "width": 32,
  "height": 24,
  "fixed": true,
  "scrollable": false,
  "visible": true,
  "coordinateSpace": "page",
  "layout": {},
  "style": {},
  "children": [],
  "interactions": []
}

看起来像小事,但这件事很重要。

因为如果 name 同时承担"节点名称"和"实际显示文案",协议很快就会变成一锅粥。

3.4 交互先收敛,不发散

V1 只支持四类动作:

  • navigate
  • external-placeholder
  • back-to-source
  • none

这个决定也很克制。

因为我此时需要的是"可运行原型",不是"完整状态机平台"。

先把最小交互跑通,比一开始做复杂要更重要。


4、为什么我还要加上 Schema

很多人看到 JSON 驱动,会觉得:

"那不就是写几个 JSON 文件吗?"

问题在于:

能写 JSON,不等于能稳定运行。

如果没有校验,问题会非常多:

  • entryPage 指向一个根本不存在的页面
  • pages[].id 重复
  • targetPage 写错
  • viewport 格式不统一
  • 路径失效
  • 显示字段缺失
  • 页面导航摘要和实际交互不一致

所以我在 V1 里做了两层 Schema:

  • schema/project.schema.json
  • schema/wireframe.schema.json

但标准 JSON Schema 还不够,因为很多规则是跨字段的,甚至跨文件的。

所以我又保留了一层补充校验逻辑,专门处理这种问题,比如:

  • entryPage 必须存在于 pages[].id
  • pages[].id 不能重复
  • pages[].file 路径必须能解析
  • schema.projectschema.wireframe 路径必须能解析
  • 页面跳转引用必须能闭环

整个主链路可以概括成这样:

如图所示

Schema 在这里的意义,不是"写给人看的规范",而是:

保证这些原型数据真的能被程序消费。


4.1 从 manifest 到运行时,整个链路是怎么串起来的

这也是为什么我觉得这个项目已经不只是"一个概念"。

当前仓库里,主链路已经真实存在了。

核心模块包括:

  • loadProject
  • project-validator
  • schema-validator
  • page-renderer
  • interaction-engine
  • navigator
  • history-stack

其中 loadProject() 干的事,基本上就是整个项目的加载总入口:

ts 复制代码
export async function loadProject(): Promise<LoadedProject> {
  const manifest = await readJsonAsset<ProjectManifest>(manifestPath);
  const projectSchema = await readJsonAsset<unknown>(projectSchemaPath);
  const wireframeSchema = await readJsonAsset<unknown>(wireframeSchemaPath);

  issues.push(...validateProjectManifestSchema(manifest, projectSchema, manifestPath));
  issues.push(...validateManifestSupplementalRules(manifest, manifestPath));

  for (const manifestPage of manifest.pages) {
    const wireframe = await readJsonAsset<Wireframe>(filePath);
    issues.push(...validateWireframeSchema(wireframe, wireframeSchema, filePath));
    issues.push(...validateWireframeSupplementalRules(loadedPage, manifestPage, manifest.pages));
    pages.push(loadedPage);
  }

  if (issues.length > 0) {
    throw new ProjectValidationError(sortIssues(issues));
  }

  return loadedProject;
}

这段逻辑背后,其实代表了我对这个项目的一个原则:

Runtime 不应该直接吞原始 JSON,而应该只消费 Loader 和 Validator 清洗过的数据。

因为只有这样,后面的渲染器和运行时才不需要一直兜底脏数据。

另外,页面入口也已经非常明确:

  • /editor
  • /runtime

默认访问 / 会重定向到 /editor

所以这个项目现在不是"停留在文档层",而是真的具备一条完整的数据消费链路。


4.2 V1 现在已经能做到什么程度

从结果看,V1 已经是可运行状态了。

目前我已经做完这些:

  • 支持 Editor 工作台模式
  • 支持 Runtime 原型运行模式
  • 内置 8 个示例页面
  • 支持页面跳转
  • 支持来源页返回
  • 支持外部占位目标提示
  • 支持历史栈
  • 支持 vitest 单元测试
  • 支持 playwright E2E 测试

本地跑起来也很简单:

bash 复制代码
pnpm install
pnpm dev

我比较满意的一点是:

这套东西已经不是"拿来展示 JSON 结构"的。

它是真的可以把一套原型数据跑成一个可交互系统。


5、AI 在这里到底扮演什么角色

虽然项目名里有 AI,但我一直不想把这个项目讲成"AI 自动生成页面代码"的故事。

我更认同的定位是:

AI 在这里参与生成结构化原型数据,而不是直接输出最终业务界面。

这条链路更像是:

布局文档 -> Prompt -> 单页 Wireframe JSON -> Manifest 注册 -> Viewer 加载

这条路的价值在于:

  • 页面可以批量生成
  • 生成结果可以回收到工程里
  • 不是一次性聊天文本,而是结构化数据
  • 可以继续做校验
  • 可以继续做 Runtime 映射
  • 可以继续交给下一位 AI 或下一轮 AI Coding

所以 AIWireframeViewer 在整个工作流里的定位,其实很明确:

它不是最终产物,它是 AI 软件研发工作流中的一个中间工具。

而且是一个非常关键的中间工具。

因为从这里开始,AI 消费的就不再是图片,而是一套稳定的结构化页面描述。


6、V1 为什么还故意保留了一些"不完美"

V1 肯定不是终态,我也没有打算在这一版里把所有事情一次做满。

目前我刻意保留了几个限制。

6.1 canvasPosition 仍然双写

现在它还同时存在于:

  • project/manifest.json
  • wireframes/*.json

从长期看,它更适合正式上收到 Project Layer。

因为它本质是工作台编排信息,不是页面本体信息。

但 V1 我先让整个系统稳定跑起来,没有急着做回收重构。

6.2 Schema 和补充校验仍然分层

有些存在性规则、跨字段规则和引用闭环规则,还依赖补充校验逻辑。

这会增加一点维护成本,但可以换来更清晰的协议边界。

6.3 viewer 目前只有版本声明

现在 manifest.viewer 只有:

  • minimum
  • recommended

它已经能表达兼容门槛,但还没有完整的版本协商能力。

6.4 暂时不支持更多 Layer

V1 只有:

  • fixed-layer
  • scroll-layer

还没有做 overlaymodaltoastsheet

这不是能力缺失,而是我有意保持克制。

V1 最重要的是把主链路做稳,而不是把协议做胖。


7、这个项目接下来会往哪走

如果继续做 2.0,我最优先想推进这些事情:

  • canvasPosition 正式上收到 Project Layer
  • 补齐引用闭环自动校验和校验报告
  • 扩展 viewer 兼容策略
  • 增加更多 Layer,例如 overlaymodal
  • 支持多项目和更多默认设备策略

但从更大的方向看,我真正想验证的是这件事:

原型能不能从"截图 + 文案说明",变成"可以运行、可以校验、可以被程序继续消费的数据"。

如果这件事成立,那它连接的就不只是原型工具,而是整个 AI Coding 工作流里的前置输入层。

也就是说,AIWireframeViewer 的价值,不在于替代 Figma。

它真正的价值在于:

为 AI 提供一套稳定的中间语言。


结尾

回头看这件事,我最在意的从来不是"我做了一个 Viewer"。

我更在意的是,我终于把这条链路打通了:

Project -> Wireframe -> Schema -> Loader -> Renderer -> Runtime

从那篇总文章的 2.4 到这个独立项目,真正重要的不是"AI 又写了一个工具"。

而是我开始更确信一件事:

当 AI 已经能参与研发时,我们要做的不只是让它写代码,更重要的是给它创造一套更适合协作的输入和中间层。

AIWireframeViewer,就是我在这个方向上的第一步。

该项目已上传至 Github AIWireframeViewer

欢迎交流。

相关推荐
Highcharts.js1 小时前
商业授权与开源图表库如何选择?
前端·javascript·开源·highcharts·chart.js·echarts.js
工具派1 小时前
写代码时,我把这个本地 AI Commit Message 生成器接进了工作流
前端·后端
LaughingZhu2 小时前
Product Hunt 每日热榜 | 2026-07-15
前端·人工智能·神经网络·react.js·搜索引擎·前端框架
掘金者阿豪2 小时前
从Oracle迁到金仓,第一个月踩的最大的坑就是它
前端·后端
小四的小六2 小时前
MCP Server 从0到1实战:手写一个让AI调用本地数据库的Tool工具
后端·openai·ai编程
AZaLEan__2 小时前
CSS文档流相关:BFC
前端·css
_codeOH2 小时前
读完这两份代码,我终于搞懂了 Agent 的 Skills 到底是什么
人工智能·ai编程
小林ixn3 小时前
Vue3接入DeepSeek流式输出,把“二进制碎片”和“局部热更新”扒个精光
前端·vue.js·人工智能
一心只读圣贤书3 小时前
如何在项目中落地Agent?从选型到上线的完整指南
aigc·ai编程