Files
youle_cocos/docs/superpowers/specs/2026-08-27-ui-asset-and-skin-design.md
T
joywayerandClaude Opus 5 5708926711 fix(skin): 修复最终评审发现的 6 处缺陷(junction 排除失效/meta 静默丢失等)
跨任务视角发现的问题:Critical1 materialize.mjs 的 junction 排除比较在
Windows 上因长路径前缀恒假、从未生效,且测试夹具的 junction 指向真源自身,
掩盖了此问题;Critical2 composeSkin 例外通道在 uuid 缺失/框架侧无 meta 时
静默失败,违反第二准则;Important3 可覆盖范围误把 theme/ 下的框架 TS 代码
也纳入;Important5 cli-entry 测试漏注册 check-skin/build-game;Important6
composeSkin 与 check-skin 各自拼路径,未共用 paths.mjs 权威推导;Important7
--platform 缺值时静默落到默认平台。逐条修复并补测试,Critical1 用诱饵框架
目录验证过能真正杀掉该 bug(变异推演见 fix report)。

spec §5 step5 的 dist/<name>/ 拷贝按要求标注为本期未实现,不实现。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 23:15:28 +08:00

26 KiB
Raw Blame History

framework/ui 资源归属 · 皮肤机制 · 打包裁剪 设计

状态:已与用户确认(brainstorming 通过),待转 writing-plans。 适用工程:cocoscreator_projects/YouleNexus(框架真源)+ cocoscreator_projects/games/*(子游戏)。 关联:架构 spec 2026-06-28-cocos-framework-design.md §2(monorepo + junction)/§5(换肤覆盖机制)/§7(new-game)/§8(版本升级);配置 spec 2026-06-28-config-channel-design.md(远程参数归属)。 本 spec 取代架构 spec §5 的落地形式(见 §0.3),是 framework/ui 层动工的前置。 后续另立 spec:组件替换(SeatView 契约、约定节点名、注册机制、按人数布局配置)。


0. 目标与背景

0.1 三条需求

  1. R1 独立打包:每个子游戏独立构建发布,包内不含任何其它子游戏的资源与代码。
  2. R2 各自皮肤:每个子游戏的平台界面皮肤可以不同。
  3. R3 框架可传播:框架改动(代码、界面、资源)方便传播到所有子游戏,消灭旧架构"人工替换到每个子游戏"的痛点。

0.2 决策依据(旧项目实测数据)

本 spec 的关键取舍不是推测,来自对旧 H5 项目的全量比对。记录在此,便于日后回看为什么这么定。

平台 UI 代码在子游戏间几乎完全相同:js/00_Surface/11_GameUI.js 模板 9862 行,doudizhu / niuniu / majiang_jx 与模板各只差 18 行,且这 18 行是功能开关(手机绑定是否走验证码、地址判定条件),不是布局差异。

例外:erqiwang 该文件仅 4629 行、与模板差 12379 行——属另一代模板,非同源演化,不作为依据。

平台美术资源是"同名覆盖"模式(Game_Surface_3/assets vs doudizhu/assets,全量 446 个文件,其中 444 个为可比对 PNG):

项 数量 占比(基数 444)
内容完全相同(共用) 328 73.9%
被替换(同名不同内容) 116 26.1%
— 其中尺寸一致 114 占被替换的 98.3%
— 其中尺寸不同 2 占被替换的 1.7%
非 PNG(未比对) 2 不计入基数
子游戏缺失的文件 0 —

推论(本 spec 的三块基石):

  • 约 74% 的平台资源在子游戏间共用 → 框架必须带一套完整默认皮肤,否则这 328 张相同的图要在每个子游戏各存一份,且框架改了不会传播(违反 R3)。
  • 文件清单完全一致、0 个缺失 → 同名路径覆盖是充分的皮肤机制。
  • 98.3% 的替换是同尺寸 → "只换图片内容、保留 .meta"这条约束现实可行;剩余 1.7% 走例外通道(§3.2)。

0.3 本 spec 取代架构 spec §5 的什么

架构 spec §5 的方向保留(子游戏定制全部落在自己的 game/ 目录、框架真源一字节不改),落地形式改变:

架构 spec §5 原方案 本 spec 方案
覆盖时机 运行时 AssetResolver.load(逻辑路径) 先查 override 后回退 构建期合成(§5)
资源加载 必须动态加载 保持静态引用

改变理由:Cocos 中 Prefab 上的 SpriteFrame 是 UUID 硬引用,运行时覆盖机制拦不到;要让 AssetResolver 生效就必须把资源放进 resources/ 或 Bundle,而那一档无法被依赖树裁剪、全量进包——被覆盖掉的框架默认资源会成为每个包里的死重量(按数据约 26%),直接损害 R1;同时框架 UI 将无法使用"美术在编辑器里拖图"这一 Cocos 主流开发方式。

前置事实(已与用户确认):美术产出同名替换包、不进编辑器,因此"编辑器里所见即所得地看到子游戏皮肤"不是需求,构建期合成的唯一代价被消除。

0.4 已确认决策

  • 皮肤合成放构建期,框架资源保持散图 + Auto Atlas(Cocos 的自动图集在构建期才真正打包)。
  • 框架带完整默认皮肤,子游戏只覆盖需要改的部分。
  • theme 契约覆盖资源覆盖 + 视觉变量 + 布局参数三项;平台功能开关不进 theme,走远程配置(复用 config/remote-config.ts 的 getParam)。
  • 定制通道共三条,组件替换是主力通道之一(§1),其完整设计另立 spec。

0.5 红线

  • 服务器零改动(CLAUDE.md 第一准则):本 spec 不涉及协议,roomtype / deskinfo 等协议契约归 GameModule,不进 theme(§4.1)。
  • 数据源权威唯一、下游不兜底(CLAUDE.md 第二准则):可覆盖资源清单不另建文件,框架文件树即清单(§3.1);override 匹配不上一律报错中止,不静默跳过(§3.2)。theme 的缺省值是该准则的明文例外,理由见 §4.3。

1. 三条定制通道

子游戏定制平台界面只有三条路,边界不得混淆:

通道 管什么 机制 本 spec
资源覆盖 换图、换音效、换 Spine 同名路径替换,构建期合成 §2 §3 §5
theme 变量 颜色、字体、字号、坐标/尺寸数值 编译期配置对象 §4
组件替换 换结构、换布局、换人数 注册不同的 Prefab + 可选行为覆写 另立 spec

边界规则:

  1. 资源覆盖与组件替换是两条不同的路。 override 是"换同名资源的内容",组件替换是"注册一个不同的实现"。自定义 Prefab 不走 override 的同名校验体系,不放 override/ 目录。
  2. 能用 theme 解决的不做组件替换,能用资源覆盖解决的不改 theme。就低不就高。
  3. 三条通道的产物全部落在子游戏 game/ 目录,框架真源一字节不改。

判断修正记录:架构 spec §5 将插槽/组件定制定位为"辅",依据是旧项目布局高度一致(0 个文件缺失)。该数据反映的是旧架构的能力上限(旧项目只能靠 Game_Config.Info.position[] 硬配坐标微调),非新框架的目标。新框架需灵活支持不同人数的不同布局,故组件替换升格为主力通道。


2. 资源归属规则

唯一判定标准:凡是放进 framework/ 的,都会出现在每一个子游戏的包里。

规则 1 — 框架带完整一套默认皮肤,不是占位图

依据 §0.2:73.9% 的平台资源在子游戏间共用。框架若不带默认,这部分要在每个子游戏各存一份,框架改了不会传播(违反 R3)。附带收益:新子游戏零美术即可跑通。

规则 2 — framework/ui/ 只放"所有子游戏都需要"的平台界面资源

判定问句:下一个子游戏还需要它吗? 否则放子游戏 game/。

需主动挡住的反例:两三个子游戏共用的对局资源(如麻将与跑得快共用的牌型图)。"部分子游戏共用"不构成进框架的理由——放进去等于让其余子游戏白背包体。这类宁可各自拷贝,也不建"部分共享层"(共享层同样会进所有包)。

规则 3 — 目录划分 = 图集划分,由框架单独负责

Cocos 的 Auto Atlas 只对同目录散图生效,因此目录结构就是性能设计。按加载时机切分:

framework/ui/
├─ atlas-common/    全程常驻:按钮、面板底、图标、通用弹窗    (.pac)
├─ atlas-login/     登录场景专用                           (.pac)
├─ atlas-hall/      大厅场景专用                           (.pac)
├─ atlas-room/      房间/牌桌的平台部分专用                  (.pac)
├─ standalone/      超图集尺寸上限的大图、整屏背景(不进图集)
├─ spine/           骨骼动画
├─ audio/           平台音效
└─ font/            字体

每个场景只加载自身图集 + atlas-common,不会为一张图拖进整张无关大图。图集划分是框架的事,子游戏不参与。

该结构同时保证 framework/ui/ 整体可在将来直接转为一个 Asset Bundle(热更预留,本期不做,见 §7)。

规则 4 — 子游戏侧目录与框架逻辑路径逐字对应

games/<name>/assets/game/
├─ override/        与 framework/ui/ 下路径一一对应的替换资源
├─ theme.ts         视觉变量 + 布局参数
├─ prefabs/         自定义组件 Prefab(组件替换通道,不走 override)
└─ ...              对局逻辑与对局美术(与框架无关)

示例:替换大厅开始按钮 → override/atlas-hall/btn_start.png。路径必须逐字对应,合成脚本才能机械匹配(§3)。

一条原有约束在本方案下解除

早期分析曾要求"框架图集里只能放不换肤的图,否则换一张要重打整个图集、影响所有子游戏"。本方案下该约束不成立——构建期合成发生在打图集之前,换肤图与不换肤图可同处一个图集,构建时用替换后的散图重打即可。图集划分因此可纯按加载时机设计,不必为换肤让路。


3. override 契约与校验

3.1 契约本身:框架的文件树就是清单

override 下每个文件的路径,必须能在 framework/ui/ 下找到同路径的默认资源。这是全部契约。

不额外维护 skinnable-assets.json 之类的清单文件——那会成为第二份真相,必然与实际文件树漂移。框架资源目录本身即权威清单(第二准则:数据源权威唯一)。

3.2 合成脚本的校验规则(构建期阻断式)

情况 处理
override 文件在框架里找不到对应路径 ❌ 报错中止构建
图片:同名、同尺寸、仅图片文件 ✅ 换内容,框架 .meta 原封不动
图片:同名、尺寸不同、仅图片文件 ❌ 报错中止,提示改为同尺寸或走例外通道
图片:需校验尺寸却读不出尺寸(非 PNG,或文件损坏) ❌ 报错中止(size-unreadable)——不得当作通过静默放行
同名、override 自带 .meta(例外通道) ✅ 拷贝两者,把框架默认 meta 的 uuid 覆写进去
扩展名/格式不一致(png → jpg) ❌ 报错中止
非图片(音效 / 字体):同名替换 ✅ 换内容,.meta 原封不动,不做尺寸校验
Spine(sp.SkeletonData):骨骼数据 + atlas + 贴图 ✅ 须整套一起覆盖,缺任一件即 ❌ 报错中止
框架有、子游戏未覆盖 ✅ 正常,用默认(不强制全覆盖)

Spine 的特殊性:新框架使用 Cocos 原生 Spine 支持(sp.Skeleton / sp.SkeletonData)。

旧项目因 gameabc 引擎不支持 Spine 而自行集成(SpineMgr.js / spine-canvas.js),该实现对新框架无参考价值,资源组织方式不照搬。

在 Cocos 的资源模型里,SkeletonData 是一个由骨骼数据、atlas 与贴图共同构成的复合资源,三者互相引用(骨骼数据引 atlas,atlas 引贴图区域坐标)。只替换其中一件会导致运行时错位或加载失败,且这类失败不会在构建期暴露——故强制整套覆盖,由校验兜住。

Spine 贴图豁免"同尺寸"约束:普通图片要求同尺寸,是因为区域坐标记在 .meta 里;而 Spine 的区域坐标记在 .atlas 文件内,整套替换时三者自洽,故贴图尺寸可变。校验须对 Spine 贴图跳过尺寸检查,否则会误报。

为什么必须保留 .meta:UUID 存放在 .meta 中,删除后重新导入会生成新 UUID,导致框架 Prefab 对该资源的引用全部断裂。

例外通道的用途:覆盖 §0.2 中 1.7% 的尺寸变化场景(含九宫格 border、pivot 等需要随尺寸调整的元数据)。由合成脚本负责覆写 uuid,保证引用不断。

错误信息要求:报错须指出子游戏名 + 文件相对路径 + 期望的框架路径,做到可定位(第二准则:错误早暴露、可定位)。

合成结束打印统计:皮肤命中 116 处,框架可覆盖资源共 446 个——一眼看出本次合成生效的范围。

3.3 该校验为资源层提供了"类 tsc 保护"

框架代码改动有 tsc 兜底,界面与资源改动此前没有任何保护。本校验补上资源层:

  • 框架新增资源 → 子游戏无需任何动作,自动用默认 ✅
  • 框架删除或重命名资源 → 所有覆盖过它的子游戏下次构建立刻报错,而非悄悄退回默认皮肤

即:框架改资源路径这类会波及全部子游戏的操作,从"无人知晓是否会炸"变为"构建期即炸,且指明炸在哪个子游戏"。

3.4 校验可脱离构建单独运行

npm run check-skin <name> 只执行本节校验,不实体化、不构建,秒级反馈。程序或美术拿到替换包即可自检。构建期那次是最后一道闸,不是唯一一道。


4. theme:视觉变量与布局参数

4.1 边界——哪些不进 theme

旧项目 Game_Config 是大杂烩,新方案须拆干净:

参数 归属
颜色、字体、字号、关键坐标/尺寸 ✅ theme.ts
roomtype 数组长度与结构 ❌ 协议契约,归 GameModule;须与服务器逐字节一致,见 docs/protocol/
支持的玩家人数集合、座位数 ❌ 子游戏固有属性,归 GameModule
手机绑定 / 支付按钮等功能开关 ❌ 远程配置,复用 config/remote-config.ts 的 getParam 分层取参
重连间隔、心跳超时等协议常量 ❌ 框架 core/constants.ts,子游戏无权改

4.2 形态

纯数据对象,编译期静态,无副作用。类型由框架定义,子游戏实现:

// framework/ui/theme/types.ts —— 框架定义契约
export interface ThemeConfig {
  colors?: { /* 主色 / 强调色 / 文字主次色 / 禁用 / 警告 */ };
  fonts?:  { /* 字体资源 + 各级字号 */ };
  layout?: { /* 关键位置与尺寸 */ };
}

// games/<name>/assets/game/theme.ts —— 子游戏只写要改的
import type { ThemeConfig } from '.../framework/ui/theme/types';
export const theme: ThemeConfig = {
  colors: { primary: '#C8102E' },
  layout: { myInfoAnchorX: 130 },
};

相对旧项目裸 JS 的 Game_Config,质变在于:字段名或类型写错,tsc 当场报错,不必等到真机上发现某个值没生效。

字段的起步集不在本 spec 穷举——见 §4.4。

4.3 缺省语义:第二准则的明文例外

ThemeConfig 全部字段可选;框架处提供一份 DEFAULT_THEME 承载全部缺省值;合并由框架内的 resolveTheme(gameTheme) 完成。

这看似"兜底",但正是 CLAUDE.md 第二准则明文列出的唯一例外:"来源本身明确定义了「可选 + 缺省语义」,且该缺省写在来源处(而非散落在各下游)"。框架是主题的权威来源,缺省集中于 DEFAULT_THEME 一处,下游子游戏无需任何兜底。

不得以此为先例:本例外仅适用于 theme。协议数据(如 login 响应字段)缺失仍须显式暴露,不得 ?? 抹平。

4.4 「可改范围」如何维护才不失控

架构 spec §10 已识别风险:"皮肤变量预留不足,子游戏被迫改框架"。解法不是预先猜全清单,而是依靠两条性质:

  1. 框架 UI 组件禁止硬编码任何颜色、字号、字体、关键坐标,一律从 ThemeProvider 读取。这是框架实现期的硬规矩。
  2. 加字段是非破坏性的(可选 + 有默认),任何时候都能加;删字段或改语义才是 breaking change,须走版本说明通知所有子游戏。

因此本 spec 只定分组与规则,不预先穷举字段:清单是框架 UI 抽象过程的产物,逐项浮现、按需扩充。起步集 = 实现第一个平台界面时确定需要的那几个。

4.5 消费方式:静态读取,不做响应式

皮肤在构建期即定死,运行时不变。框架启动时 ThemeProvider.init(resolveTheme(theme)),其后组件纯静态读取。

不引入响应式——core/reactive.ts 的 signal 服务于会变的状态(玩家资产、房间状态);主题不变,套用只是纯粹的复杂度。运行时切换皮肤见 §7 非目标。


5. 构建流水线

一条命令,从"挂着 junction 的开发工程"产出可发布包,同时完成校验、合成、零冗余裁剪。

npm run build-game <name> [--platform android]

1. 版本校验   子游戏与宿主 creator.version 一致,否则中止(复用 check-cocos-version)
2. 实体化     games/<name>/ → build-workspace/<name>/
              assets/framework 由 junction 变为真实目录拷贝
3. 皮肤合成   assets/game/override/** 覆盖到 assets/framework/ui/**
              按 §3.2 校验;任一不合法即中止;打印命中统计
4. 构建       调 Cocos CLI 在临时工程上构建
5. 产出       写 build-info.json(拷至 dist/<name>/ 本期未实现,见下)

dist/<name>/ 拷贝:本期未实现。 build-game.mjs 目前止步于 build-workspace/<name>/ 内调用 Cocos CLI 构建 + 写 build-info.json;把构建产物拷到独立的 dist/<name>/ 尚未落地 (构建产物的实际目录结构未经真实构建验证,贸然实现拷贝逻辑等于凭空猜测路径)。

5.1 四条硬规则

① 绝不在框架真源上做合成。 "改真源 → 构建 → 还原"的做法被否决:构建中断或崩溃会留下被污染的真源,而真源为所有子游戏共享的唯一副本。合成只在临时工程副本内进行,真源全程只读。

② 发布链路完全不依赖 junction。 第 2 步实体化直接从 YouleNexus/assets/framework 读真源拷贝,不要求 junction 存在。CI clone 后无需 setup-links 即可构建。

junction 只服务开发期的即时性(R3);发布期靠实体化获得自包含工程。架构 spec §10 记录的风险"junction 不被 git 跟踪,团队成员环境缺链接"在发布链路上因此不复存在——不是绕过,是发布链路根本不走该路径。

③ 临时工程不得置于 games/ 下。 否则 scripts/lib/paths.mjs 的 listGameProjects() 会将其识别为真实子游戏,污染 setup-links 与 check-cocos-version。固定放 build-workspace/,加入 .gitignore。

④ Cocos 编辑器可执行文件路径只在一处定义(环境变量或单一配置文件),其余脚本引用(第二准则常规应用)。

5.2 首次构建的性能问题

临时工程为全新工程,Cocos 首次打开须完整导入 assets 重建 library;框架 + 子游戏资源合计可达上万文件,该步骤可能耗时数分钟至十余分钟。

对策:保留 build-workspace/<name>/library/ 跨次构建复用,仅在资源变化时增量导入。代价为磁盘占用(每子游戏一份 library)。

该对策列入 §6 待实测。方案整体可行性不依赖它(最差情况每次全量导入,只是慢),但流水线的日常可用性依赖它。

5.3 产物追溯:build-info.json

{
  "game": "doudizhu",
  "frameworkCommit": "<git rev-parse HEAD>",
  "builtAt": "<ISO 时间>",
  "platform": "android",
  "skin": { "matched": 116, "frameworkTotal": 446 }
}

落地"框架版本可追溯",成本近零:出问题可立刻查清该包所用框架版本与皮肤合成生效程度。


6. 待实测清单

以下三条是本方案的承重点,须在第一个真实框架场景/资源出现后立即验证,不得凭推断实现。

# 待验证 验证方法 失败后的备选 实测结论(2026-08-27,Task 2)
1 Cocos 3.8.8 的 Auto Atlas 确在构建期打包,构建前替换散图能被正确纳入图集 造一个 .pac 目录,替换其中一张散图后构建,检查产物图集内容 改为"图集整体作为覆盖单位",由子游戏提供整套 plist+png ⏸ 阻塞(非证伪)。真正卡住的不是"构建能否跑完",而是**"造不出一个真实的 Auto Atlas 资产"**:MCP asset.create 只支持 url/content/overwrite,没有资产类型参数;对 .pac 命名文件夹做 refresh/reimport 也不会把 importer 从 "directory" 转成 "auto-atlas",多次独立尝试一致。(editor.build/editor.open_build_panel 确实也只打开构建面板要求人工点击——但项目自己的 build-game.mjs 已实现走 CocosCreator.exe --project <dir> --build "platform=..." 的官方无头 CLI 构建,不经过 MCP;只是本机 COCOS_CREATOR 未配置、也未定位到编辑器可执行文件,这条路本身也未验证可用,且即便可用也不能替代"创建 Auto Atlas"这一步——那始终是编辑器 Assets 面板 Create > Auto Atlas 的菜单命令,CLI 构建帮不上。)需人工在编辑器 GUI 内手动执行该菜单命令后再复测。在此之前不得默认本假设成立去推进 Task 3 的图集相关设计。
2 例外通道中,除顶层 uuid 外,图片 .meta 的 subMetas(spriteFrame 子 uuid)是否亦需同步覆写 用尺寸不同的图走例外通道,检查 Prefab 引用是否仍有效 合成脚本一并覆写 subMetas 的 uuid 🟡 部分验证,范围窄于本行原意。实测的是更基础的前提:保留原 .meta、只换图片内容(同尺寸)后刷新,顶层 uuid 与全部 subMetas.uuid 均未变化;换成 128×128(仍不提供新 .meta,未走例外通道)后刷新,顶层 uuid 依旧不变,且 sprite-frame 子 meta 的 width/height/rawWidth/rawHeight/vertices/uv 被 Cocos 自动重算为 128×128(前后 meta 全文见 task-2-report.md)。未验证的是本行字面所指的例外通道场景(override 自带一份独立生成的 .meta,合成脚本只覆写顶层 uuid,问 subMetas 里的子 uuid 要不要也同步覆写)——因待验证项 1 阻塞、无法在真实 .pac 图集环境下复测,这条更精确的问题仍待专项验证。spec §3.2 的例外通道设计维持不变,不降级、不简化。
3 build-workspace/<name>/library/ 跨次构建复用是否可靠,资源被替换后增量导入是否正确刷新 连续两次 build-game,第二次改动 override,比对产物 放弃缓存,每次全量导入(仅影响耗时) ⏸ 阻塞:缺构建环境(2026-08-27,Task 8)。实测需要 COCOS_CREATOR 环境变量指向 Cocos Creator 3.8.8 可执行文件——本机未配置该变量,且 where.exe CocosCreator.exe 未能在 PATH 上定位到编辑器可执行文件,build-game.mjs 的实际构建步骤(内部调用 CocosCreator.exe --project <dir> --build "platform=...")无法执行,因而无法运行"连续两次 build-game 比对耗时/产物"的实测动作。此外,buildGame 当前实现每次都会 rmSync 整个构建工作区(含 library/)后重新实体化,即便环境就绪,字面意义上的"library 跨次复用"在现有实现下也不成立——library 目录会随工作区一起被清空重建,第二次构建拿到的是全新的 library,不存在缓存复用可言。故本行结论有两层:(a) 环境阻塞,实测动作未能执行;(b) 静态阅读代码可确认现有实现未实现"保留 library 复用"的设计,若要验证复用效果需先改造 buildGame 为"不整体 rmSync 工作区、只刷新 assets",这已超出本任务范围,留作 spec 结尾「后续计划衔接」中已列出的独立任务。在此之前不得默认 library 复用已生效或已失效去做性能相关决策。
4 Cocos 的 sp.SkeletonData 在"整套替换内容、保留全部 .meta"后引用是否仍自洽(骨骼数据 ↔ atlas ↔ 贴图的 uuid 关联记在何处) 用一套不同的 Spine 资源整套替换,检查场景内动画是否正常播放 Spine 改走组件替换通道(子游戏注册自己的 sp.Skeleton 节点),不走资源覆盖 ⏸ 阻塞:仓库无 Spine 素材。projects/*/assets/spine/ 全部为空,无任何可用 Spine 导出资源。cocos_spine 工具的全部 action(info/list_animations/list_skins/set_animation/set_skin/set_property/set_data/add_socket/remove_socket)都要求场景内已存在带 sp.Skeleton 组件的节点,无法凭空验证。已在 framework/ui/README.md 加提示,待第一套真实 Spine 资源到位后专项验证,不假定其可行。

7. 非目标(YAGNI)

  • 运行时切换皮肤(同一包内多套皮肤、节日换肤)。皮肤构建期定死;§2 的目录结构不阻碍将来扩展。
  • 强制子游戏全量覆盖。覆盖 1 个文件与覆盖 116 个文件同样合法。
  • 单独的可覆盖资源清单文件。框架文件树即清单(§3.1)。
  • framework/ui 的 Bundle 化热更。§2 规则 3 的目录结构为其预留,本期不实现;是否引入需另行评估合规与版本管理成本。
  • 编辑器内预览子游戏皮肤。已确认美术不进编辑器,无此需求。

8. 与其它 spec 的接口

  • GameModule(sdk spec,待写):须声明支持的玩家人数集合与 roomtype 契约。注意人数是运行时属性(由房间 roomtype 决定,同一子游戏可支持多种人数),布局须按运行时人数选取。
  • 远程配置(config-channel-design.md):平台功能开关与 UI 类远程参数复用 getParam 分层取参,本 spec 不涉及。
  • 组件替换 spec(待写):SeatView 契约(统一 render(state) 而非逐字段 setter)、约定节点名清单、注册机制、按人数的布局配置结构。其前置是 RoomStore 的完整建模(platform Store 第二切片)。
  • 工具链(monorepo-scaffold-toolchain.md):新增 build-game / check-skin;new-game 需增建 override/ 与 prefabs/ 骨架目录。