Files
NumberSwipe_New/docs/2026-10-21_程序化美术-明亮教具室实现方案-report.md
T

345 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 数字一笔画 · 明亮教具室程序化美术实现方案
日期:2026-10-21|状态:技术方案,尚未接入运行时|首个落地版本:`wechat-campaign-200-r2`
以 **Canvas 2D 路径几何+参数化二维材质+状态驱动动效** 实现明亮教具室。背景、积木、桥接、图标、按钮和特效全部由程序生成,形成暖黄纸板、奶油教具垫、轻厚度彩色积木的视觉层次。
本方案承接[完整美术与 UI 设计报告](2026-10-21_美术设计-明亮教具室-report.md)及其[设计令牌](design/bright-classroom/tokens.json)。本次交付实现设计,不修改规则、正式渲染、关卡和发布包。
## 1. 制作原则与资源边界
### 1.1 “不用图片”的执行定义
| 内容 | 生产方式 | 交付形式 |
|---|---|---|
| 背景、舞台、积木、按钮 | 圆角路径、多边形、实色、有限渐变 | JavaScript 绘制模块 |
| 功能图标、类别、墙门、通道 | 归一化坐标、线段、圆弧、贝塞尔曲线 | 路径命令与参数 |
| 数字、中文 | 字体绘制;数字可选专用轮廓 | 字体文件或矢量路径数据 |
| 首页标题 | 第一版用字体叠绘;精修版用原创字形轮廓 | 文字排版或路径数据 |
| 动效、扫光、少量纸片 | 时间插值、裁切、几何粒子 | 动画代码 |
| 绘制缓存 | 运行时生成的离屏 Canvas | 临时内存,可随时重建 |
游戏不加载 PNG、JPG、WebP、预烘焙阴影图、图标贴图、粒子贴图或图片图集。参考图只用于美术比对,不进入运行包。不用 SVG 图片加载器绕过限制;如需要矢量形状,直接执行路径命令。
离屏缓存由代码生成,不属于外部图片美术资源;现有 `drawImage(boardCanvas, …)` 这种 Canvas 合成可以保留。字体是文字资源,音频沿用已有方案,二者与图片资源分别管理。
### 1.2 风格还原的着力点
优先还原“大色面、圆角、短底沿、左上亮边、干净数字、短促按压”。参考图中的颗粒、软糯高光和明显浮雕数字不作为生产目标,避免密集关变糊。二维分层足以建立所需触感,首版继续使用当前 Canvas 渲染链路。
首页可承载更多品牌厚度;正式对局缩小标题,让棋盘成为主物体。材质强弱按单位格节距决定,2×2 大块与普通块使用同一厚度、圆角基准和数字字号。
## 2. 当前工程与接入路线
### 2.1 已有能力和实际缺口
| 已核对来源 | 当前行为 | 对实施的影响 |
|---|---|---|
| `src/main.mjs` | Canvas 绘制导航、按钮、选关、规则面板;合成棋盘和提示 Canvas | UI 和棋盘必须一起升级 |
| `src/upstream/ui.mjs` | `localGeometry`、`paintCell`、`drawBridge`、`drawBarrier` 已程序绘制 | 可沿用几何来源,重做材质和信息布局 |
| `src/upstream/rules.mjs` | 提供 `units`、`outlineUnits`、共边、墙门状态和判定 | 逻辑结果由此消费,不在美术层重算规则 |
| `src/hints.mjs` | 独立透明层,擦除已走单位多边形,按中心点连线 | 应升级为新几何遮罩及语义避让 |
| `build.mjs` | 构建时变换上游 UI,注入微信宿主、分段提示和教学入口 | 皮肤接入需纳入受检查的构建变换 |
当前 `draw()` 同时负责几何、表现和按钮状态回写;不能整段替换而漏掉剩余块数、教学反馈、撤销禁用与下一关显隐。当前异形轮廓工具只追踪一个闭环,不能直接声称支持带内孔的单块。当前完成态亮紫、类别冲突整面染红,也需改成报告规定的状态合成。
### 2.2 建议的模块拆分
以下是拟新增模块,当前尚不存在;统一位于 `wechat-campaign-200-r2/src/bright-classroom/`。
| 模块 | 责任 | 不承担的工作 |
|---|---|---|
| `theme.mjs` | 消费原设计令牌、派生随 u 变化的材质参数 | 不另建一套手写颜色 |
| `geometry.mjs` | 多环轮廓、偏移、圆角、安全区、共边入口 | 不决定合法邻接 |
| `scene.mjs` | 把现有规则结果转换为块、边、标注、遮罩的表现数据 | 不调用求解器决定玩家行为 |
| `material.mjs` | 底沿、块面、边界、亮边和投影 | 不画数字或规则 |
| `board-renderer.mjs` | 组织棋盘各绘制通道 | 不写存档和播放声音 |
| `symbols.mjs` | 数字辅助框、奇偶、通道、类别、墙门 | 不以图形碰撞替代判定 |
| `icons.mjs`、`ui.mjs` | 统一图标与按钮、面板、标签 | 不显示未实现的设置能力 |
| `layout.mjs` | 舞台、UI、安全区、文字保留区和输入坐标变换 | 不改变关卡格点 |
| `motion.mjs` | 时间轴、按压、门切换、扫光、减少动态 | 不阻塞输入 |
| `cache.mjs` | 轮廓、材质和静态 UI 缓存及失效 | 不持有第二份玩法状态 |
数据流为:**关卡和路径 → 现有规则结果 → 表现场景 → 几何与布局 → 分层绘制 → 主 Canvas 合成**。触摸经同一布局逆变换回到原规则坐标。
### 2.3 保留快照来源的接入方法
1. 保持 `src/upstream` 快照及其来源哈希不变。在本地新增构建适配模块,扩展现有 `build.mjs` 的 UI 变换。
2. 首先建立明确的“几何准备/绘制/UI 回写”接缝,再委托新 renderer 绘制。保留原输入、求解、存档、提示控制器、通关及教学业务。
3. 构建变换以明确入口与预期匹配次数检查,入口不符直接构建失败。禁止对全部 `fillStyle` 或颜色字符串做无范围替换,也不运行时拦截 Canvas API 猜语义。
4. 主题开关放在构建配置,支持旧皮肤与新皮肤对照;第一阶段不增加玩家设置项。
5. `renderLesson` 必须使用同一 renderer;预览调用的临时状态要完整保存和恢复,新增场景及缓存状态也必须隔离,避免教学修改玩家棋盘。
6. 构建变换模块与快照哈希一起纳入回归。未来如接入新上游,先检查接缝,再更新变换。
不直接依靠只读 `variantSnapshot()` 重建整个正式渲染:它当前不包含完整轮廓、共边入口和文字保留区。应由同一几何准备过程向棋盘、提示和教学输出共同的 Scene 数据。
## 3. 几何:先保证“一整块只算一步”
### 3.1 分开管理三种几何
| 几何 | 用途 | 约束 |
|---|---|---|
| 逻辑几何 | 原有命中、相邻、阻挡和手势插值 | 按原规则;皮肤不扩大相邻重叠触点 |
| 显示轮廓 | 缩缝、圆角、底沿、材质 | 不反馈给规则判定 |
| 信息安全区 | 数字、奇偶、类别、通道、提示避让 | 基于实际文字边界和轮廓内距生成 |
单元边、块 ID、共边入口全部保留稳定标识。显示轮廓按关卡和布局生成一次,按压动画只改变表现变换。
### 3.2 矩形与异形轮廓算法
1. 从 `units(c)` 获取占用单位格;每格生成定向四条边,共享内部边抵消。
2. 连接剩余有向边,遍历所有闭环;按包含关系识别外环与内孔,统一绕向,删除共线点。
3. 同一块的单位格先形成完整轮廓,再缩进、倒角、投影。任何中间单位格线都不进入材质绘制。
4. 面轮廓向块内缩进 `inset = 0.045u`,凸角半径 `clamp(6, 0.18u, 12)`;凹角最多 `0.06u`,窄凹口可保持直角。
5. 正交轮廓按边法线偏移并求相邻偏移边交点,限制尖角与短边;检查偏移后自交、环消失和细颈收缩。失败时先减小局部圆角和缩进,仍失败则使用保拓扑直角轮廓。
6. 外环与内孔反向绕制,用基础非零绕数填充和裁切;目标宿主需做内孔自检。若目标不满足裁切行为,独立离屏遮罩擦出内孔后合成,不能擦除主画布已有内容。
矩形走专用圆角矩形快路径。禁止对 L、T、S 等异形逐单位格画圆角矩形,那会产生内部缝和多份阴影。棋盘块之间围成的空洞与“单块自身内孔”分别测试,后者只有经内容审计确认存在时才作为当前内容覆盖项。
### 3.3 六边形
沿用当前轴向坐标到竖屏顶点的转换。当前 renderer 的 `unit` 是外接半径缩放量,视觉用的六向中心距为 `uHex = √3 × unit`;材质和文字比例统一使用 `uHex`。
从实际顶点包围盒求适配比例;圆角上限 `0.11uHex`。墙门和桥仍取未圆滑的真实共边,不能把 q/r 范围当矩形宽高,不能用缩圆后的外轮廓推导邻接。
### 3.4 数字锚点
普通矩形保留整体中心;异形以现有占用单位格安全锚点为起点,再检查整组文字矩形是否留在块内。候选点按离中心距离、到外环/内孔距离、与墙门及通道的间隔排序;候选选择与 ID 稳定绑定。
同一关锚点固定,访问前后数字不跳位置。若完整信息组放不下,切换预定义密集排版;必要说明移至固定反馈栏。不得仅检查中心点在块内,就认定两位数和角标一定可放下。
## 4. 材质:用二维叠层表现轻厚度
### 4.1 每块的绘制配方
| 通道 | 实现 | 起始参数 |
|---|---|---|
| 接触投影 | 整块轮廓的短投影,静态或材质缓存时生成 | x0、y3、blur5、墨色10% |
| 底沿 | 完整轮廓向下平移后实色填充,再由面覆盖 | `h=clamp(2,0.055u,4)` |
| 正面 | 同一轮廓填充,中心文字区域尽量纯色 | 奶油/紫/类别面 |
| 有效边界 | 清楚的连续描边 | 1.25,密集态1.5 |
| 左上倒角 | 只强调朝光侧的内侧轮廓段,裁切于面内 | 0.75–1;紫块用 `primaryEdge` |
| 右下收边 | 低强度暗边,必要时省略 | 不能叠成第二圈厚黑边 |
未走面 `#FFF8EA`、底沿 `#D8C4A0`、边界 `#8A7660`;标准已走面 `#6552D9`、底沿 `#49379E`。蓝橙类别块保持原类别面,访问仅增加紫内框和桥。
先按轮廓绕向确定外法线,再与左上光方向做点积选择受光边。圆角亮边用路径分段近似,端部淡化;不把整个块复制一层白描边。块面可选线性微渐变,各 RGB 通道变化不超过6,不用逐像素噪声、法线贴图或实时模糊制造质感。
投影用于接触感,边界负责可读性。全板先画底沿和投影,再画所有块面,避免后一块阴影压在前一块数字上。内孔处的底沿也按相同上下关系裁切,不填平孔洞。
### 4.2 桥接应成为积木的一部分
桥只出现在玩家实际连续访问、规则允许跨越的共边上,宽度取 `0.42u`,六边使用 `0.42uHex`,并受有效共边长度限制。
- 合并连续共线的单位共边,去掉端点安全距;多段共边按实际入口选择,选定后保持稳定。不能无条件取 `sharedSegments()[0]`。
- 取共边中点和法向构造短胶囊,沿法向长度覆盖两侧缩进及少量重叠;不拿两块数字中心直接相连充当实体桥。
- 绘制桥底沿和面,与块面小幅重叠以消除抗锯齿裂缝;隐藏被桥穿过的局部边界和亮边,保留其他外边界。
- 桥厚度动效仅在沿共边方向展开,跨缝方向始终连通;墙保持可见,锁定开启门保留框与扣件。
- 双色关桥可用紫色,但只覆盖桥本身,不能涂满两端类别面。
桥的连接关系来自逻辑,材质动画不会让一条非法边看起来可通过。
## 5. 状态、规则符号与提示合成
### 5.1 用组合状态替代单一颜色
每块至少分开持有:类别、已访问步号、固定要求、通道状态、冲突、当前末端、提示保留区。场景引用规则给出的墙门状态;这些字段共同决定绘制通道。
| 状态组合 | 块面和数字 | 附加表现 |
|---|---|---|
| 普通未走 | 奶油面,固定条件深墨字 | 固定条件内框 |
| 普通已走 | 紫面白步号 | 深紫底沿、桥 |
| 类别已走 | 蓝/橙面深墨步号 | 圆/三角、2单位紫内框 |
| 固定要求已满足 | 沿所属访问态 | 条件框保持,以适配底色的浅/深色呈现 |
| 普通冲突 | 深红面,实际步号 | 叹号和具体要求;反馈栏说明 |
| 类别冲突 | 保留类别面与形状 | 红色局部角标和边;不整面染红 |
| 当前末端 | 沿所属访问态 | 一组短焦点角标 |
| 提示 | 保留全部底层状态 | 独立白芯深边轨迹 |
| 完成 | 保留最终基础颜色和数字 | 外围短扫光、对勾与完成文案 |
空路径的固定1仍要清楚标识起点;表现模型将“起点条件”和“已访问”分开,计数、桥和实际步号完全依据玩家路径。
### 5.2 规则符号的程序实现
| 元素 | 几何做法 | 排版与语义 |
|---|---|---|
| 奇偶 | 字体绘制“奇/偶”+条件框 | 已走后数字在上,奇偶在下,副标目标11–12 |
| 通道 | 端口到中心的折线路径,浅衬线+深槽线 | 六种方形直/弯通道,可反向,无箭头;数字右上 |
| 类别 | 实心/描边圆与三角 | 持续可见;与通道组合时类别左下 |
| 永久墙 | 真实共边上的深墨连续条带,裁切黄色短斜线 | 宽6–8;不使用虚线代替实体阻挡 |
| 关闭门 | 两侧端框+中间连续棕色门片 | 附“关”,挡条连续 |
| 开启门 | 保留端框,门片收向两侧 | 中间明确留空,附“开” |
| 已穿门 | 开口+固定扣几何 | 可读“已过”;回退由规则恢复 |
通道位置由真实端口方向决定,中心数字与通道分区。非常密集时优先保留数字、类别和开口形态,将冗余解释移到反馈栏,不把全部信息缩成难辨的小点。
六边版只渲染实际数据支持的机制;若后续增加六向通道,应补六向端口合同,不能直接套用当前四向 `l/r/u/d` 绘制函数。实验转墙只接六边原型,不加入当前200关皮肤范围。
### 5.3 正式绘制顺序
| 顺序 | 内容 |
|---|---|
| 1 | 暖黄背景、外围静态纹样、舞台 |
| 2 | 全板块体与桥的投影、底沿 |
| 3 | 块面、桥面、有效轮廓及局部倒角 |
| 4 | 类别、条件框、通道、数字、当前位置、局部错误 |
| 5 | 独立提示层,先做遮罩和语义避让后合成 |
| 6 | 最终墙门及必要语义补绘 |
| 7 | 导航、反馈、操作按钮、弹窗 |
提示遮罩是必要条件;只把底层数字画在上面没有用,因为独立提示 Canvas 会更晚合成。
### 5.4 提示升级
保留当前分段提示的请求、段末消失、偏离、撤销恢复行为;只升级显示路线和遮罩。
1. 路线按“块内引导点 → 合法共边入口 → 下一块内引导点”构造。异形内部折线限制在所属块的占用区域内,必要时在占用单位格图上寻路;这是提示画线,不改变玩家规则。
2. 已走块遮罩取完整显示轮廓,并包含底沿和抗锯齿安全边;已走桥也加入遮罩。覆盖错误路径的已走块同样擦除,不能只擦正确前缀。
3. 数字、条件副标、类别、通道核心和墙门各输出文字/图形保留区。提示路径绕行或切段;光点与端点环采用相同裁切。
4. 提示全程只改透明提示层;`destination-out` 只能在此层或专用遮罩层执行,不用于擦除主画面。
5. 白芯4–7,深色外线总宽再增3–4;透明度与底色合成后复核。减少动态采用持续静态虚线,保留整段信息。
优先从真实共边生成引导路线,避免中心连线跨出 L 形块、穿过空洞。数字处允许线段中断,不为追求连续发光而遮挡关键要求。
## 6. UI、文字和屏幕适配
### 6.1 通用组件
背景默认 `#FFE69A`,可选底端 `#FFDE79`;舞台 `#FFF6DF`。背景仅生成3–5个静态圆、圆角方框、三角轮廓和弧线,使用关卡/页面稳定种子,避免每帧随机闪变;棋盘与操作区周围保留净区。
按钮由圆角路径、底沿、图标路径和文字构成。主按钮紫面白字,次按钮奶油面深墨字;常规高64、圆角18,紧凑高52、圆角14。按下表面下移1单位,底沿变浅,触点和布局不动。重开/撤销/指路按当前微信能力显示,完成后同一区域替换下一关。
功能图标统一24单位母版、2–2.5笔画:重开用回转弧+箭头,撤销用左回箭头,指路用圆弧灯泡+短光线,设置用齿轮路径,选关用圆角网格,对勾用两段折线。绘制前统一缩放与设置圆端点,颜色从语义令牌取。禁止使用 Emoji 代替正式图标,以免平台外观不同。
选关卡片、弹窗、规则教学共用组件。新增首页属于全页面阶段;现有微信包起始选关页并不等于已经有独立首页。新开关必须接线、持久化并通过生命周期检查后才显示。
### 6.2 字体选择
正式目标采用 Nunito 800 数字和 Noto Sans SC 中文。先清点实际使用汉字与字号,按许可交付所需字集及声明;不能根据字体名称就假设宿主已经可用。
字体加载属于平台适配工作,实施时核对目标基础库支持的加载方式和路径约束。进入对局前完成关键字形准备;若失败,使用明确回退并一次性完成测量,避免解题中途换字体。数字0–9也可制作原创贝塞尔轮廓,支持1–36拼排,维持一致字形;中文仍保留文字排版能力,不逐句做成轮廓。
路径命令、文字测量缓存和离屏绘制均不需要生产图片资源。首页品牌首版可用标题文字叠绘米白外缘、短底沿与珊瑚/紫主字;原创轮廓精修列为P2,避免把标题制作变成首个技术阻塞点。
### 6.3 自适应和统一坐标
矩形按占地包围盒计算 `u = min(stageInnerW/C, stageInnerH/R, 64)`,优选56;根据内容和屏幕进入密集布局。当前代码允许96/110的放大上限,要在新皮肤布局中改成设计报告的限制。
7列36块盘面:375宽采用外边距12、内边距8时净宽335,`u≈47.9`;320宽同策略净宽280,`u≈40`。后者需要真机检查,不能承诺全部达到44触点。
固定顶栏、反馈和底部操作区,舞台使用剩余高度。常规单数字约 `0.50u`、两位数约 `0.44u`;低于报告目标字号时输出布局诊断,不默默缩到不可读。
`Layout` 同时输出舞台原点、缩放、UI矩形和逆变换。同步修改当前 `event()` 中硬编码的 `top+82`,以及棋盘合成位置和尺寸;这三处必须取同一份布局。DPR只决定 backing store 清晰度,不能重复进入触摸坐标和逻辑单位。
## 7. 动效与运行调度
| 事件 | 时间与表现 | 规则/输入约束 |
|---|---|---|
| 按钮 | 80ms按下、120ms恢复,最多0.98缩放 | 点击即时生效 |
| 落格 | 140ms,0.985压低后最高1.015回稳 | 固定命中;窄异形/墙门附近只变亮边 |
| 桥接 | 120ms扩展宽度 | 不出现暂时断路 |
| 数字 | 100–120ms淡入 | 固定条件持续可读 |
| 撤销 | 100ms残影淡出 | 路径立即回退,批量撤销不串行等待 |
| 错误 | 200ms红角/边强调 | 墙挡后末端不动,不全屏摇晃 |
| 门 | 160ms门片收拢/展开 | 连续输入合并到最新目标状态 |
| 完成 | 总计320ms外缘扫光,完成反馈500ms | 下一关可手动点击,不按块逐个等待 |
统一使用当前时刻求进度,采用设计令牌中的缓出曲线;新事件从当前视觉值过渡到新目标,旧门动画不排队。形变围绕稳定锚点,底沿与亮边一起响应。
减少动态时取消缩放、抖动、光点和粒子,门直接显示最终形态。退后台取消 RAF 和临时动效,回前台按最新玩法状态重建,清除过期动画;沿用当前音频中断管理,不额外合成声音。
当前主循环每帧全屏绘制,棋盘自身还会重设 Canvas 尺寸。新方案改为脏状态触发:输入、布局、页面、提示时间或动画进度变化才更新。无活动动效时停止 RAF;反馈自动消失、字体完成等异步变化显式标脏,不依赖常驻循环才看得到变化。
## 8. 缓存、兼容与性能预算
### 8.1 分层缓存
| 缓存 | 键/失效条件 | 策略 |
|---|---|---|
| 本地轮廓与真实共边 | 内容修订、几何ID | 与颜色和访问态无关 |
| 屏幕几何和信息区 | 舞台尺寸、缩放、字体、密度档 | resize与字体准备后重建 |
| 材质轮廓或小块缓存 | 轮廓、u、DPR、面类别、质量档、主题版本 | 惰性生成,有总量上限 |
| 静态背景和UI | 页面、尺寸、主题、文字 | 状态变化时更新 |
| 教学预览 | 教学关、尺寸、主题 | 不复用玩家可变Scene |
首版无需为每块每种状态建缓存,也不必每层创建全屏 Canvas。数字和墙门动态绘制,只有测量数据支持时才进一步缓存。Canvas宽高只在尺寸/DPR真正变化时赋值,避免每次落格重新分配并清空状态。
375×812、DPR3的全屏RGBA表面原始像素约10.45MiB,三张全屏表面约31.36MiB,尚未计宿主副本和其他内存。棋盘/提示按实际区域分配,缓存计数加上字节估算;质量降级先关模糊与粒子,再降低非关键层缓存分辨率或DPR,避免常驻大量全屏离屏层。
### 8.2 平台实现约束
基线采用项目已经使用的 `beginPath`、`lineTo`、`quadraticCurveTo`、`arc`、`fill`、`stroke`、Canvas合成方式。轮廓缓存为普通路径命令数组,重放到 context;不把 `Path2D`、原生 `roundRect`、滤镜或某种额外离屏接口作为必需前提。
新增裁切、渐变、投影和字体加载在微信目标环境逐项自检。原生投影若成本高或显示不一致,可用缓存时生成的2–3层低透明度短偏移轮廓近似;降级仍保留实色底沿与有效边界。每次绘制通道用 `save/restore` 隔离裁切、透明度、混合方式和虚线状态。
### 8.3 度量目标
目标是常规设备稳定60fps;低性能档可评估稳定30fps。绘制CPU耗时建议以P95低于8ms为首轮目标,并同时记录整帧耗时、输入到首次可见反馈、缓存字节数与重建次数。这些是待测目标,不能由桌面Canvas或模拟微信测试推导真机达标。
密集盘快速连画、分段提示、教学动画分别记录;纯思考阶段应无持续绘制。降级永远不删除墙门、数字、条件框、类别和提示信息。
## 9. 制作顺序与交付门槛
| 阶段 | 实际工作 | 交付门槛 |
|---|---|---|
| A 技术骨架 | 主题读取、布局统一、渲染接缝、几何与Scene | 原有行为保持,快照不变,教学状态隔离 |
| B 黄金样张 | 用真实关卡生成基础、大块、异形、通道、双色、门及密集盘 | 面、底沿、桥和文字在复杂盘面清楚 |
| C 交互单关 | 落格、连画、逐格回退、撤销、提示、门动画 | 输入即时,提示不改玩家填色 |
| D 全页面 | 选关、对局、规则、完成;按范围新增首页与设置 | 窄屏、胶囊、安全区、按钮布局通过 |
| E 全内容与平台 | 200关自动回归、视觉抽样、真机性能与生命周期 | 新皮肤独立产出验证记录,才进入发布 |
P0:真实轮廓、规则信息、类别保留、桥接、提示遮罩、输入坐标。
P1:完整轻厚度材质、UI字阶、字体、局部动效、缓存调度。
P2:首页原创字形精修、少量通关纸片。首版只做暖黄主题,不为200关逐关做美术资源。
建议先交付“6类真实关卡的可交互样张页”,共用正式 renderer,以配置切换主题、尺寸、减少动态与质量档。该页是开发验收工具,不进入玩家流程。预览和QA截图可以导出用于检查,但不可反向成为运行时游戏资源。
### 9.1 验收矩阵
| 验收项 | 方法与通过条件 |
|---|---|
| 无图片美术依赖 | 审查运行包和加载调用;没有作为游戏美术使用的位图、图片图集或外部SVG |
| 几何与大块 | L/T/S、凹口、空洞样张;一块一次,内部无格线,轮廓无自交;桥不穿墙 |
| 数字与组合 | 10/11/17/20/28/36、奇偶、通道、类别组合;保留区互不覆盖 |
| 提示 | 比较开提示、撤销重画前后的已走面采样;基础填色相同,提示避开数字与通道 |
| 门 | 空盘、落格、穿过、回退、重开;形态与 `doorOpen/doorLatched` 一致 |
| 适配 | 320×568、375×667、390×844、414×896;至少含 r2-163/r2-187 |
| 手势 | 快画、慢画、抬手续画、逐格退回、撤销、重开;屏幕位置与命中一致 |
| 教学和弹窗 | 正式renderer复用,关闭后玩家路径/提示/坐标/存档不变 |
| 动效生命周期 | 后台、返回、旋转/尺寸变化、减少动态;没有积压动画和状态漂移 |
| 内容和构建 | 全关唯一解和原有输入回归通过;快照哈希与适配入口检查通过 |
| 真机表现 | 同时记录视觉、帧耗时、内存估算、音频与触摸;浏览器截图不当作微信实测 |
### 9.2 后续实施时复用的检查命令
以下在仓库根目录执行,命令沿用现有工程;本次文档编写未执行新皮肤测试。
```powershell
node docs/design/bright-classroom/audit-design.mjs
Push-Location wechat-campaign-200-r2
node build.mjs
node --test hints.test.mjs lessons.test.mjs audio-copy.test.mjs
node smoke.mjs
Pop-Location
```
`build.mjs` 当前依赖本仓库原型内的 esbuild 安装;`smoke.mjs` 会读取manifest指定的上游来源路径。实施前检查这些依赖,缺失时修正可复现环境,不能把路径错误当成皮肤问题。原有颜色与采样断言需要主题参数化,同时保持“提示前后不改变玩家填色”的不变量,不能简单删除失败断言。
新增有实际价值的验证集中在多环轮廓、窄凹口退化、真实共边入口、信息区碰撞、教学Scene隔离、坐标正逆变换及提示像素不变量;颜色常量和简单绘制包装无需逐项写镜像测试。
## 10. 依据、结论和执行路径
下表是本方案的 Evidence → Finding → Path,对应本地文件,可从仓库根目录用 `Get-Content -LiteralPath <路径>` 复核;未以未运行的原型或真机截图作为证据。
| 证据 | 已观察事实 | 技术结论 | 执行路径 |
|---|---|---|---|
| E01:[完整美术报告](2026-10-21_美术设计-明亮教具室-report.md)及[令牌](design/bright-classroom/tokens.json) | 暖黄、奶油、轻厚度、明确规则和版本边界 | F01:程序化材质与语义分层,材质服从读盘 | P01:主题→材质→复杂关样张 |
| E02:`wechat-campaign-200-r2/src/upstream/ui.mjs` | 现有Canvas几何、块、桥、墙门和UI回写 | F02:可复用Canvas,但不能只改颜色或删除draw业务 | P02:渲染接缝→Scene→新绘制通道 |
| E03:`wechat-campaign-200-r2/src/upstream/rules.mjs` | 占用格、单环轮廓、共边、门和判定 | F03:显示需补多环与安全偏移,规则仍沿用原结果 | P03:边抵消→闭环→缩进倒角→共边入口 |
| E04:`wechat-campaign-200-r2/src/hints.mjs`、`src/main.mjs` | 透明提示层、中心连线、玩家单位格擦除、延后合成 | F04:升级引导路线、完整遮罩和信息避让 | P04:统一几何→提示切段→像素不变量 |
| E05:`wechat-campaign-200-r2/build.mjs`与README | 上游快照有哈希;构建注入教学与宿主 | F05:皮肤采用可检查的构建适配,教学复用同一renderer | P05:入口断言→构建→教学隔离→整包回归 |
第一项可验收工作应是:用真实大块/异形关和一个密集组合关,在当前微信宿主中跑通“完整轮廓+轻厚度+桥接+数字+提示遮罩”,并保持原有操作。通过后再铺开全页面,最终以200关回归与微信真机记录判定是否可以交付。