diff --git a/vtubermini/AGENTS.md b/vtubermini/AGENTS.md index 24afb56..1b883aa 100644 --- a/vtubermini/AGENTS.md +++ b/vtubermini/AGENTS.md @@ -1,43 +1,73 @@ -# AGENTS.md — VTuber Mini +# AGENTS.md — VTuber Mini 自适应规则(权威 · 统一) -> 给 codex / AI agent:在本项目调整页面**自适应布局**时,遵循本文件。 -> 目标:任何同事用 codex 微调任意页面,做法都统一、不再各搞一套。 +> 给 codex / AI agent / 同事:本项目调整**任意页面**的自适应布局,**以本文件为唯一权威**。 +> 本文件 = `docs/adaptive-architecture.md` 的分层方案 + 实战修正(对话框 `cd83c35`)整合后的最终版。 +> 旧版"别用 9:16 画布 / 架构文档已废弃"的说法**作废**——画布要用(放美术),只是 UI 别挂进去。 -## 这是什么项目 -540px 宽的移动端 H5(单 VTuber 粉丝养成 app)。React 19 + Vite + Tailwind 4 + Capacitor(Android)。 -在桌面浏览器里看 = 一个 540 宽的竖条居中显示。 +## 项目形态 +540px 宽移动端 H5(单 VTuber 养成 app)。React 19 + Vite + Tailwind 4 + Capacitor(Android)。 +真实像素、无 rem 缩放;桌面浏览器里 = 一条 ≤540 宽竖屏居中。包管理用 **pnpm**。 -## 自适应三条规则(就这么简单,别搞复杂) -1. **容器**:页面根容器宽 = `min(100vw, 540px)`,水平居中,高 = `100dvh`。窄屏(<540)自动占满 100%。 - - 全局 `.device-stage` 已是这个规则,页面挂在它里面即可。 -2. **不要用百分比绝对定位**。元素位置别用 `style={{ left: 'X%', top: 'Y%' }}` 这种绝对定位——手机宽度一变就错乱(这是本项目布局乱的根因)。 - - 用正常 flex / 文档流;或贴边的 `absolute`(`bottom-0` / `top-0` / `inset-x-0`)。 -3. **导航 / tab 贴屏幕底**:`absolute inset-x-0 bottom-0` + 内部 flex 等分。背景美术用 `object-cover` 铺满容器。 +## 一、核心心法:分层解耦(整套体系就这一句) +把页面里每个元素归到两类之一,**各用各的坐标系,别焊死在一起**: -## 两个必避的坑(亲测,栽过) -1. **Tailwind 4 会静默丢弃自定义 CSS 类里的 `cqw / cqh / container-type`**(Lightning CSS 把整条规则删掉,不报错)。 - → 关键尺寸**别写自定义 CSS 类,直接写 inline style,用 `vw/vh`**。例: - ```tsx -
- ``` -2. **`npm run build` 通过 ≠ 生效**。自定义 CSS 可能编译过但运行时根本没渲染(本项目曾让画布 `height` 塌成 0 却一直没发现,误以为成功)。 - → 改完**必须实测元素几何**,不能只看编译过。 +| 层 | 是什么 | 挂哪个容器 | 怎么定位 | +|---|---|---|---| +| **美术层** | 背景视频 / 底图 / 立绘 | **9:16 画布**:`.reference-fit-frame` 或 inline `aspectRatio:'9 / 16'` | `object-cover` 铺满,边缘允许裁切 | +| **UI 层** | 对话框 / 底栏 tab / 图标 / 头像 / 按钮——自带完整视觉的独立 PNG、要可点 | **真实屏幕容器**:`.device-stage`(`height:100dvh`)或页面级 `h-full`/`100dvh` 容器 | 锚屏幕边(`absolute inset-x-0 bottom-0` 等)+ `safe-area`,**绝不挂进画布** | -## 改完怎么验证(别跳过) +一句话:**背景管「好看」(可裁),UI 管「可用」(锚屏幕、永不裁)。** + +## 二、为什么必须这样(第一性 · 记牢这条因果) +- 9:16 画布高度 = `宽 × 16/9`,**随宽度变**。 +- 元素挂画布里、用百分比纵向定位(`bottom-[X%]`)→ 实际像素 = `X% × 画布高` → **随宽度上下漂**。 +- `.device-stage` 高 = `100dvh`(视口高),**不随宽度联动** → UI 挂这里才钉得住。 + +## 三、三类页面 → 三种做法 +| 类型 | 页面 | 做法 | +|---|---|---| +| 沉浸·交互页 | `home`、`anniversary` | 美术留画布 + UI 锚屏幕(见 §一)← 重点 | +| 沉浸·演出页 | `gacha`、`heart-moments` | 整段全屏演出,按设计稿**整体等比 `scale`**,可接受少量裁切 | +| 功能·流式页 | `my`/`shop`/`album`/各 ledger…(约 14 个) | flex/grid 文档流 + `safe-area` + `clamp()` 字号,天然较好,只补 token 死角 | + +## 四、铁律 + +**✅ 要这么做** +- UI 元素挂屏幕容器(`.device-stage` 或页面级 `h-full`),贴边 `absolute inset-x-0 bottom-0` / flex 等分。 +- 背景 `object-cover` 铺满画布(**不是 `object-fill`**,那会把图标拉胖)。 +- 关键尺寸写 **inline style**,用 `vw/vh/dvh/min()`。 + +**❌ 绝不这么做** +- **UI 挂 9:16 画布里用百分比纵向定位**(`bottom-[15.8%]`)→ 必随宽度漂。← 本项目布局乱、对话框漂的根因。 +- 自定义 CSS 类里写 `cqw / cqh / container-type` → Tailwind 4(Lightning CSS)**静默删整条规则、不报错**。改用 inline `vw/vh`。 +- 在有 `transform` 的祖先内用 `position: fixed` → fixed 被该祖先接管、相对它而非屏幕,照样漂。 + +## 五、判断一个元素该放哪(3 步 · 套到任意页任意元素) +1. **它是美术还是 UI?** 自带完整视觉的独立 PNG / 要可点 = UI;只是画面氛围 = 美术。 +2. **查它的定位祖先链**:最近一个 `position:relative/absolute` 的祖先,高度是 **9:16 画布派生**(`aspectRatio` / 套在 `.reference-fit-frame` 里)还是 **视口高**(`100dvh` / `.device-stage`)? +3. **若是 UI 却挂在画布派生高度上 → 移出来挂屏幕容器层。** 定位类基本不用动——`bottom-[X%]` 移到屏幕容器后,X% 就相对视口高,自然不漂。 + +## 六、反面教材(真实案例 · 别重蹈) +首页对话框原本 `