7.3 KiB
7.3 KiB
🏗️ 《Project Vibe: Ship It!》技术架构与关键路径文档
一、 技术栈选型 (Tech Stack)
强烈建议在 Prompt 开头向 AI 明确这些技术栈,防止它自由发挥引入不兼容的库。
- 前端框架: React 18 + Vite (纯前端单页应用,无需复杂后端)。
- 开发语言: TypeScript (极其重要!严格的类型定义是 VibeCoding 不翻车的绝对保障)。
- 状态管理: Zustand (极其推荐!比 Redux 轻量,比 Context 性能好,非常适合做游戏的状态机更新)。
- 样式方案: Tailwind CSS (方便 AI 快速生成好看的 UI 卡片)。
- 拖拽与动画:
framer-motion(处理卡牌平滑移动和翻转动画) + 原生 Pointer Events (处理自由桌面坐标 x,y,不要用基于网格的dnd-kit,因为我们要的是类似操作系统的无网格自由堆叠)。
二、 核心数据模型 (Data Models - TypeScript Interfaces)
这是整个系统的灵魂。第一步请先让 AI 生成并完善这些类型定义文件 types.ts。有了它,AI 后续写的逻辑就不会乱。
// 1. 卡牌基础模型
export interface Card {
id: string; // 唯一实例ID (uuid)
templateId: string; // 对应配置表中的模板ID (如 'dirty_code', 'developer')
name: string;
type: 'resource' | 'actor' | 'module' | 'crisis' | 'warning';
tags: string[]; // 用于危机判定 (如 ['need_test', 'human'])
position: { x: number; y: number }; // 桌面绝对坐标
status: 'idle' | 'dragging' | 'processing' | 'locked';
processEndTime?: number; // 如果在合成中/危机倒计时中,记录结束的绝对时间戳
}
// 2. 合成配方模型 (静态配置)
export interface Recipe {
id: string;
inputs: string[]; // 需要堆叠在一起的 templateId 列表
timeMs: number; // 合成所需时间 (毫秒)
outputs: Array<{ templateId: string; chance: number }>; // 产物及概率
}
// 3. 全局状态模型 (Zustand Store)
export interface GameState {
// --- 资源状态 ---
funds: number; // 项目资金
sprintTimeRemaining: number; // 当前 Sprint 倒计时
sprintNumber: number; // 当前处于第几个 Sprint
// --- 实体状态 ---
cards: Card[]; // 桌面上的所有卡牌
// --- 核心方法 (Actions) ---
moveCard: (id: string, x: number, y: number) => void;
checkCraftingOverlap: (cardId: string) => void; // 碰撞检测核心逻辑
tick: () => void; // 游戏主循环 (Game Loop),每帧/每秒更新状态
triggerCrisis: (crisisData: any) => void; // LLM 返回后触发危机
}
三、 系统架构设计图 (单向数据流)
游戏的架构必须是数据驱动的。UI 层只负责渲染 cards 数组和捕获鼠标事件。
[ 玩家操作 (拖拽/松开) ]
│
▼
[ 操作意图 (Pointer Events) ] ──发起请求──> [ LLM 危机生成器 (异步 Hook) ]
│ │ (返回JSON/超时Fallback)
▼ ▼
[ 碰撞检测算法 (Overlap Check) ] [ 触发预警卡/危机卡生成 ]
│ │
▼ (匹配 Recipe) │
[ 状态机引擎 (Zustand Store) ] <─────────────────┘
├─ 更新卡牌坐标 (x, y)
├─ 锁定卡牌状态 (status: 'processing')
└─ 结算资金/时间 (funds, sprintTime)
│
▼ (响应式数据)
[ React 渲染层 (UI Components) ]
├─ <DesktopBoard /> (渲染桌面)
├─ <CardItem /> (渲染实体卡、倒计时进度条)
└─ <HudPanel /> (渲染顶部资金与时间)
四、 VibeCoding 关键开发路径 (Critical Paths)
千万不要让 AI “一口气写一个游戏”。请严格按照以下 4 个阶段向 AI 提需求 (Prompting),每完成一个阶段就运行测试,确保无误后再进入下一阶段。
🚩 Path 1: 静态桌面与全局状态 (The Dumb Board)
- 目标: 能在屏幕上看到几张卡牌,资金数值能够显示。
- AI 任务:
- 初始化 Vite + React + TS 项目,安装 Zustand 和 Tailwind。
- 创建
types.ts(使用上面提供的模型)。 - 创建
useGameStore.ts(Zustand),初始化几个假数据卡牌 (Mock Data)。 - 编写
<DesktopBoard>和<CardItem>组件。卡牌通过绝对定位absolute渲染在对应的x, y坐标上。
🚩 Path 2: 自由拖拽与物理碰撞 (Drag & Collision)
- 目标: 卡牌可以被鼠标拖拽,松开鼠标时,能判断两张卡是否重叠。
- AI 任务:
- 给
<CardItem>添加onPointerDown,onPointerMove,onPointerUp事件。 - 拖拽时,调用 Store 的
moveCard更新坐标。 - 核心算法要求: 松开鼠标时,写一个
checkOverlap(cardA, cardB)函数(通过判断两个矩形的边界 bounding box 是否相交)。如果重叠率超过 50%,则判定为“堆叠成功”。
- 给
🚩 Path 3: 核心主循环与合成引擎 (Game Loop & Crafting)
- 目标: 两张配方卡重叠 -> 出现进度条 -> 读条结束产出新卡。
- AI 任务:
- 创建一个静态的
recipes.json(包含 2-3 个基础配方,如 开发+脏代码=模块)。 - 在 Store 中创建一个
requestAnimationFrame或setInterval(..., 100)驱动的tick()函数(这就是游戏的心跳)。 - 合成逻辑: 当卡牌重叠,匹配 JSON 成功后,将这两张卡的 status 改为
processing,并设置processEndTime = Date.now() + timeMs。 - 心跳检测:
tick()函数不断检查当前时间是否超过processEndTime。如果超过,删除旧卡,在原坐标push新产物卡。
- 创建一个静态的
🚩 Path 4: LLM 异步危机总线 (The AI Director)
- 目标: 每隔一段时间,根据桌面状态调用大模型,生成危机并处理延迟。
- AI 任务:
- 编写一个独立的服务
llmService.ts。 - 编写
useCrisisDirector自定义 Hook。内部设置一个定时器(如每 30 秒触发一次)。 - 时序逻辑编写:
- 触发时:立刻在 Store 中推入一张 status 为
processing的【预警卡】。 - 发起
fetch请求调用 OpenAI/DeepSeek API,附带当前桌面状态。 - 使用
Promise.race实现 5 秒超时控制。 - 请求 Resolve (或超时 Fallback) 时:将那张【预警卡】的数据替换为真实的【危机卡】JSON 数据,并开始倒计时。
- 触发时:立刻在 Store 中推入一张 status 为
- 编写一个独立的服务
💡 给开发者的 VibeCoding 避坑指南 (Tips)
- 这是一个自由摆放的桌面,没有列表,只需要纯粹的 x,y 坐标更新和基于宽高的 AABB (Axis-Aligned Bounding Box) 碰撞检测。”
- 在 Zustand store 里统一管理所有状态。不要在
<CardItem>组件内部用useState去管理倒计时!所有的进度条渲染都应该基于processEndTime - Date.now()实时计算得出,这样即使组件卸载/重新渲染,进度也不会丢失。 - Mock First: 在写 LLM 接入时,用
setTimeout模拟一个假的大模型返回。把游戏跑通了,最后再填入真实的 API Key 和fetch请求。