---
name: responsive_2d_layout.aicomponent
description: 2D 可玩 UI 布局规范（框架无关）+ 本仓库默认的 Phaser 参考实现。规范定义设计分辨率、uiScale/vScale 与不变量；ref/UiLayout.ts 为 Phaser 绑定，非 Phaser 运行时需按同一公式实现等价逻辑。
triggers: 需要为试玩或 2D UI 做跨屏适配、从设计稿坐标换算到运行时坐标、或统一 UI 缩放规则时触发。
---

# 2D 自适应布局（Responsive 2D Layout）

本 skill 分两层：

1. **布局规范（Layout Canon）**：与具体引擎无关；Agent **必须先理解并遵守**，在任何运行时（Phaser、Canvas、DOM、其他）中复用同一套数学与约束。
2. **Phaser 参考实现**：本仓库提供的默认代码骨架；若项目使用其他引擎，**不得删改规范公式**，只替换「从哪里读取 width/height」的绑定层。

---

## 一、框架无关：布局规范（Layout Canon）

### 1.1 坐标系与设计空间

- **设计稿（Design space）**：固定基准宽 \(W_d\) × 高 \(H_d\)（本系列 skill 约定默认 **750 × 1334**，竖屏可_play 常用；可按项目替换，但须在配置中单点定义）。
- **原点**：画布左上角为 \((0,0)\)，**x 向右、y 向下**（与常见 2D 画布一致）。
- **设计像素**：UI 稿上的数值（间距、字号、图标边长）均以设计空间中的 **dp**（design px）理解，记为无单位实数，与 \(W_d, H_d\) 同量纲。

### 1.2 运行时视口

- **运行时布局宽高** \(W_r, H_r\)：Agent 必须从当前「用于摆放 UI 的矩形」读出——在 Phaser 中通常是主摄像机在 **Scale 模式生效后** 的宽高；在 DOM 中可以是根容器 clientWidth/Height；原则一致：**与最终绘制/点击检测使用同一坐标系**。
- **不规定** 如何实现全屏或 HiDPI（devicePixelRatio、内部渲染倍数由引擎 skill 决定）。规范只要求：用于布局公式的 \(W_r, H_r\) 与 **UI 摆放/命中** 一致。

### 1.3 缩放系数（必须按此定义）

令：

\[
\text{scaleX} = W_r / W_d,\quad \text{scaleY} = H_r / H_d
\]

- **uiScale**（整体 UI 可取的最小维缩放，且夹断）：

\[
\text{rawUiScale} = \min(\text{scaleX}, \text{scaleY}),\quad
\text{uiScale} = \mathrm{clamp}(\text{rawUiScale}, \text{minScale}, \text{maxScale})
\]

其中 `minScale`、`maxScale` 为项目配置（默认可沿用 `GameConfig`：0.7～1.4），**须在单点配置中可调，禁止在组件内各自写死缩放**。

- **vScale**（仅随高度变化，用于「贴底 / 贴顶」等垂向比例）：

\[
\text{vScale} = \text{scaleY} = H_r / H_d
\]

- **中心点**（运行时像素）：

\[
\text{centerX} = W_r / 2,\quad \text{centerY} = H_r / 2
\]

### 1.4 从设计量到运行时的映射（约定）

Agent 布置控件时应**统一**使用下列规则（除非本规范另有说明）：

- **以设计稿为单位的宽高、圆角、描边粗细、图标边长**（各向同性缩放需求）：乘以 **uiScale**。
- **距屏幕上/下边的垂直距离**（设计稿中从底边向上的距离）：用 **vScale** 换算，例如距底 `80` dp → 运行时 `y = H_r - 80 * vScale`（锚点策略与具体引擎 API 由实现决定，**换算系数必须是 vScale**）。
- **居中偏移**：相对中心的水平/垂直偏移，优先用 `centerX/centerY` 加 **设计偏移 × uiScale**（与项目现有代码一致）。

### 1.5 布局不变量（跨引擎）

- **单一真理来源**：每个画面/场景一次计算 \(W_r, H_r, \text{uiScale}, \text{vScale}, \text{centerX}, \text{centerY}\)，**全屏 UI 共用**；禁止部分组件自行 `innerWidth/字体模糊估算` 另起一套比例。
- **棋盘 / 世界内容**：可与 UI 分层；若棋盘 skill 依赖「可用区域高度（扣除顶栏/底栏）」，扣除量须用 **设计稿高度常量 × vScale** 或 **运行时像素** 明确统一，并与本规范中的 \(W_r, H_r\) 一致。
- **安全区 / 刘海**：若需适配，**先**得到有效 \(W_r', H_r'\)（ inset 后的矩形），再**代入以上公式**替换 \(W_r, H_r\)；公式不变。

---

## 二、Agent 执行要点（与引擎无关）

1. 读取规范第一节，确认项目的 \(W_d, H_d\) 与 `minScale`/`maxScale` 数据源（如 `GameConfig`）。
2. 在目标运行时实现或调用与 **1.3 节公式等价** 的函数，得到 `uiScale`、`vScale`、`centerX`、`centerY`。
3. 所有 2D UI 字号、边距、控件尺寸除非特例，均通过 **dp × uiScale** 或 **dp × vScale（垂向边距）** 导出；**禁止** 混用未夹断的 `scaleX` 作为「整体 UI 缩放」以免扁长屏拉伸失调。
4. 若运行时不是 Phaser：**不要**复制粘贴 Phaser 类型；保留输入为「宽、高 + 配置」、输出为「上述系数与中心点」的纯函数即可。

---

## 三、Phaser 参考实现（本仓库默认）

`ref/UiLayout.ts` 中的 `computeUiLayout(sceneOrCamera, config?)` 即为 **1.3 节** 的 Phaser 绑定：`width/height` 取自主摄像机，`config` 默认 `GameConfig`。

### Scaffold

| 目标路径 | 来源 | 说明 |
|---------|-----|-----|
| `src/game/utils/UiLayout.ts` | `ref/UiLayout.ts` | `computeUiLayout()` + 类型定义 |

### Imports

- `phaser.aicomponent`（硬依赖：从 `Phaser.Scene` / `Camera` 取宽高）

### Skill Definition

```yaml
tools:
  - read_file
  - write_file
inputs:
  - source: src/game/utils/UiLayout.ts
outputs:
  - computeUiLayout: function computing responsive UI scale parameters
  - UiLayoutConfig: interface
  - UiLayoutResult: interface
```

### 使用示例（Phaser）

```typescript
import { computeUiLayout } from '../utils/UiLayout';

// 在 Phaser Scene.create() 中
const { width, height, uiScale, vScale, centerX, centerY } = computeUiLayout(this);

// UI 元素定位示例（与第一节规范一致）
const buttonY = height - 80 * vScale;   // 距底 80 dp
const iconSize = 48 * uiScale;        // 边长 48 dp 的图标
```

---

## 四、与引擎 skill 的关系

- **`phaser.aicomponent`**：负责画布分辨率、Scale 模式、HiDPR 等 **引擎层** 行为；**UI 逻辑坐标**仍须服从本 skill **第一节** 的 \(W_r, H_r\) 定义（与主摄像机一致）。
- **`grid_board_layout.aicomponent`**：棋盘几何在已扣除 HUD 的可用区域内计算；所用 **\(W_r, H_r\) 与 uiScale/vScale** 须与本规范一致，避免棋盘与 UI 两套比例。

---

## Recipe

| 决策 | 原因 |
|------|------|
| **规范与实现分离** | Layout Canon（第一节）与引擎无关；若与 `phaser.aicomponent` 合并，则 Three.js 或 DOM 项目无法复用布局数学 |
| **数学符号表述** | 用 LaTeX 公式明确定义 uiScale/vScale 计算式，消除 Agent 对"缩放"语义的歧义（clamp 边界、最小维优先等） |
| **vScale 独立于 uiScale** | 垂向间距随高度变化，水平内容随最小维变化，两者不可混用；独立命名强制 Agent 正确选择换算系数 |
| **单点配置原则** | minScale/maxScale 从 GameConfig 读取，禁止各组件内写死，保证全局一致性 |

## Adapter

- **Role**: `responsiveLayout` — 2D UI 自适应布局规范（Canon）及 Phaser 参考实现
- **Provides**: 布局数学规范文档（引擎无关）、`computeUiLayout()` Phaser 绑定实现、`UiLayoutResult` 接口类型
- **Requires**: `phaser.aicomponent`（Phaser 绑定层硬依赖；规范层本身无运行时依赖）
- **Consumed by**: `grid_board_layout.aicomponent`、`top_ui_bar.aicomponent`、`bottom_ui_bar.aicomponent`、`playable_hud_layout.aicomponent`、`playable_end_screen_layout.aicomponent` 等所有涉及 UI 坐标换算的 skill
- **Integration point**: `src/game/utils/UiLayout.ts` —— 所有 Phaser Scene 在 `create()` 中调用 `computeUiLayout(this)` 获取布局参数

## 五、屏幕分区与分层（引专用规范 skill）

以下 skill **不重复** 推导 uiScale/vScale，仅在 **本第一节** 之上约定 **顶/底/棋盘/指引/结算** 的合同：

| skill | 内容 |
|-------|------|
| `playable_hud_layout.aicomponent` | HUD 顶/底区与中间 playable 区域高度扣减、相对 z-order |
| `playable_end_screen_layout.aicomponent` | 全屏结算：遮罩、主视觉安全区、主/次 CTA 锚点 |
| `playable_guidance_layer.aicomponent` | 指引层：遮罩/挖洞/手指缩放、与 HUD 及结算的深度关系 |
| `bottom_ui_bar.aicomponent` | （Phaser）底栏占位与 `GAME_BOTTOM_UI_BAR_HEIGHT` 与 `GameConfig` 对齐 |

Agent 处理 HUD / 结算 / 指引时 **应加载** 对应规范 skill，再落地到具体 `aicomponent` 代码。
