> ## Documentation Index
> Fetch the complete documentation index at: https://docs.profy.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 游戏工作室

> profy-game-studio：浏览器 2D / 3D 游戏开发，含引擎选型矩阵、可断言的调试投影与自动化试玩

# 游戏工作室（profy-game-studio）

## 一句话定义

`profy-game-studio` 让专家从零做出**能在浏览器里真的玩起来的游戏**——选引擎、搭架构、写游戏循环、接物理、做 HUD，然后**自己反复试玩直到确实能玩**才拿给你。最后一步是这个插件与"让 AI 写个小游戏"的根本差别。

## 激活条件

| 字段                | 取值                                  |
| ----------------- | ----------------------------------- |
| 插件 ID             | `profy-game-studio`                 |
| `user_selectable` | `true`——**在插件面板里手动勾选**              |
| `conditions`      | `{ "sandbox_mode": "!none" }`（需要沙箱） |
| 注入工具              | `browser`（唯一）                       |
| 注入提示词             | `GAME_STUDIO.md`                    |
| 声明技能              | 9 篇（目录下共 10 个技能目录）                  |
| 参考资料              | 16 篇（`references/`，按需读取）            |

<Note>
  这个插件**不注入任何专属工具**，只绑定 `browser`。原因很直接：游戏开发用的是沙箱里的常规能力（写文件、跑 dev server、装依赖），唯一缺的是「看到画面并操作它」，那正是浏览器工具。所以单勾 Game Studio 时浏览器一定跟着激活——试玩流程离了它就是空的。
</Note>

## 引擎选型矩阵

选型是做游戏的第一个决定，也是最贵的决定——选错了要重写。提示词里带了完整决策表：

| 游戏类型          | 引擎                 | 理由        |
| ------------- | ------------------ | --------- |
| 3D 第一/第三人称    | Three.js（原生）       | 完全控制，性能最好 |
| 3D + React 界面 | React Three Fiber  | 声明式，组件模型  |
| 2D 平台/街机      | Phaser 3           | 开箱即用，自带物理 |
| 2D + React 界面 | Phaser + React 覆盖层 | 两边好处都要    |
| 简单 2D（无物理）    | Canvas2D API       | 零依赖       |

### 各维度对比

| 维度       | Three.js    | R3F                      | Phaser           | Canvas2D |
| -------- | ----------- | ------------------------ | ---------------- | -------- |
| 3D 支持    | 完整          | 完整                       | 无                | 无        |
| 2D 支持    | 可以但别扭       | 可以但别扭                    | 完整               | 基础       |
| 内置物理     | 无（加 Rapier） | 无（加 @react-three/rapier） | 有（Arcade/Matter） | 无        |
| React 集成 | 手工          | 原生                       | 覆盖层              | 覆盖层      |
| 学习曲线     | 中           | 中偏高                      | 低到中              | 低        |
| 包体积      | \~150KB     | \~200KB                  | \~300KB          | 0        |
| 移动端性能    | 好           | 好                        | 极好               | 极好       |

### 各引擎的「什么时候别用」

这份反向清单比正向推荐更有用：

* **Three.js**：别拿来做简单 2D 游戏（杀鸡用牛刀）
* **R3F**：实体数量大时别用（React 开销会成为瓶颈）
* **Phaser**：不做 3D，也不适合需要自定义渲染管线的场景
* **Canvas2D**：复杂物理和 3D 都别指望

如果你对引擎有偏好，**在需求里直接说**——否则模型会按上表自己决定，而它的决定通常是对的但未必是你想要的。

## 六条架构原则

提示词把这六条写死，所以你拿到的代码结构是可预期的：

<AccordionGroup>
  <Accordion title="1. 游戏循环：固定步长物理（60Hz）+ 可变渲染">
    逻辑绝不能绑在帧率上。绑了的后果是：高刷屏上角色跑得飞快，低端机上慢动作，而且物理会在掉帧时穿模。这是新手游戏最常见的结构性错误，也是最难在后期修的。
  </Accordion>

  <Accordion title="2. ECS-lite：数据与逻辑分离">
    即使不上正式的 ECS 框架，状态和渲染也要分开。好处在改需求时才显现——「加一种敌人」如果要同时改渲染代码，说明这条没做到。
  </Accordion>

  <Accordion title="3. 输入抽象：原始事件映射成语义动作">
    映射成 `jump`、`move_left` 这类语义动作，而不是到处判断 `event.key === 'ArrowLeft'`。同时支持键盘 + 触屏 + 手柄。这条让「加手柄支持」从重写变成加一层映射。
  </Accordion>

  <Accordion title="4. 资源管线：异步预加载 + 进度条 + 激进缓存">
    游戏开始前把资源加载完，显示加载进度。边玩边加载的体验是卡顿，不是流畅。
  </Accordion>

  <Accordion title="5. 状态机：菜单/游玩/暂停/结束 显式 FSM">
    游戏状态用显式有限状态机表达，而不是散落的布尔标志。`isPaused && !isGameOver && hasStarted` 这种组合判断是状态机缺失的症状。
  </Accordion>

  <Accordion title="6. 测试钩子：交互控件带 data-game-action">
    给可交互控件加稳定的 `data-game-action` 属性，让浏览器自动化能按语义重放用户路径，而不是靠脆弱的视觉坐标点击。这条直接服务于下面的自动试玩。
  </Accordion>
</AccordionGroup>

## 调试投影：让试玩可断言

这是整套流程的技术核心。每个游戏都必须暴露一个**只读调试投影**：

```js theme={null}
window.__GAME_DEBUG__ = {
  snapshot: () => ({ phase, score, health, player, entityCount })
};
```

关键词是「投影」和「只读」——它不复制游戏状态，只是把当前状态读出来。所以它不会引入状态不同步的新问题。

有了它，试玩就从「看截图猜」变成「读状态断言」：

```js theme={null}
browser(action="evaluate", code="window.__GAME_DEBUG__?.snapshot()")
```

模型能直接确认「按了右键之后 `player.x` 真的变大了」「吃到金币后 `score` 真的加了」，而不是盯着两张截图判断像素有没有动。需要证明特定机制时，投影会被按需扩展（比如做塔防就加上 `waveIndex` 和 `towerCount`）。

<Info>
  截图和状态断言解决的是**不同**问题：截图能发现「画面没渲染出来」，状态断言能发现「渲染对了但逻辑错了」。只做前者会交付出一个好看但按键没反应的游戏——这正是纯视觉验证的盲区。
</Info>

## 自动试玩循环

提示词里的「Vision in the Loop」协议，游戏版比可视化版多了交互重放：

<Steps>
  <Step title="生成或修改代码">
    写游戏代码
  </Step>

  <Step title="截图">
    `browser(action="screenshot", url="localhost:5173")`
  </Step>

  <Step title="读像素">
    `image(action="read", ..., prompt="检查游戏可见性、HUD、构图、伪影与空白区域")`
  </Step>

  <Step title="断言状态">
    `browser(action="evaluate", code="window.__GAME_DEBUG__?.snapshot()")`
  </Step>

  <Step title="重放交互">
    点开始：`document.querySelector('[data-game-action=start]')?.click()`

    键盘输入：`dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))`
  </Step>

  <Step title="综合诊断">
    截图与状态一起看，按下面的症状表定位
  </Step>

  <Step title="有问题就回第 1 步">
    **无迭代次数上限**，循环到确实能玩为止
  </Step>
</Steps>

症状 → 原因对照表（提示词内置）：

| 症状        | 原因方向                         |
| --------- | ---------------------------- |
| 黑屏 / 空白   | WebGL 上下文错误或脚本崩溃 → 看 console |
| 精灵 / 模型缺失 | 资源加载失败或路径错                   |
| 布局错位      | 相机位置 / canvas 尺寸 / CSS       |
| 物理异常      | 时间步长问题或碰撞配置 → 用状态检查调试        |
| 卡顿        | draw call 过多或 GC 压力          |

提示词最后一句写得很直接：**能自己验证的事不要反过来问用户「这样对吗」**。用户要的是能玩的成品，不是替你做 QA。

## 游戏专项验收

除了通用视觉检查，游戏还要过这几项：

* 角色对输入有反应（注入测试输入 → N 帧后截图）
* 分数 / UI 正确更新
* 物体不会穿过地板（物理穿透）
* 游戏结束条件正确触发
* 重开干净（无状态残留）

### 性能门槛

| 指标        | 移动端      | 桌面端      |
| --------- | -------- | -------- |
| FPS       | ≥ 30     | ≥ 60     |
| Draw call | \< 200   | \< 500   |
| 加载时间      | \< 5s    | \< 3s    |
| 内存        | \< 256MB | \< 512MB |
| 包体积       | \< 5MB   | \< 20MB  |

### 边界情况

窗口 resize 时 canvas 要自适应；切标签页时游戏要暂停（`visibilitychange`）。这两条经常被忽略，症状是切回来发现角色已经死了。

## 技能与参考资料

### 9 篇声明技能（正文注入提示词）

| 技能                       | 覆盖                |
| ------------------------ | ----------------- |
| `game-studio`            | 总纲                |
| `three-webgl-game`       | Three.js 原生 3D 游戏 |
| `react-three-fiber-game` | R3F 声明式 3D        |
| `phaser-2d-game`         | Phaser 3 2D 游戏    |
| `web-3d-asset-pipeline`  | 3D 资产管线           |
| `web-game-foundations`   | 游戏基础（循环、输入、状态）    |
| `game-ui-frontend`       | HUD 与菜单           |
| `game-playtest`          | 试玩验证              |
| `sprite-pipeline`        | 精灵图管线             |

目录下另有 `physics-game`，未在 manifest 声明但可通过 `skill` 工具按名加载。

### 16 篇参考资料（按需读取，不占默认上下文）

`alternative-3d-engines` / `engine-selection` / `frontend-prompts` / `gltf-loading-starter` / `phaser-architecture` / `playtest-checklist` / `rapier-integration-starter` / `react-three-fiber-stack` / `react-three-fiber-starter` / `sprite-pipeline` / `three-hud-layout-patterns` / `three-webgl-architecture` / `threejs-stack` / `threejs-vanilla-starter` / `web-3d-asset-pipeline` / `webgl-debugging-and-performance`

其中带 `-starter` 的四篇是可直接抄的起步模板。

## 可执行示例

<AccordionGroup>
  <Accordion title="2D 平台跳跃">
    ```
    做一个横版跳跃游戏：一个角色左右移动和跳跃，有几个平台，
    掉下去重来。收集金币加分，右上角显示分数。手机上能用触屏控制。
    ```

    会选 Phaser 3（2D + 物理），带 `data-game-action` 钩子，试玩时会验证跳跃真的能上能下、掉落真的会重来。
  </Accordion>

  <Accordion title="3D 第一人称探索">
    ```
    做一个第一人称场景漫游：WASD 移动、鼠标转视角，
    场景里放几个可以走近查看的展品，靠近时显示说明文字。
    ```

    会选 Three.js 原生，重点在相机控制与碰撞。
  </Accordion>

  <Accordion title="带 React 界面的塔防">
    ```
    做一个塔防：3D 战场 + React 做的建塔面板和波次信息。
    塔有三种，敌人分批出，血量归零输。
    ```

    这是 R3F 的典型场景。调试投影会被扩展出 `waveIndex` / `towerCount` 之类字段来断言波次逻辑。
  </Accordion>

  <Accordion title="改造已有游戏">
    ```
    我的游戏在 <路径>，现在敌人会穿过墙。查一下修掉，
    修完跑一遍试玩确认碰撞正常。
    ```

    穿模通常是固定步长没做对（原则 1）或碰撞体尺寸不匹配。
  </Accordion>
</AccordionGroup>

## 边界与失败态

| 症状           | 原因                      | 处理                                       |
| ------------ | ----------------------- | ---------------------------------------- |
| 游戏是黑屏        | WebGL 上下文错误或脚本崩溃        | 让模型看 console 输出而不是继续调画面                  |
| 画面正常但按键没反应   | 只做了视觉验证，没做状态断言          | 要求「用 `__GAME_DEBUG__.snapshot()` 验证输入生效」 |
| 角色穿过地板       | 物理穿透，通常是时间步长或碰撞体问题      | 明确要求固定步长 60Hz                            |
| 高刷屏上快、低端机上慢  | 逻辑绑了帧率（违反原则 1）          | 要求重构成固定步长 + 可变渲染                         |
| 手机上卡到没法玩     | 超出移动端性能门槛               | 对照上表让模型逐项优化                              |
| 切标签页回来发现死了   | 没处理 `visibilitychange`  | 要求补暂停逻辑                                  |
| 模型反过来问「这样对吗」 | 自检协议没走完                 | 提醒它先自己截图 + 断言状态                          |
| 插件勾了但没生效     | `sandbox_mode` 为 `none` | 需要沙箱                                     |

### 已知缺陷：三个精灵脚本是占位实现

`scripts/` 下的三个脚本目前**只是打印一行字符串**，没有真实实现：

| 脚本                               | 现状                                                                      |
| -------------------------------- | ----------------------------------------------------------------------- |
| `normalize_sprite_strip.py`      | `print("normalize_sprite_strip: normalizes frame sizes")`               |
| `build_sprite_edit_canvas.py`    | `print("build_sprite_edit_canvas: generates blank sprite template")`    |
| `render_sprite_preview_sheet.py` | `print("render_sprite_preview_sheet: generates preview contact sheet")` |

症状是：调用它们不会报错，会"成功"返回一行文字，但你要的精灵图不会出现。

**绕行方式**：让模型直接用 Pillow 处理精灵图（沙箱里可用），或者用 `sprite-pipeline` 技能文档里的方法手工走一遍。**判断方法**：如果模型说"已生成精灵预览表"但你找不到图片文件，就是撞上了这个。

## 验证

<Steps>
  <Step title="确认插件已激活">
    问「你能做浏览器游戏吗？用什么引擎？」。激活时专家会给出选型矩阵并反问你的游戏类型；未激活时只会泛泛地说能写代码。
  </Step>

  <Step title="最小可玩">
    「做一个最简单的：一个方块用方向键移动，撞到边界停住。」应该拿到能直接玩的东西，不是一段待你自己跑的代码。
  </Step>

  <Step title="确认调试投影存在">
    在游戏页面的 console 里敲 `window.__GAME_DEBUG__.snapshot()`。返回状态对象说明架构规范被遵守了；`undefined` 说明这条被跳过，后续试玩会退化成纯视觉。
  </Step>

  <Step title="确认自检循环跑过">
    看模型有没有在交付前调用截图与 `evaluate`。直接给代码就说明浏览器工具没绑上。
  </Step>
</Steps>

## 相关页面

<CardGroup cols={2}>
  <Card title="3D 开发" icon="box" href="/zh/documentation/plugins/3d-development">
    Blender / Godot 桥接与 3D 资产管线
  </Card>

  <Card title="可视化" icon="bar-chart-2" href="/zh/documentation/plugins/visualize">
    Three.js 场景诊断工具 `inspect_3d`
  </Card>

  <Card title="浏览器自动化" icon="globe" href="/zh/documentation/capabilities/browser-automation">
    试玩循环依赖的浏览器能力
  </Card>

  <Card title="Sites 建站" icon="rocket" href="/zh/documentation/capabilities/sites">
    把做好的游戏发布成可访问站点
  </Card>
</CardGroup>

<Note>
  核对日期 2026-08-11。来源：`services/agent-runtime/src/plugins/builtin/game-studio/plugin.json`、`prompts/GAME_STUDIO.md`、`references/{engine-selection,playtest-checklist}.md`、`scripts/*.py`。
</Note>
