Compare commits
2
Commits
6e72b95ad8
..
v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fc83c34f2 | ||
|
|
4ea5949cfb |
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"version": "0.0.1",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "dev",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": [
|
||||
"run",
|
||||
"dev"
|
||||
],
|
||||
"port": 3000
|
||||
}
|
||||
]
|
||||
}
|
||||
-12
@@ -2,15 +2,3 @@
|
||||
node_modules/
|
||||
.DS_Store
|
||||
*.log
|
||||
# Local research downloads and generation checkpoints
|
||||
/tmp/
|
||||
|
||||
# Agent bench: regenerated from scripts, never edited by hand
|
||||
bench/runs/
|
||||
bench/report.json
|
||||
bench/hex-bench/
|
||||
bench/hex-bench.zip
|
||||
bench/pack/
|
||||
|
||||
# Phone bundle: regenerated by scripts/build-phone.mjs
|
||||
/build/
|
||||
|
||||
@@ -32,11 +32,3 @@ No Git history was available when this project was created. Use focused, imperat
|
||||
## Agent-Specific Instructions
|
||||
|
||||
Before calling MCP tools, read `/Users/wukaibing/.grok-go/agents-guide.md` for version-specific GrokGo instructions.
|
||||
|
||||
### Level-production scope
|
||||
|
||||
The user has explicitly limited this work to level creation: board layouts, track connections, pieces, difficulty, and level ordering. Use the game's existing interface and interaction logic. Do not independently add controls, hide controls, change layouts or themes, or introduce teaching-specific interface behavior. Any future interface or interaction change requires an explicit user request. Preserve existing campaign numbering and saved progress when integrating level data.
|
||||
|
||||
### Design-system entry point
|
||||
|
||||
For user-requested design/UI work, start at [design/README.md](design/README.md) and [design/AGENTS.md](design/AGENTS.md), then read [design/shared.md](design/shared.md) and the selected `design/directions/<id>/design.md`. [design/manifest.json](design/manifest.json) lists all five stable IDs, canonical documents, previews, and generated tokens. Each design has five themes; design IDs are separate from theme IDs and campaign versions. Authored design.md files must not be overwritten by generators. This entry point does not expand the scope of level-only tasks.
|
||||
|
||||
+29
-205
File diff suppressed because one or more lines are too long
@@ -1,14 +1,12 @@
|
||||
# HEX TRAILS 设计规范
|
||||
|
||||
版本:2.0 · 2026-09-08 · 适用:网页、手机触摸界面与 Cocos 移植。
|
||||
版本:1.0 · 2026-09-08 · 适用:网页、手机触摸界面与 Cocos 移植。
|
||||
|
||||
本文件保留基础方案与通用组件的设计规范。五套方案的 Agent 入口为 [design/README.md](design/README.md),各套独立规则见 `design/directions/<id>/design.md`;本文的基础哑光造型和配色要求不覆盖其他四套的独立画法。
|
||||
|
||||
`src/design-tokens.js` 是基础语义色来源,`src/art-directions.js` 定义各套独立配色。修改数值后运行 `npm run design`,同步生成 CSS、JSON、面板 PNG、对比度报告、设计包和可视化手册 `Design.html`。HTML 为单文件离线版本,包含原始图片、色值复制、组件示例、弹窗动效与本文全文。新界面应复用所选方案的颜色源,不另写一份重复色库。
|
||||
本文件规定设计角色和使用方式;`src/design-tokens.js` 是颜色数值的唯一来源。修改数值后运行 `npm run design`,同步生成 CSS、JSON、面板 PNG、对比度报告和可视化手册 `Design.html`。HTML 为单文件离线版本,包含原始图片、色值复制、组件示例、弹窗动效与本文全文。新界面不得另写一套 HEX 或用滤镜临时拼配色。
|
||||
|
||||
## 1. 设计方向
|
||||
|
||||
**清爽、明快、易读的哑光解谜游戏。** 环境使用按难度或活动组织的低饱和主题色,棋盘采用暖白,主操作采用紫色。全局建立 12 色棋子库,单关默认使用其中 7 色,支持 4 / 7 / 9 / 12 色对照;高饱和度不平均分配给每一个按钮。
|
||||
**清爽、明快、易读的哑光解谜游戏。** 环境采用冷蓝灰,棋盘采用暖白,主操作采用紫色。鲜艳的蓝、粉、黄、紫主要留给棋子;高饱和度不平均分配给每一个按钮。
|
||||
|
||||
- 棋子是第一视觉焦点,Level 和步数是第二层,工具是第三层。
|
||||
- 纯色背景,无纹理、光晕、装饰圆盘。底板要看得出六边形分格。
|
||||
@@ -22,7 +20,7 @@
|
||||
|
||||
采用 W3C 的对比度方法作为验收约束:普通文字至少 4.5:1,大号文字和必要的非文字视觉标识至少 3:1。颜色之外还要用文字、图标、位移或选中标记表达状态。[文字对比度](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html) · [非文字对比度](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html)
|
||||
|
||||
这些来源提供方法和约束;下面的 HEX、游戏形态、动效时长是本项目的设计选择,并非 Material 官方游戏模板。当前有四套主线主题与一套每周挑战美术主题,不随系统壁纸自动换色。主题只改变美术表现,不改变难度判定。
|
||||
这些来源提供方法和约束;下面的 HEX、游戏形态、动效时长是本项目的设计选择,并非 Material 官方游戏模板。当前为固定浅色主题,不随系统壁纸自动换色。
|
||||
|
||||
## 3. 颜色体系
|
||||
|
||||
@@ -30,11 +28,11 @@
|
||||
|
||||
| Token | 色值 | 用途与配对 |
|
||||
|---|---|---|
|
||||
| `background` | `#A8BECF` | 基础回退色;游戏场景使用下表主题背景与场景文字色 |
|
||||
| `background` | `#A8BECF` | 页面背景,搭配主文字或辅助文字 |
|
||||
| `board` | `#F2EEE5` | 棋盘底格,暖白区分冷色背景 |
|
||||
| `boardGrid` | `#89867D` | 六边形边界,细线且清楚可见 |
|
||||
| `track` | `#435F78` | 深蓝轨道中心线,线宽 `max(2.5px, 格子半径 × 0.10)` |
|
||||
| `trackHalo` | `#F2EEE5` | 轨道浅色外缘,不能盖断接头 |
|
||||
| `boardGrid` | `#7C8B94` | 六边形边界,细线且清楚可见 |
|
||||
| `track` | `#6D808B` | 轨道中心线 |
|
||||
| `trackHalo` | `#DFE3E2` | 轨道浅色外缘,不能盖断接头 |
|
||||
| `surface` | `#F7F6F2` | 弹窗与编辑面板 |
|
||||
| `textPrimary` | `#273B50` | Level、步数、标题、主要标签 |
|
||||
| `textSecondary` | `#314A5F` | 说明与次要标签;用字号和字重区分层级 |
|
||||
@@ -47,7 +45,7 @@
|
||||
|---|---|---|
|
||||
| `primary / onPrimary` | `#6652B8 / #FFFFFF` | 下一关、试玩、主要确认、当前选中关卡 |
|
||||
| `secondary / textPrimary` | `#E4EAF0 / #273B50` | 重玩、普通选关、编辑器次级动作 |
|
||||
| `utility / onUtility` | `#52697E / #FFFFFF` | 选关、设置与编辑器的图标底板 |
|
||||
| `utility / onUtility` | `#52697E / #FFFFFF` | 选关、设置、撤销、重来、提示的图标底板 |
|
||||
| `selection / onSelection` | `#DFD9F3 / #3F327A` | 可扩展的弱选中状态 |
|
||||
| `warningSurface / warning` | `#F9E3D2 / #A44825` | 阻挡、导入失败、不可解提示 |
|
||||
| `reward` | `#B9760C` | 星星轮廓与奖励强调,限制面积 |
|
||||
@@ -56,13 +54,13 @@
|
||||
| `scrim` | `#273B50`,透明度 48% | 模态遮罩,背景模糊 5px |
|
||||
| `focus` | `#3F327A` | 键盘焦点外框 |
|
||||
|
||||
一张弹窗只安排一个高强调主操作。顶部选关、设置使用紧凑蓝灰底板;底部撤销、重来、提示使用更大的独立彩色道具底座。当前游戏不显示次数或广告角标。成功不额外引入薄荷绿,使用主操作色和星星表达。
|
||||
一张弹窗只安排一个高强调主操作。工具按钮统一用蓝灰底板,不再分别使用蓝、粉、黄。提示无需绿色“免费”角标;现有角标沿用中性表面。成功不额外引入薄荷绿,使用主操作色和星星表达。
|
||||
|
||||
编辑器的工具、方向、旋转和文件操作同样使用 `utility / onUtility`,保证生成白色图标在底板上可辨认;选中工具与试玩使用 `primary / onPrimary`。
|
||||
|
||||
### 3.3 棋子色与图片事实
|
||||
|
||||
棋子颜色不代表功能、品质或阵营。原有四枚棋子来自已接受的图片;以下是采样区域中心的代表值,图片像素允许存在小幅变化:
|
||||
棋子颜色不代表功能、品质或阵营。现有四枚棋子来自已接受的图片;以下是采样区域中心的代表值,图片像素允许存在小幅变化:
|
||||
|
||||
| Token | 代表色 | 方向箭头 |
|
||||
|---|---|---|
|
||||
@@ -71,29 +69,9 @@
|
||||
| `tileYellow` | `#FDBC28` | 深蓝灰 `textPrimary` |
|
||||
| `tilePurple` | `#874FFD` | 白色 |
|
||||
|
||||
黄色上的白箭头对比不足,因此使用深色箭头。所有棋子均可通过方向箭头、位置和运动判断,不要求辨认颜色才能通关。未经用户确认,不重新生成或调色替换已接受的棋子。
|
||||
黄色上的白箭头对比不足,因此使用深色箭头。四种棋子均可通过方向箭头、位置和运动判断,不要求辨认颜色才能通关。未经用户确认,不重新生成或调色替换已接受的棋子。
|
||||
|
||||
### 3.4 场景主题与 12 色库
|
||||
|
||||
互动展示:在本地开发服务打开 `/design-showcase.html`,可切换主题、点击真实棋盘、播放离场效果与慢速观察。展示中的五套主题使用同一关,便于比较色彩。
|
||||
|
||||
| 难度 / 场景 | 主题 | 环境色 | 棋子搭配 |
|
||||
|---|---|---|---|
|
||||
| 轻松 0–29 | 薄荷浅湾 | `#C5E4DF` | 晴空蓝、湖水青、日光黄 |
|
||||
| 进阶 30–49 | 杏色午后 | `#F1D7B8` | 珊瑚橙、鸢尾蓝、湖水青、蜜桃杏 |
|
||||
| 烧脑 50–69 | 鸢尾花园 | `#D8D0EB` | 葡萄紫、嫩芽绿、玫瑰红、冰川青 |
|
||||
| 挑战 70–100 | 玫瑰暮色 | `#E7C3CE` | 玫瑰红、鸢尾蓝、日光黄、兰花紫 |
|
||||
| 每周挑战美术预览 | 午夜极光 | `#293956` | 冰川青、兰花紫、日光黄、莓果粉 |
|
||||
|
||||
四套浅色背景使用 `textPrimary` 场景文字;午夜背景使用 `surface` 色文字。弹窗内部继续使用暖白底和深色文字,避免场景文字色污染组件。每周挑战目前提供独立美术主题和预览入口,尚未接入周赛、排行榜或活动日历。
|
||||
|
||||
新增八色:湖水青 `#008B83`、珊瑚橙 `#EF704F`、嫩芽绿 `#91C95B`、鸢尾蓝 `#5267CF`、玫瑰红 `#C83F66`、蜜桃杏 `#F5AA83`、冰川青 `#58C9D5`、兰花紫 `#AE64C7`。前四色保留已接受的图片采样;新增色使用同一圆角六边形轮廓进行纯色绘制,没有改动原始图片。
|
||||
|
||||
`PIGMENTS` 与 `LEVEL_THEMES` 在 `src/design-tokens.js` 中维护,并导出到 `design/tokens.json`。箭头按实际色值选择白色或深蓝灰,最低对比度 3:1。主线默认将主题色组扩展为 7 色,URL 参数 `colors` 支持 4、7、9、12;主题表中的配色作为起始色,优先补足差异较大的色相。主线按初始棋子顺序循环分配主题色组,因此移走棋子、旋转和撤销不会让剩余棋子变色。编辑器开放完整 12 色库,自由创作不强制收敛。
|
||||
|
||||
颜色不代表功能、品质或阵营;难度也必须保留文字,不只靠背景判断。主题切换只发生在换关或主动预览时,不随剩余步数改变。背景保持纯色,用色彩变化建立旅程感。
|
||||
|
||||
### 3.5 禁止的搭配
|
||||
### 3.4 禁止的搭配
|
||||
|
||||
- 白色小字放在黄色、浅蓝灰或浅绿色按钮上。
|
||||
- 使用同样的浅灰同时承担背景、底板和轨道。
|
||||
@@ -105,21 +83,15 @@
|
||||
|
||||
### 游戏主界面
|
||||
|
||||
游戏顶部恢复居中关卡计数,左侧选关、右侧设置;剩余步数位于其下方,不显示主题说明。棋盘视口占据顶部通知与独立旋转区之间的可用空间,棋盘在该区域垂直居中,不再限制为正方形。左右转与底部道具分别占据真实布局行,不覆盖棋盘。底部仅排列撤销、重来、提示。缩放按钮与常驻手势说明不占用棋盘空间;保留双指缩放、放大后拖动及桌面组合键滚轮。左侧选关,右侧设置。没有 Logo、关卡副标题、难度、待离场数量、角度读数或底部导航。
|
||||
顶部仅显示居中的 Level 与其下方的剩余步数。左侧选关,右侧设置。没有 Logo、关卡副标题、难度、待离场数量、角度读数或底部导航。
|
||||
|
||||
旋转操作为放大的生成箭头,下方分别写“左转”“右转”,不加矩形底板。文字用主文字色;白色箭头允许轻微蓝灰轮廓阴影增强边缘识别,不能改写原图轮廓。它们须保留至少 44×44 的触摸区域。
|
||||
|
||||
撤销、重来、提示使用独立彩色底座:原版为蓝、紫、金;高彩为青、荧粉、亮黄;玩具为蓝、红、黄圆角积木键;动物为绿、棕、麦黄徽章;轻线纸境为雾蓝、陶橙、赭金平面底座。五套方案的底部道具均采用纯色平面,不使用投影、内阴影、立体底边或渐变高光;图标和未来次数/广告角标同样不加阴影。第 07 套「马卡龙」的白色圆钮带柔和投影是用户于 2026-09-14 确认的唯一例外,只允许该套使用。普通底座 64px,大屏 68px,短屏 56px;图标 32px、标签 13px。整体点击区至少 80×96px,短屏 80×84px。禁用时确实停止操作,道具透明度为 50%;不得只有颜色变化却仍可点击。
|
||||
|
||||
右上角预留 27px 次数角标或 42px 广告角标,距底座上缘 -5px;广告使用播放符号 + AD,不能只有模糊的加号。两种角标互斥,不遮挡图标与标签。设计稿仅展示“撤销 3 次”和“广告获取提示”的外观,不接入库存、扣次数、广告播放或奖励。实际次数、定价与获取方式待产品确定。
|
||||
|
||||
统一审核页的“道具设计”区域、五套独立设计稿与离线手册均包含普通态和未来角标示例,允许在同一页面切换比较。
|
||||
撤销、重来、提示使用相同的工具底色和图标规格,下方标签不少于 12px。禁用时确实停止操作,网页透明度为 55%;不得只有颜色变化却仍可点击。
|
||||
|
||||
### 棋盘和轨道
|
||||
|
||||
大棋盘测试支持边长 6(轴向半径 5,91 格)与边长 7(半径 6,127 格)。网页棋盘支持以双指中点为锚的 1–4 倍缩放,放大后单指拖动;双指手势及其余指抬起不触发棋子点击。100% 视图保留原有边缘拖动旋转,放大后用左右按钮旋转。桌面提供 Ctrl/Command + 滚轮缩放;收拢双指或缩小回 100% 恢复全盘视图。缩放与绘制、点击共用同一坐标变换,不改变规则坐标。
|
||||
|
||||
先画全部底格,再画分格线,再统一画轨道外缘与中心线,最后画棋子。相邻格子连接端口必须完全重合。内部不留透出背景的缝;外边缘需为线帽预留空间。分格线宽取 `max(1px, 格子半径 × 0.024)`。
|
||||
先画全部底格,再画分格线,再统一画轨道外缘与中心线,最后画棋子。相邻格子连接端口必须完全重合。内部不留透出背景的缝;外边缘需为线帽预留空间。分格线宽取 `max(1.25px, 格子半径 × 0.038)`。
|
||||
|
||||
棋子保持微小圆角。所有游戏运动、碰撞和绘制使用同一坐标体系。图片只能在原图不透明、无杂点的区域采样;不得带入棋盘格底纹或透明噪点。
|
||||
|
||||
@@ -165,13 +137,10 @@
|
||||
|
||||
## 7. 动效、音效与反馈
|
||||
|
||||
- 快速连点:每次点击立即按当前逻辑棋盘判定路线,成功棋子立即释放占位,多枚棋子各自播放运动动画,无须等待上一枚结束;失败试路也不阻挡其他棋子出发。同一枚运动中的棋子不重复触发。转盘运动期间暂存点击并以紫色描边反馈,到位后按点击顺序立即执行;重来、换关、进入编辑器或打开弹窗时取消暂存点击。移动中的动画不参与后续占位碰撞判定。撤销、提示和再次旋转等待所有棋子运动结束,通关结果也在全部离场动画结束后显示。
|
||||
- 按压:150ms,缩放到 94%;不移动命中区域。
|
||||
- 弹窗:420ms,从上方 60px 和 96% 缩放进入;遮罩约 250ms。
|
||||
- 星星:分别延迟 300/490/680ms 出现,每枚动画 400ms。
|
||||
- 离场:总时长随路径长度变化,按实际轨道长度以每单位 60ms 滑行,滑行段限制为 140–800ms,出口收束固定为 180ms。边缘棋子约 320ms 完成离场;从 3 格路线起平滑增加滑行时间,5 格及以上恢复初版总时长(550ms + 每格 85ms,最长 1700ms),新增时间全部用于滑行,出口收束仍为 180ms。不再给短路线添加固定等待。滑行与出口位移使用平滑 S 曲线(smoothstep),起止速度为零,中段流畅加速;缩小同样使用 S 曲线,避免末段突然消失。碎片采用快速展开、缓慢停下的 ease-out 曲线。棋子向外推进约 0.48 个格子半径,缩小后留下短尾迹与 6 枚同色六角碎片;效果结束后再显示结果。不得把消散阶段放在画布外,不引入额外彩虹色。减少动态效果时取消尾迹与碎片,仅保留短路线过渡与成功状态文字。
|
||||
- 旋转:240ms,快速到位,棋子保持固定。
|
||||
- 碰撞:总长 800ms,先接近,再接触停顿并让阻挡棋子轻震,最后原路弹回;不改变模型中的位置。
|
||||
- 碰撞:总长 1250ms,先接近,再接触停顿并让阻挡棋子轻震,最后原路弹回;不改变模型中的位置。
|
||||
- 音效:首次手势后启动,点击、旋转、离场、碰撞和通关各有短音;设置里可关闭并保存偏好。
|
||||
- `prefers-reduced-motion` 下取消非必要位移、缩放和震动,仍保留状态文字。
|
||||
- 手机棋盘禁用 WebKit tap highlight、选中文字和长按菜单,避免整块矩形高亮。
|
||||
@@ -188,39 +157,8 @@
|
||||
2. 修改 `src/design-tokens.js`,运行 `npm run design`。
|
||||
3. 检查自动生成的 PNG/CSS/JSON 和对比度报告。
|
||||
4. 运行 `npm test`、`npm run build`。
|
||||
5. 对五套背景逐一检查场景文字与箭头,并检查离场、旋转和撤销后颜色稳定。检查 390×844 手机布局,以及较矮屏幕;检查主界面、选关、设置、通关/失败和碰撞状态。
|
||||
5. 检查 390×844 手机布局,以及较矮屏幕;检查主界面、选关、设置、通关/失败和碰撞状态。
|
||||
6. 验证弹窗不能穿透操作、图标居中、轨道接缝不断裂。
|
||||
7. 如需替换已接受的图片,明确告知用户素材来源和变化,再更新本表。
|
||||
|
||||
Cocos 读取同一 JSON/JS token 和 PNG。`CandyUiSkin` 使用纯色 Sprite、圆角 Mask 和居中的图标;不得在原生侧另外猜颜色。本规范与适配组件已提供,原生场景尚需导入后做视觉验收。
|
||||
|
||||
## 多设计方案审核
|
||||
|
||||
Agent 接入先读 [design/README.md](design/README.md),共用规则见 [design/shared.md](design/shared.md)。每套独立目录包含人工维护的 design.md、生成配色 tokens.json 和预览 index.html;五套方案不能只用本手册的基础色值描述。
|
||||
|
||||
共有五套并列设计(现有方案 + 三套实验方案 + 玩法实验页衍生方案),每套均包含轻松、进阶、烧脑、挑战、每周挑战五种主题。设计切换同时作用于棋子造型、轨道材质与主题配色;共享同一弯曲关卡与动画逻辑。
|
||||
|
||||
| 编号 | 设计 | 视觉特征 | 独立设计稿 |
|
||||
| --- | --- | --- | --- |
|
||||
| 01 | 柔和原色 | 哑光色块、蓝灰轨道 | [柔和原色](design/directions/calm/index.html) |
|
||||
| 02 | 高彩游乐场 | 高饱和撞色、粗轮廓、贴纸硬阴影 | [高彩游乐场](design/directions/vivid/index.html) |
|
||||
| 03 | 积木轨道屋 | 塑胶高光、分层厚度、圆角积木 | [积木轨道屋](design/directions/toy/index.html) |
|
||||
| 04 | 动物弯弯镇 | 猫、熊、兔、蛙造型与独立箭头 | [动物弯弯镇](design/directions/animals/index.html) |
|
||||
| 05 | 轻线纸境 | 浅色细轨道、微小格缝、细白边六角与线条箭头 | [轻线纸境](design/directions/paper/index.html) |
|
||||
| 06 | 路标 | 奶白卡片棋盘、双层轨道、路标棋子、压痕式旋转按钮 | [路标](design/directions/signpost/index.html) |
|
||||
| 07 | 马卡龙 | 白托盘、带白缝的糖砖格、糖果色棋子与白色粗箭头、果糖色反馈动效,参考 Meowdoku | [马卡龙](design/directions/macaron/index.html) |
|
||||
|
||||
在 [设计总览](design/index.html) 并排比较各套画法、切换统一主题,完整编号与 25 种主题见 [方案目录](design/README.md)。最新是第 07 套「马卡龙」,七套方案均可并列保留。
|
||||
|
||||
在 [统一审核页](design-showcase.html) 切换设计及主题,可同时保留多套、逐套记录意见并导出 JSON。意见保存在当前浏览器。设计稿由 `scripts/build-art-directions.mjs` 生成,颜色及造型规则来自 `src/art-directions.js`、`src/token-art.js`。
|
||||
|
||||
### 轻线纸境 · 实验页画法提取
|
||||
|
||||
来源为 [玩法变种实验页](labs/variants/index.html) 的棋盘绘制,不改动实验页的关卡或玩法。独立设计稿中以「双色试航」的初始布局作对照,保留陶橙/雾蓝棋子、细白边与线条箭头;统一审核页使用与其他方案相同的弯曲轨道测试关,供多选比较。
|
||||
|
||||
- 轻松主题沿用背景 `#EAF0F3`、格面 `#FAFBF7`、分格 `#D3DFE3`、轨道 `#B2C4CE`,核心棋子为陶橙 `#D66C4D` 与雾蓝 `#477FC0`。
|
||||
- 格面半径为格半径的 0.97,棋子为 0.88;格线宽度 0.025、轨道线宽 0.055、棋子白边 0.035、箭头线宽 0.09,均相对于格半径。极小缩略图的轨道最小 0.7px、格线最小 0.4px。
|
||||
- 棋子为正六角纯色面,细白边;箭头由一根直线和开放的箭头头部组成,圆头圆接缝。移动时同样使用此画法,不切回原版粗实心箭头。
|
||||
- 五种主题为雾蓝信纸、暖砂手札、鼠尾草页、石墨练习、夜航图纸;保留 12 色库与每关 4/7/9/12 色对照,所有白色棋子箭头对比度至少 3:1。
|
||||
- 浅色细轨道忠实保留用户认可的参考画面,轨道本身低于原版 3:1 目标;这是一份待视觉审核的设计方案,不宣称通过轨道可访问性对比度标准。页面文字与棋子方向仍分别检查可读性。
|
||||
- 延续当前居中棋盘、大尺寸扁平道具、通知位置与动画时序;线条和六角形可通过现有跨引擎绘制命令实现。原生引擎尚未实机验收。
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
# HEX TRAILS · 转转六角
|
||||
|
||||
一款竖屏六角轨道解谜游戏:观察路线,点击箭头棋子让它离场;免费旋转底盘和尝试路线,在清楚的反馈中逐步清空棋盘。
|
||||
一款竖屏六角轨道解谜游戏:点击箭头棋子,让它沿轨道离场;旋转底盘改变路线,在有限步数内清空棋盘。
|
||||
|
||||
项目使用原生 JavaScript ES modules 和 Canvas,无第三方运行依赖,无在线字体或 CDN。选关窗口提供 v0.1 最初 24 关、v0.2 直线较多的 48 关、v0.3 弯轨 48 关、v0.4「长路与惊喜」20 关,以及 v0.5「千段轨迹」1000 关。新玩家默认 v0.5,已有版本选择继续保留。另有关卡工坊、求解器、确定性关卡生成器,以及 Cocos Creator 适配示例。
|
||||
项目使用原生 JavaScript ES modules 和 Canvas,无第三方运行依赖,无在线字体或 CDN。包含 24 个主线关卡、关卡工坊、求解器、确定性关卡生成器,以及 Cocos Creator 适配示例。
|
||||
|
||||
v0.5 按 20 章 × 50 关组织花瓣、环绕、螺旋、回折、编织、双叶交叉六类真实路线,穿插巡游、清挡、反差、换路和分段释放。沿用主游戏的快速连点与并行离场。每关保存构造配方、正式解、体验解与 20 种顺序回放;制作与验收范围见 [千关制作报告](docs/v0.5-production-report.md)。
|
||||
## 版本
|
||||
|
||||
正式第 1 关前另有 3 关入门序章:单棋子沿弯路离场、两棋子清挡连点、旋转底盘找出口。三课都使用与正式第 1 关相同的完整 19 格六边形棋盘,分别只放 1、2、2 枚棋子。新玩家从序章开始,教学单独存档,原 1–1000 编号与完成记录保持原位;选关窗口可以重玩教学。[开始教学](http://localhost:4173/?campaign=v0.5&tutorial=1),[教学设计与验证](docs/tutorial-prologue.md)。明确的 `?level=1` 链接仍直达正式第 1 关。
|
||||
- [v1](https://zeroplus.fun/games/hextrails/v1.html):首次发布版本,对应 `v1` 分支。
|
||||
- [v2](https://zeroplus.fun/games/hextrails/v2.html):对应 `v2` 分支,支持连续点击不同棋子立即出发,多枚离场动画同时播放;每次点击按最新棋盘判定路线。离场中的棋子不可重复点击,全部动画结束后再显示通关结果。左右旋转免费。
|
||||
|
||||
v0.4 按 4 组 × 5 关安排长路巡游、朝内棋子一次旋转放行、短路清挡和往返换路。设计依据见 [新版关卡设计准则](docs/level-design-principles-v2.md),逐关制作意图与完整操作证据见 [v0.4 体验报告](docs/v0.4-experience-review.md)。长路径本身是观看内容,轻巧反差也可通过短路径兑现;不按难度分对关卡排序。
|
||||
|
||||
后续关卡优化的原始设计参照见 [v0.1 · 最初 24 关设计理念](docs/v0.1-design-philosophy.md):还原必要旋转、空间让路与分阶段解开轨道的结构,并区分历史规则、实际布局和本次设计归纳。
|
||||
两个版本保留同一套 24 关顺序。v2 难度按免费旋转重新计算,因此分数不保证逐关递增。
|
||||
|
||||
## 快速开始
|
||||
|
||||
@@ -25,11 +24,7 @@ npm run dev
|
||||
打开 [游戏](http://localhost:4173/)。请通过 HTTP 访问,直接双击 HTML 文件无法正常加载 ES modules。开发服务监听 `0.0.0.0`,同一局域网的手机可通过电脑 IP 和端口访问。
|
||||
|
||||
- [关卡工坊](http://localhost:4173/?editor=1):当前精简游戏界面隐藏工坊导航,通过此地址进入。
|
||||
- [千关版](http://localhost:4173/?campaign=v0.5&level=1):按章选关或直接输入 1–1000;URL 的关号从 1 开始。
|
||||
- [千关审核页](http://localhost:4173/labs/campaign-review/index.html):按章看布局,检查制作证据,逐步回放和导出本章总览。
|
||||
- [花形轨道测试](http://localhost:4173/labs/flower/index.html):双层十二瓣与三重环带编织成花,包含 10 枚棋子的独立可玩实验,详见 [设计说明](docs/flower-study.md)。
|
||||
- [交互设计规范](http://localhost:4173/Design.html):色板、图标、组件状态与动效示例。
|
||||
- [设计方案总览](http://localhost:4173/design/index.html):01–07 七套设计、35 种主题、完整设计稿与多选审核入口;最新为「马卡龙」(参考 Meowdoku),主游戏用 `?design=macaron` 查看。[方案目录](design/README.md)记录各套特点与共用规则。
|
||||
- 修改端口:`PORT=4174 npm run dev`。
|
||||
|
||||
## 游戏规则
|
||||
@@ -37,24 +32,16 @@ npm run dev
|
||||
- 点击棋子,从箭头方向进入轨道;弯道自动转向,交叉处不换轨。
|
||||
- 点击左右旋转按钮,或沿棋盘边缘拖动,将底盘旋转 60°。棋子的位置与箭头方向保持不动,底板格子与轨道配对一起旋转。
|
||||
- 棋子不能穿过其他棋子。碰撞检测覆盖整段运动路径,包括弯道与邻格擦碰;碰撞动画展示接触后退回原位。
|
||||
- 只有成功移除棋子消耗 1 次预算;旋转和失败试路均免费。主线预算等于初始棋子数,只表示剩余消除工作量,不惩罚试错。撤销恢复棋盘、棋子、朝向和计数;没有倒计时。
|
||||
- 点击棋子消耗 1 步,碰撞也扣步;左右旋转不消耗步数。撤销恢复棋盘、棋子、朝向和步数;没有倒计时。
|
||||
- 提示会高亮可安全离场的棋子,或建议旋转方向。棋子配色不影响规则。
|
||||
|
||||
v0.3 每章按“进入 → 换路 → 展开 → 小挑战 → 释放 → 长局回报”安排,不按难度分数单调排序,也不要求每关必须旋转。早期就可使用 37 格棋盘,后期舒缓关使用 61 格延长熟悉操作的体验;19 格小棋盘也可承担局部挑战。棋盘规模与认知难度分别记录。
|
||||
|
||||
9 月 9 日版的 48 关以真正的弯轨消除为主:每关参考解答至少 65% 的成功离场棋子经过弯道,且不少于 3 枚。直线只作少量节奏调剂,不安排纯直出关,也不用空格上的装饰曲线充数。当前单关最多 25 枚棋子,后期长局增加的是沿弯轨观察与解开的实际内容。
|
||||
|
||||
v0.3 第 1 关为 37 格、8 枚棋子,开局全部可离场,每枚参考路径恰好转弯一次,无需旋转;“全部可离场”不表示任意朝向都相同。前 7 关通过 `lesson` 字段依次学习箭头起步与弯轨转向、旋转换路而棋子箭头不动、交叉不换轨、阻挡先后、舒缓的一两弯、大盘连续解路径,以及完整路线观察。
|
||||
|
||||
v0.3 发布要求包括完整可解、每枚棋子在六个朝向下的独立路线无闭环,以及参考解答中的阻挡可解释、旋转后有明确进展;这些门槛不代表玩家任意旋转或点击序列都不会遇阻。该版制作方向见 [玩法方向](docs/gameplay-direction.md),逐关生成与验收记录见 [主线审阅报告](docs/campaign-review.md),验证结果以实际生成报告和测试输出为准。v0.4 按新版准则单独筛选与回放,不沿用以上全部布局限制。
|
||||
|
||||
所有关卡可自由选择。在左上角选关窗口切换 v0.1 至 v0.5,分别保存通关进度与上次选关;对应旧存档会自动迁移,旧数据继续保留。历史布局原样恢复,五版共用当前免费旋转与失败试路规则,详见 [关卡版本与来源](docs/campaign-versions.md)。以上弯轨比例与节奏门槛针对 v0.3。音效使用 Web Audio 合成,首次交互后启用,可在设置中关闭并保存偏好。
|
||||
主线关卡均经过求解验证,且需要旋转才能完成。所有关卡可自由选择,通关进度保存在当前浏览器。音效使用 Web Audio 合成,首次交互后启用,可在设置中关闭并保存偏好。
|
||||
|
||||
## 关卡工坊
|
||||
|
||||
工坊支持 19、37、61 格底板、棋子方向与配色、15 种轨道配对、单格轨道旋转和整体底盘旋转;还提供擦除、路径检查、撤销编辑、试玩、随机生成、本机单槽存档及 JSON 导入导出。
|
||||
工坊支持 19 格和 37 格底板、棋子方向与配色、15 种轨道配对、单格轨道旋转和整体底盘旋转;还提供擦除、路径检查、撤销编辑、试玩、随机生成、本机单槽存档及 JSON 导入导出。
|
||||
|
||||
试玩不修改草稿,也不计入主线进度。工坊与正式游戏共用碰撞及求解规则。分析器区分最少消除成本 `minimumMoves=N` 与最少交互数 `minimumActions=N+R`,其中 `R` 是最少旋转数;自定义预算不足 `N` 时仍会报告预算不足。认知难度与工作量分别提供,搜索达到上限时显示“尚未确定”,不直接判定无解。
|
||||
试玩不修改草稿,也不计入主线进度。工坊与正式游戏共用碰撞及求解规则,显示可解性、必要旋转数、最短步数与结构难度评分。搜索达到上限时显示“尚未确定”,不直接判定无解。
|
||||
|
||||
不具备六重旋转对称性的导入底板会禁用整体旋转。导入失败保留当前草稿;不可解关卡仍可保存用于调试。浏览器存档不会跨设备同步,需长期保存或分享时请导出 JSON。
|
||||
|
||||
@@ -67,11 +54,7 @@ v0.3 发布要求包括完整可解、每枚棋子在六个朝向下的独立路
|
||||
| `npm run dev` | 启动本地开发服务,默认端口 4173 |
|
||||
| `npm test` | 执行 Node 内置测试套件 |
|
||||
| `npm run build` | 生成设计资源并输出静态站点到 `dist/` |
|
||||
| `npm run levels` | 读取 v0.3 种子清单重新生成 48 关,同步关卡 JSON、共享模块和实际路径验收报告 |
|
||||
| `npm run levels:v04` | 读取 v0.4 制作卡重新生成 20 关,验证两套完整回放并同步体验报告 |
|
||||
| `npm run levels:v05` | 离线生成并筛选完整 1000 关,冻结配方、布局、分章数据及回放证据 |
|
||||
| `npm run levels:v05:verify` | 校验冻结数据及生成源码指纹,重新求解 1000 关并回放每关 22 套解 |
|
||||
| `npm run levels:versions` | 校验历史关卡归档并生成 v0.1 / v0.2 / v0.3 的归档模块 |
|
||||
| `npm run levels` | 使用固定种子重新生成关卡,同步两个关卡数据文件 |
|
||||
| `npm run design` | 生成颜色 token、CSS、JSON、PNG、对比度报告和设计指南 HTML |
|
||||
| `node scripts/serve.mjs --dist` | 本地预览构建产物 |
|
||||
|
||||
@@ -79,10 +62,6 @@ v0.3 发布要求包括完整可解、每枚棋子在六个朝向下的独立路
|
||||
|
||||
修改语义颜色时编辑 `src/design-tokens.js`,然后运行 `npm run design` 并检查生成资源的差异。修改关卡生成逻辑后运行 `npm run levels` 和 `npm test`,确保关卡数据同步且全部可解。
|
||||
|
||||
v0.3 布局来源为 `levels/campaign-seeds.json`,包含逐关种子和生成参数;v0.4 来源为 `levels/v0.4-seeds.json`,包含种子、生成参数、设计意图和完整体验动作。不要直接编辑派生关卡。`levels/campaign-analysis.json` 与 `levels/v0.4-analysis.json` 记录实际成功路径;后者还区分最少旋转参考解与突出关键反差的体验解。报告是结构与回放证据,不包含真人体验数据。
|
||||
|
||||
v0.5 的编排在 `src/production-plan.js`,选中配方在 `levels/v0.5-recipes.json`;静态构建只验证冻结千关,不在每次构建时重新抽取布局。完整生产使用确定性种子,每个槽位在同一种形态和体验内比较候选。调试小批次可运行 `node scripts/build-production-levels.mjs --count=50`,仅写入临时目录;仅完整 1000 关可通过 `--publish` 写入本地正式数据。此标志不会部署网站。
|
||||
|
||||
## 项目结构
|
||||
|
||||
| 路径 | 职责 |
|
||||
@@ -96,15 +75,7 @@ v0.5 的编排在 `src/production-plan.js`,选中配方在 `levels/v0.5-recipe
|
||||
| `src/collision-animation.js` | 碰撞反馈动画 |
|
||||
| `src/sprites.js`、`src/ui-skin.js` | 棋子与 UI 图集裁切、共享皮肤定义 |
|
||||
| `src/design-tokens.js`、`design/` | 语义颜色源与生成的设计资源 |
|
||||
| `levels/campaign-seeds.json` | 48 关种子与生成参数的制作来源 |
|
||||
| `levels/campaign.json`、`src/levels.js` | 根据种子清单生成的主线 JSON 与浏览器模块 |
|
||||
| `levels/campaign-analysis.json` | 逐关回放、真实成功路径 `pathUsage` 与结构指标 |
|
||||
| `levels/v0.4-seeds.json`、`src/experience-generator.js` | v0.4 逐关制作卡与支持不同朝向逆向放置的生成器 |
|
||||
| `levels/v0.4.json`、`src/levels-v04.js`、`levels/v0.4-analysis.json` | v0.4 布局、浏览器模块与双方案回放证据 |
|
||||
| `src/route-grammar.js`、`src/stage-seed.js`、`src/production-generator.js` | 六类开放路线、两次换路锁组与有构造解的布子 |
|
||||
| `src/campaign-evidence.js` | 正式求解、策略回放、对称去重、结构难度与体验兑现证据 |
|
||||
| `levels/v0.5.json`、`levels/v0.5/`、`src/levels-v05.js` | 千关全集、20 章独立 JSON 与浏览器模块 |
|
||||
| `levels/v0.5-analysis.json`、`levels/v0.5-recipes.json` | 千关逐关证据与可复现配方 |
|
||||
| `levels/campaign.json`、`src/levels.js` | 主线关卡 JSON 与浏览器模块 |
|
||||
| `assets/` | PNG 图集、历史素材与生成提示词 |
|
||||
| `tests/`、`scripts/` | 自动测试、开发服务和生成脚本 |
|
||||
| `cocos/` | Cocos Creator 棋盘及 UI 适配示例 |
|
||||
@@ -119,34 +90,18 @@ v0.5 的编排在 `src/production-plan.js`,选中配方在 `levels/v0.5-recipe
|
||||
|
||||
[Design.md](Design.md) 记录设计规范;[Design.html](Design.html) 内嵌图片与样式,可单文件离线分享。生成过程与提示词见 [素材说明](assets/GENERATION.md)。
|
||||
|
||||
五套独立设计的 Agent 入口是 [design/README.md](design/README.md),共用接入规则见 [design/shared.md](design/shared.md)。每套在 `design/directions/<id>/` 下提供人工维护的 `design.md`、生成的 `tokens.json` 和预览 `index.html`;[manifest.json](design/manifest.json) 提供可编程读取的目录。使用方案时复用共享 JS/CSS,基础 Design.md 不包含各套的全部独立规则。
|
||||
|
||||
Cocos 示例复用规则、碰撞、渲染命令和图集;HTML 控件、文件导入导出与存储需替换成宿主接口。接入步骤见 [Cocos 移植指南](docs/cocos-port.md)。`wechat/HexTrail/` 是本仓库管理的 Cocos Creator 3.8.8 工程,后续将把当前游戏移植到该工程中。使用 Creator 打开该目录;工程自身的 `.gitignore` 排除缓存、本地配置和构建产物,源码与项目配置随主仓库提交。
|
||||
|
||||
## 验证与已知限制
|
||||
|
||||
自动测试覆盖主线完整解答、生成关卡、旋转与撤销、弯轨寻路、连续碰撞、闭环、导入校验,以及设计颜色对比度和图标裁切。测试结果以当前 `npm test` 输出为准。
|
||||
|
||||
界面变更还需在浏览器检查竖屏布局、旋转、碰撞回位、弹窗和工坊导入导出;自动测试不替代实机交互验收。较小屏幕可能需要纵向滚动。认知难度评分不直接加入棋盘规模,仍是未经玩家数据标定的结构估计。工作量中的估计秒数也只是内部制作假设,不能当作真人平均通关时长。
|
||||
界面变更还需在浏览器检查竖屏布局、旋转、碰撞回位、弹窗和工坊导入导出;自动测试不替代实机交互验收。较小屏幕可能需要纵向滚动。难度评分是结构估计,尚未通过玩家数据标定。
|
||||
|
||||
`cocos/` 是适配示例,不是完整 Creator 工程;原生场景及 Android/iOS 构建尚未完成验收。`docs/ui-layout.json` 是旧版布局快照,不应直接作为当前场景模板。
|
||||
|
||||
更多背景见 [视频与规则分析](docs/video-analysis.md)。
|
||||
|
||||
## V2 色彩与离场展示
|
||||
## 版本发布
|
||||
|
||||
打开 `http://localhost:4173/design-showcase.html`,切换五套关卡主题并播放离场动效。主线按难度使用四套背景,12 色棋子库在每关收敛为 3–4 色;编辑器开放全部 12 色。每周挑战目前为独立美术主题预览,尚未实现周赛功能。规范与色库详见 `Design.md`。
|
||||
|
||||
## 视频 UI 实验室
|
||||
|
||||
[Hex Video Lab](labs/hex-video/index.html) 是基于 `examples/hex.mp4` 的独立 UI / 特效复刻,可切换地图、棋盘和领奖场景,支持自动试玩、单片翻转、彩纸、金币飞入、慢速播放及参考帧对照。棋子按本项目要求保留单片薄侧边,不使用视频中的多片堆叠。运行 `npm run dev` 后访问 `/labs/hex-video/index.html`;详见 [复刻笔记](labs/hex-video/README.md)。
|
||||
|
||||
## 环路车场 Lab
|
||||
|
||||
[打开环路车场实验](http://localhost:4173/labs/car-loop/index.html):对照六角与方格道路,点击方块小车发车,经固定引道汇入顺时针环路,驶向右上方终点。提供多弯路网、旋转、路线提示、三组样本和自动演示。独立实验不影响主线;详见 [Lab 说明](labs/car-loop/README.md)。
|
||||
|
||||
转盘发车玩法于 2026-09-10 暂缓研发,保留可运行版本;详见 [研发记录与阶段结论](docs/car-loop-research.md)。
|
||||
|
||||
## 玩法变种 Lab
|
||||
|
||||
[打开独立实验室](http://localhost:4173/labs/variants/index.html):分色归站、机关换轨、接力停靠,各 5 个可解关卡,支持旋转、撤销、提示和重来。仅使用实验室数据,不写入主线存档。规则和验证范围见 [Lab 说明](labs/variants/README.md)。
|
||||
构建后运行 `node scripts/package-release.mjs v2 <唯一资源版本号> <临时输出目录>`,生成 `v2.html` 和独立资源目录。将两者部署到服务器网站根目录的 `games/hextrails/`;入口需使用游戏专用的样式 CSP 和禁缓存策略。先上传资源,最后原子替换 HTML,保留旧资源供回滚。v1 分支固定在首次上线的 `9f8990b`,旧地址 `/games/hextrails.html` 跳转到 v1。v2 使用独立的浏览器进度存储。
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# 资源圆体子集(Resource Han Rounded)
|
||||
|
||||
来源:[CyanoHao/Resource-Han-Rounded](https://github.com/CyanoHao/Resource-Han-Rounded) v0.990,CN 版 Medium 与 Bold,SIL Open Font License 1.1。用户于 2026-09-14 指定,用于第 07 套「马卡龙」的界面文字。
|
||||
|
||||
`ResourceHanRoundedCN-Medium.subset.woff2` / `ResourceHanRoundedCN-Bold.subset.woff2` 是按 `macaron-charset.txt` 裁剪的子集(游戏界面、弹窗与 v0.1–v0.5 关卡数据中出现的 1001 个字符,含 ASCII 与常用标点),每个约 170 KB。子集里没有的字符由浏览器按字形回落到 PingFang 等系统字体。
|
||||
|
||||
重新生成(fonttools + brotli):
|
||||
|
||||
```sh
|
||||
pyftsubset ResourceHanRoundedCN-Medium.ttf --text-file=macaron-charset.txt --flavor=woff2 --layout-features='*' --no-hinting --desubroutinize --output-file=ResourceHanRoundedCN-Medium.subset.woff2
|
||||
```
|
||||
|
||||
新增大量界面文字或关卡文案后,把新字符加入 `macaron-charset.txt` 再重新裁剪。原生端可直接使用完整 TTF。
|
||||
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~°±·×÷–—‘’“”…←↑→↓↖↗↘↙○●★☆✓ 、。《》「」『』一七三上下不与世丢两个中丰临为主义之乎乐也习了二于互五些交享亮人仁仅仍从他以们件价任份优会估伴似位低住体余作你使例供依侧保信倒偶储像允充先光克免兔入全六兰共关其具典内再冒冰冲决冷准减几凸出击分切则刚创初判别到制刷刺刻剂前剩力功加动助励包化匹区十千午华单占卡印即压厚原去参又叉及双反发取受变叠口另只可台右叶号各合同名后向否启告周命和咪品响哑哪喜嘉器回因园困围图圆圈土在地场均坊坐块型垫城域基塑境增墨声处备复外多夜大天太央失头奏奖套奶好始姜嫩子字存学它安完定实审家容宽密富察寸对寻导封将小少尚尝就尽尾局层屋展岸峰川巡工左巧差已布带常平年并广庆序库应底度座廊廓延建开式引张弯弹强归当录形彩影往径待得循微心必快态思性总恢悉情惊意感慢懂戏成我或战房所手打托扣扩扫找承把投折报抹担拉拖拥择拼拿持挂指按挑挡挤捉换据排探接控推描提插搜搭撒撞撤播操擦支收改放效教散数整文断新方旅旋无日旧时明星映是显晨普景晰晴暂暖暮曲更替最有朝木未末本札术朱朵机杂李杏束条来松板极构林枚果架柑染柔柜柠查标栗校样核格桃案桌档检棋棕森楚榛槛模橘橙橡檬次欢正此步段每比毛毯气氛水求沙没油沿法波注洁洋派浅测浏浪浮海消润深清渐温渲游湖湾源溪滑滚满漂演激火灯灰灵点烈烟烧热然照熊熟爆片版牛物特状独猜猫玩玫环现玻珀珊理琥瑚瑰璃瓣甜生用由电画畅界留白百的盈益盐盒盘盛目直相看真眼着睛短石砂砖破础硬确碎碰磨示祝离秋种秒秩积称移程空穿突窗立章端笔符第等签简算箭粉粗糖系索紧紫红约纯纷纸线练组细织终经结绕绘给统继续绿编缘缝缤缩置美翼考而耳肩背胶能脑脸腾自至致舍舒舞航船色节芋花芽苔范茶草荧荷莓获萄萤落葡蓝薄藏藕藤蛙蜂蜜螺行衍衔衡补表被装要见观规视览觉角解触言警计认让议记许设证评识试话该详语说请读课谁调负败质贯贴费资赖赠赤赭走起超足跟跨路跳轨转轮软轻载较辅辑输辨边达过运近返还这进远连述迷迹退送选逐途通速造逢遇遍道避邻部都配释里重野量金针钢钮钴铁铅铺销锁错键镇长门闭间闸阔队阴阶阻际降限除险陪陶随隔隙难集雪零雾需露青静靛靠面音韵页顶项顺预领题颜额风飞餐饰饱馈首香马验高鲜鸢麦黄黑默鼠齐龙!(),/:;?
|
||||
@@ -1,280 +0,0 @@
|
||||
{
|
||||
"goal": "调出 50 关难度合适、好玩的关卡,交付人工审核",
|
||||
"updated": "09-14 16:45",
|
||||
"round": 3,
|
||||
"definition": {
|
||||
"title": "「难度合适且好玩」的操作定义",
|
||||
"why": "旋转是免费的、是这个游戏的特色,玩家应该频繁做——所以不该限制旋转次数。该限制的是每一次旋转值不值:转了有没有棋子出来、能不能看出来该转哪、以及转完之后有没有「原来这么简单」的反差。评分里只有 difficulty(复测 r=0.93)和 stuck(r=0.85)可信,rotation / clarity / fun 是噪声(0.32 / 0.19 / 0.56),所以「好玩」全部换成机械代理。 另外,演出本身就是奖励——棋子沿弯路走出去的那几秒是减压点,所以开局必须有得看,而不是只有两枚贴边棋子和 0.3 秒。",
|
||||
"rules": [
|
||||
{
|
||||
"k": "旋转要深",
|
||||
"v": "难度来自「需要转很多次」,不是「转错受罚」。旋转数随关号上升,不设上限",
|
||||
"how": "求解器最少旋转数"
|
||||
},
|
||||
{
|
||||
"k": "每转都有回报",
|
||||
"v": "每一次旋转至少放出 2 枚棋子;无效转动 = 0",
|
||||
"how": "deepLevelStats.releasePerTurn / 规则机器人"
|
||||
},
|
||||
{
|
||||
"k": "演出是回报",
|
||||
"v": "开局就要有得看:可点 ≥3 枚、其中最好的一条离场演出 ≥0.9s;全关长巡游(≥0.9s)≥3 次",
|
||||
"how": "showStats,用真实动画计时"
|
||||
},
|
||||
{
|
||||
"k": "反差感",
|
||||
"v": "平均反差 ≥12:棋子在某个朝向看着像噩梦(长路线多弯),转过去就是几步走出(代价 = 格数 + 2×弯数)",
|
||||
"how": "六朝向逐棋子代价差"
|
||||
},
|
||||
{
|
||||
"k": "不无脑",
|
||||
"v": "猴子 动作÷棋子 ≥3.0(v0.5 全库 1.67 = 乱点就能过)",
|
||||
"how": "生成时算"
|
||||
},
|
||||
{
|
||||
"k": "不挫败",
|
||||
"v": "stuck ≤2.0;终局任一朝向卡住时,左右转都能开",
|
||||
"how": "grok 抽样 + 求解器"
|
||||
},
|
||||
{
|
||||
"k": "不重复",
|
||||
"v": "盘面签名互不相同,路线家族分布不偏科",
|
||||
"how": "deepLevelKey"
|
||||
}
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"levels": 50,
|
||||
"rotationDepth": [
|
||||
{
|
||||
"band": "L1–L12",
|
||||
"rot": "2–3 转",
|
||||
"difficulty": "1.5 – 2.0"
|
||||
},
|
||||
{
|
||||
"band": "L13–L32",
|
||||
"rot": "3–5 转",
|
||||
"difficulty": "2.0 – 2.6"
|
||||
},
|
||||
{
|
||||
"band": "L33–L50",
|
||||
"rot": "5–8 转",
|
||||
"difficulty": "2.6 – 3.0"
|
||||
}
|
||||
],
|
||||
"gates": {
|
||||
"releasePerTurn": "≥2",
|
||||
"blindRotations": 0,
|
||||
"contrast": "≥12",
|
||||
"monkeyAPT": "≥3.0"
|
||||
}
|
||||
},
|
||||
"phases": [
|
||||
{
|
||||
"id": "P0",
|
||||
"title": "判据:先说清楚什么叫「好」",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "T0.1",
|
||||
"title": "难度曲线与旋转配额定义",
|
||||
"status": "done",
|
||||
"note": "50 关分三档,0 转关卡死 10% 上限(用户硬要求)"
|
||||
},
|
||||
{
|
||||
"id": "T0.2",
|
||||
"title": "机械验收门槛",
|
||||
"status": "done",
|
||||
"note": "盲转=0、转错=0、终局可走朝向≥2 —— 前两项已由改锁结构达成"
|
||||
},
|
||||
{
|
||||
"id": "T0.3",
|
||||
"title": "「好玩」的机械代理指标",
|
||||
"status": "done",
|
||||
"note": "猴子 APT ≥3.0。fun 评分复测 r=0.56 不可用,改用「乱点过不了」当代理"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "P1",
|
||||
"title": "产能:解除旋转上限,把反差感做进筛选",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "T1.1",
|
||||
"title": "growDeepLevel 扩展到 6 个朝向",
|
||||
"status": "done",
|
||||
"note": "现在只在朝向 0/1/2 插棋子,所以最少旋转恒等于 3 —— 这是「太简单」的根因"
|
||||
},
|
||||
{
|
||||
"id": "T1.2",
|
||||
"title": "解除 rotations===3 的硬限制,允许 4/5/6+",
|
||||
"status": "done"
|
||||
},
|
||||
{
|
||||
"id": "T1.3",
|
||||
"title": "反差感指标进 deepLevelStats 并作门槛",
|
||||
"status": "done",
|
||||
"note": "contrastStats 已进 deepLevelStats 并作门槛;实测 weave 22–33、switchback 29、spiral 18–24、orbits 12–17,petals 仅 2.0–5.7、crossing 3.8–5.5"
|
||||
},
|
||||
{
|
||||
"id": "T1.4",
|
||||
"title": "每转释放 ≥2 枚的门槛",
|
||||
"status": "done",
|
||||
"note": "改为按朝向配额插棋(每个朝向 ≥2 枚在等),取代原来的随机比例——随机比例会留下空转的朝向"
|
||||
},
|
||||
{
|
||||
"id": "T1.5",
|
||||
"title": "扩产到 ≥120 候选并去重、家族均衡",
|
||||
"status": "done",
|
||||
"note": "两批共 720 个种子 → 1113 个候选 → 过闸门 369 关(原 228)。家族 weave 262 / switchback 58 / orbits 39 / spiral 10"
|
||||
},
|
||||
{
|
||||
"id": "T1.6",
|
||||
"title": "终局三枚互锁(hero+gate+tail)",
|
||||
"status": "blocked",
|
||||
"note": "量化了:扫 1113 个候选,过闸门后深度≥4 的只有 23 个(2%)。第二次扩池把种子数翻倍,深关卡只从 16 涨到 23 —— 难度上限是构造的供给瓶颈,不是筛选问题。后档平均 4.0 转就是这个供给能支撑的上限"
|
||||
},
|
||||
{
|
||||
"id": "T1.7",
|
||||
"title": "开局展示位(快速爽到)",
|
||||
"status": "done",
|
||||
"note": "实测整个构造的开局中位只有 2 枚可点、最佳演出 0.57s——锁链开局全锁死。在构造里预留 2 个开局位(立即可点且路线长到值得看),实测开局可点 2→3 枚、最佳演出 0.72s→1.12s"
|
||||
},
|
||||
{
|
||||
"id": "T1.8",
|
||||
"title": "离场演出封顶",
|
||||
"status": "done",
|
||||
"note": "计时原本线性无上限,最长一次 17.4s,正式关 18.8% 超过 2s。拐点 2.4s 以下完全不变,以上加速逼近 3.2s 上限。labs/exit-timing 可同步对比"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "P2",
|
||||
"title": "标定:把机械指标映射到真实难度",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "T2.1",
|
||||
"title": "grok 抽样跑候选池,收集 difficulty / stuck",
|
||||
"status": "done",
|
||||
"note": "R1:grok-4.6 xhigh 全量跑 50 关,收齐 difficulty / stuck / 机械指标与自由文本抱怨"
|
||||
},
|
||||
{
|
||||
"id": "T2.2",
|
||||
"title": "拟合 difficulty ~ 机械特征",
|
||||
"status": "blocked",
|
||||
"note": "做不成,且不是样本量问题:27 关里 26 关 difficulty 都打 2 分,响应几乎无方差,回归的是常数。根因在 bench 本身——文字盘面把每颗棋子的路线、挡路者、紧贴者直接列成清单,agent 不必用眼睛顺线走,而那正是这游戏的难点。agent 原话:「挡路名单已经写全,不用顺着格子数」。为解释它另建的 legibility 指标与评分相关 -0.02,同样无效,已记录为负结果不采用"
|
||||
},
|
||||
{
|
||||
"id": "T2.3",
|
||||
"title": "用模型给全部候选打分并按曲线选 50 关",
|
||||
"status": "done",
|
||||
"note": "select-50 按机械特征打分并均匀铺开,家族上限 36%。权重是设计假设而非拟合结果(见 T2.2),由人工审核裁定"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "P3",
|
||||
"title": "迭代:跑几轮把曲线调平",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "T3.1",
|
||||
"title": "第 1 轮:grok 全量跑 50 关",
|
||||
"status": "done",
|
||||
"note": "50 关全部跑完;机械面干净:空点 0、盲转 ~0.3/关、全部通关。总体读数:整批偏易一档(2 分 vs 刚好的 3 分)"
|
||||
},
|
||||
{
|
||||
"id": "T3.2",
|
||||
"title": "按实测曲线调整选关,重选",
|
||||
"status": "done",
|
||||
"note": "连续空转设闸门(≤1)+ 难度曲线改为按旋转深度配额。同一规则机器人对照:盲转 0.24→0.12,最长连续盲转 4→1,决策数不变"
|
||||
},
|
||||
{
|
||||
"id": "T3.3",
|
||||
"title": "第 2 轮验证",
|
||||
"status": "done",
|
||||
"note": "R2:99 局覆盖 50 关,全部通关,空点 0。难度按档 2.00 / 2.05 / 2.40,无解感 1.21 / 1.15 / 1.74 —— 评分第一次出现梯度"
|
||||
},
|
||||
{
|
||||
"id": "T3.4",
|
||||
"title": "收敛判定(难度曲线单调、stuck 达标)",
|
||||
"status": "done",
|
||||
"note": "收敛判定完成。机械面全部达标:空点 0、不可解态 0、连续空转≤1、终局朝向≥3、三轮全部通关。难度面 2.00/2.05/2.39 单调,后档仍低于「刚刚好」的 3 分,上限由深关卡供给决定(T1.6)。第三轮试图用反差再推一把,被数据否掉并回退"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "P4",
|
||||
"title": "交付",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "T4.1",
|
||||
"title": "50 关关卡集",
|
||||
"status": "done",
|
||||
"note": "交付的是第二版(R2 跑的那一版),从其 run 反建,50 关旋转深度 {1:5,2:5,3:24,4:12,5:4},家族 weave18/switchback12/v05 10/orbits8/spiral2。198 项测试全绿,规则机器人复核 50/50 通关、空点 0、最长连续盲转 1"
|
||||
},
|
||||
{
|
||||
"id": "T4.2",
|
||||
"title": "人工审核页(可直接试玩每一关)",
|
||||
"status": "done",
|
||||
"note": "docs/review-50.html:50 张开局盘面缩略图 + 机械指标 + agent 实测 + 试玩直达;并标注「哪些数字能信」,把感知类问题(路线长度、紧贴)显式交给人眼"
|
||||
},
|
||||
{
|
||||
"id": "T4.3",
|
||||
"title": "后续关卡制作流程的优化总结",
|
||||
"status": "done",
|
||||
"note": "docs/level-process.html:两轮对照、复测可信度表(本批现算)、五条规则各带证据、被否掉的做法清单"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"rounds": [],
|
||||
"log": [
|
||||
{
|
||||
"at": "起点",
|
||||
"text": "已完成前置工作:擦碰漏报修复(113/581 例)、终局单出口门槛、锁结构改为双向可开 —— 规则机器人盲转/转错/多转已全部归零"
|
||||
},
|
||||
{
|
||||
"at": "方向修正",
|
||||
"text": "旋转配额的思路被推翻:旋转免费且是核心特色,不该限次数,该限的是每次旋转的回报与可读性。实测发现 17 关最少旋转全部恒为 3(生成器写死),且 petals/crossing 两个家族几乎没有反差感(平均 2.0–5.7 对比 weave 的 22–33)"
|
||||
},
|
||||
{
|
||||
"at": "P1 进展",
|
||||
"text": "旋转深度打开:生成分布从「全部恒为3」变成 {3,4,5,6,7,8,9}。两次结构性猜测失败并已撤回(插入端多朝向出口过滤实测零效果)。深关卡的瓶颈定位为终局三枚互锁,改用扩大扫描量应对"
|
||||
},
|
||||
{
|
||||
"at": "演出",
|
||||
"text": "离场动画封顶定稿(拐点 2.4s / 上限 3.2s),最长 17.4s→3.5s;拐点以下手感不变。同时发现开局演出是结构性缺陷并在构造里修掉"
|
||||
},
|
||||
{
|
||||
"at": "R1 结论",
|
||||
"text": "难度评分在这批关卡上无区分度(26/27 都是 2 分),原因是文字 bench 把判断白送给了 agent。结论:agent 轮次用于抓缺陷(死局、盲转、空点、演出),难度排序只能靠机械假设 + 人工审核。这条改变了后续流程的设计"
|
||||
},
|
||||
{
|
||||
"at": "未擅自改动",
|
||||
"text": "agent 33 条抱怨里两大主题是路线太长(68 格 27 弯)与紧贴易看漏。但已上线的 v0.5 在这两项上更严重(最长 88 格 vs 84 格),属于游戏本来的性格;且文字盘面会同时夸大和缩小感知问题。因此只在审核页标出,不擅自设闸门"
|
||||
},
|
||||
{
|
||||
"at": "R2 依据",
|
||||
"text": "后段 14 条抱怨里两类:路线太长(感知,已对照 v0.5 基线否掉)与「转了没反应」(机械,可设闸门)。只改后者:endgameMinOpen 2→3、doubleDead 无闸门→≤2。两条合计只留 16% 候选,所以先扩池"
|
||||
},
|
||||
{
|
||||
"at": "R2 结果",
|
||||
"text": "难度评分按档 2.00/2.05/2.40(R1 是三档全平),无解感 1.21/1.15/1.74。意外把每关跑了两次,得到 45 对复测:84% 重放了完全相同的动作序列,机械指标 r=1.00,难度评分 r=0.55——且评分分歧的那几对全是同轨迹。结论:agent 近乎确定性,同一关不必跑两遍"
|
||||
},
|
||||
{
|
||||
"at": "供给瓶颈",
|
||||
"text": "扩池两轮共 720 种子、1113 候选,深度≥4 的过闸门后只有 23 个(2%)。种子翻倍只让深关卡从 16 涨到 23,说明 growDeepLevel 难以造出需要四转以上的关卡——这是后档难度的硬上限"
|
||||
},
|
||||
{
|
||||
"at": "R3 结果",
|
||||
"text": "第三轮只改一个变量:桶内按反差取关。后档反差 27.9→28.5、旋转深度不变,后档评分 2.39→2.17。以 r=0.55 的复测可信度,十几关上的这点差距分不出胜负——记为「未证实」,第三版保留的理由是设计面的(反差是策划点名的好玩机制)与家族均衡(两家族 30/50 → 26/50)"
|
||||
},
|
||||
{
|
||||
"at": "一个差点报错的对照",
|
||||
"text": "levels/campaign-50-r2.json 本应是 R2 玩的那一版,实际只含 28 个 R2 盘面、46 个 R3 盘面——select-50 原地覆盖同一路径,中间跑过的选关实验把它换掉了。改为从 run 反建(run 自带完整盘面与序号),并删掉该快照"
|
||||
},
|
||||
{
|
||||
"at": "第三轮回退",
|
||||
"text": "按反差选关后,后档评分 2.39±0.10 → 2.19±0.08(约两个标准误),平均分≥2.5 的关从 11 掉到 6。反差确实和「被评得更难」相关,但按它选关造不出更难的关——相关不等于可操纵。已回退到第二版"
|
||||
}
|
||||
]
|
||||
}
|
||||
-981788
File diff suppressed because it is too large
Load Diff
-66965
File diff suppressed because it is too large
Load Diff
-22989
File diff suppressed because it is too large
Load Diff
-343515
File diff suppressed because it is too large
Load Diff
-150442
File diff suppressed because it is too large
Load Diff
-625025
File diff suppressed because it is too large
Load Diff
-582541
File diff suppressed because it is too large
Load Diff
@@ -1,85 +0,0 @@
|
||||
# v0.5 千关 · 规则机器人扫描
|
||||
|
||||
日期:2026-09-14 · 工具:scripts/bench-batch.mjs(BENCH_PROVIDER=mock)· 12 秒 · 1000/1000 清盘 · 0 空点
|
||||
|
||||
规则机器人只做协议里的四条规则:路上没人、不紧贴谁就点;一枚都走不了就右转。它不读求解器,也不会左转——所以它的「盲转」就是「一个只会朝一个方向转的玩家会撞到的空朝向」。
|
||||
|
||||
## 总体
|
||||
|
||||
| 指标 | 值 |
|
||||
|---|---:|
|
||||
| 清盘 | 1000 / 1000 |
|
||||
| 零旋转清盘 | 568 |
|
||||
| 用了比最少多的旋转的关 | 75(7.5%) |
|
||||
| 其中要绕整整一圈(连续 4 次空转)| **21** |
|
||||
| 转错方向 ≥1 的关 | 75(全部只错 1 次:错一次就得绕一圈或绕回)|
|
||||
| 动作 ÷ 棋子 中位 | 1.00(照规则玩没有任何浪费)|
|
||||
|
||||
## 转错方向的 75 关按体验类型
|
||||
|
||||
| 体验 | 关数 |
|
||||
|---|---:|
|
||||
| 分段释放 | 75 |
|
||||
|
||||
绕整整一圈的 21 关按体验类型:{"分段释放":21}
|
||||
|
||||
## 要绕一圈的 21 关(右转是错的,而且要连错 4 次才回到对的朝向)
|
||||
|
||||
| 关号 | 体验 | 格 | 枚 | 旋转 用/最少 | 步 |
|
||||
|---:|---|---:|---:|---:|---:|
|
||||
| 72 | 分段释放 | 37 | 8 | 6/2 | 14 |
|
||||
| 78 | 分段释放 | 37 | 11 | 6/2 | 17 |
|
||||
| 94 | 分段释放 | 37 | 9 | 6/2 | 15 |
|
||||
| 99 | 分段释放 | 37 | 8 | 6/2 | 14 |
|
||||
| 110 | 分段释放 | 37 | 11 | 6/2 | 17 |
|
||||
| 184 | 分段释放 | 37 | 11 | 6/2 | 17 |
|
||||
| 214 | 分段释放 | 61 | 10 | 6/2 | 16 |
|
||||
| 254 | 分段释放 | 61 | 11 | 6/2 | 17 |
|
||||
| 300 | 分段释放 | 91 | 14 | 6/2 | 20 |
|
||||
| 322 | 分段释放 | 37 | 11 | 6/2 | 17 |
|
||||
| 409 | 分段释放 | 37 | 10 | 6/2 | 16 |
|
||||
| 494 | 分段释放 | 91 | 12 | 6/2 | 18 |
|
||||
| 509 | 分段释放 | 61 | 13 | 6/2 | 19 |
|
||||
| 522 | 分段释放 | 91 | 13 | 6/2 | 19 |
|
||||
| 693 | 分段释放 | 91 | 15 | 6/2 | 21 |
|
||||
| 757 | 分段释放 | 91 | 16 | 6/2 | 22 |
|
||||
| 784 | 分段释放 | 37 | 11 | 6/2 | 17 |
|
||||
| 850 | 分段释放 | 91 | 14 | 6/2 | 20 |
|
||||
| 853 | 分段释放 | 37 | 11 | 6/2 | 17 |
|
||||
| 860 | 分段释放 | 91 | 16 | 6/2 | 22 |
|
||||
| 900 | 分段释放 | 91 | 14 | 6/2 | 20 |
|
||||
|
||||
这些关的结构都是 createStageSeed 的 A/B/C 两转锁:第一转 +1 放出 B,第二转必须 **转回 0** 放 A。一个转过去之后继续朝同一方向转的玩家,会连续看到 4 个空朝向——这正是 D5 原型第 02 关被判「无解」的那种体验,在 v0.5 里有 21 关。
|
||||
|
||||
## 逐章
|
||||
|
||||
| 章 | 需旋转关 | 转错方向≥1 | 绕一圈 | 平均多转 |
|
||||
|---:|---:|---:|---:|---:|
|
||||
| 1 | 40% | 2 | 0 | 0.10 |
|
||||
| 2 | 44% | 5 | 4 | 0.34 |
|
||||
| 3 | 40% | 4 | 1 | 0.18 |
|
||||
| 4 | 42% | 2 | 1 | 0.10 |
|
||||
| 5 | 46% | 3 | 1 | 0.12 |
|
||||
| 6 | 40% | 2 | 2 | 0.16 |
|
||||
| 7 | 44% | 3 | 1 | 0.12 |
|
||||
| 8 | 42% | 4 | 0 | 0.14 |
|
||||
| 9 | 46% | 5 | 1 | 0.18 |
|
||||
| 10 | 46% | 5 | 1 | 0.20 |
|
||||
| 11 | 48% | 6 | 2 | 0.30 |
|
||||
| 12 | 42% | 6 | 0 | 0.16 |
|
||||
| 13 | 40% | 3 | 0 | 0.10 |
|
||||
| 14 | 46% | 5 | 1 | 0.24 |
|
||||
| 15 | 42% | 3 | 0 | 0.08 |
|
||||
| 16 | 42% | 3 | 2 | 0.18 |
|
||||
| 17 | 42% | 4 | 1 | 0.16 |
|
||||
| 18 | 40% | 5 | 3 | 0.32 |
|
||||
| 19 | 46% | 3 | 0 | 0.10 |
|
||||
| 20 | 46% | 2 | 0 | 0.04 |
|
||||
|
||||
20 章之间没有坡度:转错方向的关每章 2–6 个,绕一圈的关每章 0–2 个;最早的两关在第 2 章(L72、L78),第 1 章已有 2 关转错方向。全部 75 关都是「分段释放」这一种体验——问题集中在 createStageSeed 的 +1 再 −1 结构上。
|
||||
|
||||
## 怎么用
|
||||
|
||||
- 这 21 关是「体感无解」的高风险名单,优先人工看或让 Claude Code 跑( 人设 turner)。
|
||||
- 75 关转错方向的关,如果 §07 的闲置方向提示上线,就不再是问题;没上线之前,它们是流失点。
|
||||
- 规则机器人 0 空点、1.00 动作/棋子,说明**照规则玩 v0.5 没有任何需要判断的地方**——与「猴子玩家 100% 通关」互为印证:难度旋钮和选择旋钮都是零。
|
||||
@@ -31,7 +31,7 @@ class CocosPainter {
|
||||
return new Color((rgb >> 16) & 255, (rgb >> 8) & 255, rgb & 255, alpha);
|
||||
}
|
||||
sprite(index: number, x: number, y: number, radius: number) {
|
||||
if (!this.frames[index]) return false;
|
||||
if (!this.frames.length) return false;
|
||||
if (!this.pool[this.cursor]) {
|
||||
const node = new Node('Tile'); node.layer = this.root.layer; node.parent = this.root;
|
||||
node.addComponent(UITransform);const mask=node.addComponent(Mask);mask.type=Mask.Type.GRAPHICS_STENCIL;
|
||||
@@ -94,7 +94,7 @@ export class HexTrailsBoard extends Component {
|
||||
this.painter = new CocosPainter(this.node,graphics,arrowGraphics,ui.width,ui.height,this.tileAtlas);
|
||||
this.node.on(Node.EventType.TOUCH_END,this.onTouch,this);
|
||||
this.node.on(Node.EventType.SIZE_CHANGED,this.redraw,this);
|
||||
this.loadLevel(this.levelAsset?.json ?? LEVELS[Math.max(0,Math.min(LEVELS.length-1,this.levelIndex))]);
|
||||
this.loadLevel(this.levelAsset?.json ?? LEVELS[Math.max(0,Math.min(23,this.levelIndex))]);
|
||||
}
|
||||
onDestroy() {
|
||||
this.node.off(Node.EventType.TOUCH_END,this.onTouch,this);
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>HEX TRAILS · 五套设计审核</title><link rel="stylesheet" href="design/showcase.css"><link rel="stylesheet" href="design/notifications.css"><link rel="stylesheet" href="design/art-directions.css"><link rel="stylesheet" href="design/game-tools.css"></head>
|
||||
<body>
|
||||
<header class="masthead"><a href="index.html">HEX TRAILS<span>转转六角</span></a><span>DESIGN REVIEW / 07</span><a class="game-link" id="game-link" href="index.html">进入游戏 ↗</a></header>
|
||||
<nav class="quick-review" aria-label="快速切换设计与主题"><label>设计 <select id="quick-design"></select></label><label>主题 <select id="quick-theme"></select></label><a href="#direction-picker">多选与审核 ↑</a><a href="#item-study">道具设计 ↓</a></nav>
|
||||
<main>
|
||||
<section class="direction-review" aria-label="设计方案审核">
|
||||
<div class="review-heading"><div><span class="eyebrow">ART DIRECTIONS / 7 × 5</span><h1>七种性格,同一段旅程。</h1><p>每套设计都有轻松、进阶、烧脑、挑战和每周挑战五种主题。切换查看,也可以同时保留多套。</p></div><a href="design/index.html">查看 01–07 设计总览 ↗</a></div>
|
||||
<div id="direction-picker" class="direction-picker"></div>
|
||||
<div class="review-summary-bar"><p id="review-summary" aria-live="polite"></p><button id="export-review">导出审核记录 ↓</button></div>
|
||||
<div id="direction-detail" class="direction-detail"></div>
|
||||
</section>
|
||||
<section class="intro"><div><div class="eyebrow">COLORFUL WORLDS. FOCUSED PLAY.</div><h1>同一套设计,<br>五种关卡氛围。</h1><p>12 种棋子色彩,5 套关卡氛围。<br>同一棋盘,对照 4、7、9、12 色。</p></div><div class="intro-note"><span>01 / COLOR SYSTEM</span><p>选择下方主题,比较同一棋盘的不同配色。</p><div class="theme-tabs" id="theme-tabs" aria-label="关卡主题"></div></div></section>
|
||||
<section class="density-section"><div class="section-heading"><div><div class="eyebrow">COLOR DENSITY STUDY</div><h2>七色,会不会更好玩?</h2></div><p>点击任一棋盘,在下方体验对应色数;布局保持一致。</p></div><div class="density-grid" id="density-grid"></div></section>
|
||||
<div class="board-size-control"><label>棋盘规模 <select id="board-size"><option value="regular">弯曲小盘 · 12 枚棋子</option><option value="5" selected>边长 6 · 91 格 · 24 枚棋子</option><option value="6">边长 7 · 127 格 · 32 枚棋子</option></select></label><span>双指缩放 · 放大后拖动 · 电脑可用 Ctrl/Command + 滚轮</span></div>
|
||||
<section class="studio" aria-label="主题和动效互动展示">
|
||||
<div class="theme-story"><div class="eyebrow" id="scene-label"></div><h2 id="scene-name"></h2><p id="scene-description"></p><div class="color-spec"><span>环境色</span><b id="background-value"></b><i id="background-chip"></i></div><div class="palette-title">本关棋子 <span id="palette-count"></span></div><div class="local-palette" id="local-palette"></div><p class="small-note">颜色只表达个性,不改变路线或碰撞规则。<br>难度同时保留文字标识。</p><a id="play-theme" href="index.html">用这套主题玩一关 ↗</a></div>
|
||||
<div class="phone" id="phone"><div class="phone-top"><button class="icon-button" id="reset" aria-label="选择关卡" data-icon="grid"></button><div><strong>LEVEL 01</strong><span id="phone-label"></span></div><button class="icon-button" id="next-theme" aria-label="设置" data-icon="gear"></button></div><div class="moves"><span>剩余步数</span><strong id="moves">11</strong></div><div class="notice-slot"><div class="game-notice visible" id="phone-status" role="status" aria-live="polite" aria-atomic="true">点击棋子,沿轨道出发</div></div><canvas id="preview" aria-label="可点击棋子的真实规则演示棋盘"></canvas><div class="rotations"><button id="left"><span data-icon="left"></span><b>左转</b></button><button id="right"><span data-icon="right"></span><b>右转</b></button></div><div class="phone-tools"><button id="undo" class="game-tool" data-tool="undo"><span class="item-face" data-icon="undo"></span><b>撤销</b></button><button id="restart" class="game-tool" data-tool="restart"><span class="item-face" data-icon="restart"></span><b>重来</b></button><button id="hint" class="game-tool" data-tool="hint"><span class="item-face" data-icon="bulb"></span><b>提示</b></button></div></div>
|
||||
<div class="motion-story"><div class="eyebrow">02 / EXIT CHOREOGRAPHY</div><h2>离开,也有回响。</h2><p>沿轨道出发,冲出边缘。<br>短尾迹跟随,同色六角碎片轻轻散开。</p><ol><li><b>01</b><div><strong>沿轨道滑行</strong><span>保留完整路线,读得懂运动。</span></div></li><li><b>02</b><div><strong>出口收束</strong><span>在棋盘边缘缩小,留下短尾迹。</span></div></li><li><b>03</b><div><strong>六角余韵</strong><span>6 枚同色碎片,向外展开后消失。</span></div></li></ol><button class="demo-button" id="demo">播放离场效果 <span>↗</span></button><label class="slow"><input type="checkbox" id="slow"> 慢速观察 ×0.4</label><p class="motion-status" id="motion-status" aria-live="polite">可反复播放,也可直接操作棋盘。</p><p class="small-note">系统开启减少动态效果时,关闭尾迹和碎片。</p></div>
|
||||
</section>
|
||||
<section class="item-study" id="item-study"><div class="section-heading"><div><span class="eyebrow">GAME ITEMS / 功能与道具</span><h2>让道具一眼可辨。</h2></div><p>随上方设计切换 · 角标仅为未来状态示意</p></div><div class="item-study-content" id="item-study-content"></div></section>
|
||||
<section class="theme-collection"><div class="section-heading"><div><div class="eyebrow">03 / ONE JOURNEY, FIVE MOODS</div><h2>五种关卡主题。</h2></div><p>主线按难度自动匹配 · 每周挑战拥有独立主题</p></div><div class="theme-grid" id="theme-grid"></div><p class="collection-note">每周挑战为美术主题预览;所有设计共用弯曲轨道测试关。</p></section>
|
||||
<section class="pigment-section"><div class="section-heading"><div><div class="eyebrow">04 / THE PIGMENT LIBRARY</div><h2>更多颜色,更有分寸。</h2></div><p>全局 12 色 · 单关开放 4 / 7 / 9 / 12 色 · 离场效果沿用棋子本色</p></div><div class="pigment-grid" id="pigment-grid"></div><div class="rules"><p><b>风格成套</b>棋子、轨道、控件与奖励使用同一套设计语言。</p><p><b>单关有取舍</b>以七色为默认起点,更多颜色也保持统一形状与箭头。</p><p><b>交互有秩序</b>造型可以变化,箭头与路径始终清晰。</p></div></section>
|
||||
</main><footer>HEX TRAILS / DESIGN STUDY 02<span>实时 Canvas · 与游戏共用渲染与碰撞规则</span><a href="Design.html">查看设计规范 ↗</a></footer>
|
||||
<dialog class="study-dialog" id="study-dialog"><div id="study-dialog-content"></div><button id="study-close">关闭</button></dialog>
|
||||
<script type="module" src="src/showcase.js"></script></body></html>
|
||||
@@ -1,11 +0,0 @@
|
||||
# 使用与维护设计方案
|
||||
|
||||
这是主游戏五套并列设计的入口。先读 [README.md](README.md),再读 [shared.md](shared.md) 和本次指定方案的 `directions/<id>/design.md`。可通过 [manifest.json](manifest.json) 发现全部 ID、规范、配色和预览路径;不必依赖先前会话。
|
||||
|
||||
- 设计 ID 固定为 `calm`、`vivid`、`toy`、`animals`、`paper`、`signpost`、`macaron`;方案编号为 01–07。每套都有相同的五个主题 ID。不得把设计、主题、关卡版本混成同一个参数。
|
||||
- 使用方案时复用 `src/art-directions.js` 的 `artDirection` / `directionTheme` 和 `src/renderer.js` 的 `drawScene`。样式接入、颜色映射和跨引擎限制见 shared.md。
|
||||
- 修改指定方案时,先核对该方案的 design.md。遵循用户已确认的共用规则:通知在步数下方、居中棋盘、大尺寸扁平道具、金色发光星星。`paper` 不画外围色标或棋子编号。道具带投影只是 `macaron` 一套获准的例外(2026-09-14),不向其他方案放开。
|
||||
- `README.md`、`shared.md`、本文件及各套 `design.md` 是人工维护的文档源。`manifest.json`、各套 `tokens.json`、预览 HTML 由脚本生成;修改源 JS/CSS 和设计规则后重新构建,不手改生成结果。
|
||||
- 每套仍是可单独使用、可同时保留的设计方向。除非任务明确选择默认方案,不因新增方案而替换 `calm` 默认值或其他审核选择。
|
||||
- UI 任务以用户本次授权为边界。仅使用设计不需要改关卡、玩法、碰撞数学、存档或原生工程。不要为文档整理顺便改这些模块。
|
||||
- 按 shared.md 的验证流程检查受影响内容。没有原生实机证据时,不报告 Cocos 已完成视觉接入或验收。
|
||||
@@ -1,82 +0,0 @@
|
||||
# HEX TRAILS · 设计系统入口
|
||||
|
||||
这是给设计审核者和 Agent 共用的主游戏设计入口。当前有 7 套并列方案,每套 5 个主题,共 35 种组合。默认方案是 01「柔和原色」,最新候选是 07「马卡龙」;可同时保留多套。
|
||||
|
||||
人看 [设计总览](index.html) 与 [可操作审核页](../design-showcase.html)。Agent 从本文、[共用接入约定](shared.md) 和本次指定方案的 design.md 开始;可直接读 [manifest.json](manifest.json) 发现全部文件。根目录 [AGENTS.md](../AGENTS.md) 与本目录 [AGENTS.md](AGENTS.md) 提供路由和维护要求。
|
||||
|
||||
## 按任务找到入口
|
||||
|
||||
| 你要做什么 | 先读 | 然后做什么 |
|
||||
| --- | --- | --- |
|
||||
| 使用指定设计实现页面 | shared.md → 该套 design.md → tokens.json | 复用 directionTheme 和 drawScene,并接入对应 CSS |
|
||||
| 调整某套造型或配色 | 该套 design.md → 文档列出的 JS/CSS 源 | 修改对应分支,同步文档,再生成配色与预览 |
|
||||
| 比较与选择设计 | index.html | 同主题比较,再到审核页多选、记录意见 |
|
||||
| 用其他引擎实现 | shared.md 跨引擎范围 → 该套 design.md | 复用绘制命令和几何,按浏览器参考验收 |
|
||||
| 自动发现方案与颜色 | manifest.json → designs[].tokens | 路径从仓库根解析,schemaVersion 当前为 1 |
|
||||
|
||||
## 五套独立规范
|
||||
|
||||
| 编号 | ID | 方案 | Agent 规范 | 数据 | 预览 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 01 | calm | 柔和原色:哑光原版 | [design.md](directions/calm/design.md) | [tokens.json](directions/calm/tokens.json) | [查看](directions/calm/index.html) |
|
||||
| 02 | vivid | 高彩游乐场:高饱和贴纸 | [design.md](directions/vivid/design.md) | [tokens.json](directions/vivid/tokens.json) | [查看](directions/vivid/index.html) |
|
||||
| 03 | toy | 积木轨道屋:塑胶积木 | [design.md](directions/toy/design.md) | [tokens.json](directions/toy/tokens.json) | [查看](directions/toy/index.html) |
|
||||
| 04 | animals | 动物弯弯镇:动物角色 | [design.md](directions/animals/design.md) | [tokens.json](directions/animals/tokens.json) | [查看](directions/animals/index.html) |
|
||||
| 05 | paper | 轻线纸境:细线纸面 | [design.md](directions/paper/design.md) | [tokens.json](directions/paper/tokens.json) | [查看](directions/paper/index.html) |
|
||||
| 06 | signpost | 路标:线路图棋盘与压痕控件 | [design.md](directions/signpost/design.md) | [tokens.json](directions/signpost/tokens.json) | [查看](directions/signpost/index.html) |
|
||||
| 07 | macaron | 马卡龙:白托盘糖砖棋盘,参考 Meowdoku | [design.md](directions/macaron/design.md) | [tokens.json](directions/macaron/tokens.json) | [查看](directions/macaron/index.html) |
|
||||
|
||||
设计 ID、主题 ID 和关卡版本各自独立。每套都支持 `lagoon`(轻松)、`apricot`(进阶)、`lavender`(烧脑)、`rose`(挑战)、`midnight`(每周挑战);显示名可以不同,ID 不变。各主题名称、色值与有序色板从 tokens.json 读取。
|
||||
|
||||
## 文件架构与来源
|
||||
|
||||
```text
|
||||
design/
|
||||
├── AGENTS.md # Agent 工作入口,人工维护
|
||||
├── README.md # 本索引,人工维护
|
||||
├── shared.md # 共用规则、接入、验证与限制,人工维护
|
||||
├── manifest.json # 全部方案与文件路径,生成
|
||||
├── index.html # 人看的总览,生成
|
||||
├── examples/
|
||||
│ └── render-design.mjs # 可执行的无 DOM 接入示例
|
||||
├── directions/
|
||||
│ ├── calm/ # 其余 vivid / toy / animals / paper 结构相同
|
||||
│ │ ├── design.md # 本套设计规范,人工维护,构建不覆盖
|
||||
│ │ ├── tokens.json # 12 色库、5 主题与 4/7/9/12 色板,生成
|
||||
│ │ └── index.html # 人看的完整设计稿,生成
|
||||
│ ├── calm.html # 兼容旧 URL,跳转到 calm/index.html
|
||||
│ └── calm.md # 兼容旧文档入口,指向 calm/design.md
|
||||
├── art-directions.css # 五套控件的样式源
|
||||
├── game-tools.css # 共用扁平道具与布局源
|
||||
└── tokens.json # 基础语义色导出,不是五套方案全集
|
||||
```
|
||||
|
||||
设计颜色定义仍在 [src/art-directions.js](../src/art-directions.js) / [src/design-tokens.js](../src/design-tokens.js),几何仍在 [src/renderer.js](../src/renderer.js) / [src/token-art.js](../src/token-art.js)。没有将运行时代码复制到每套目录。各 design.md 解释意图、精确画法、控件差异、不可丢失的特征和验收点;tokens.json 给 Agent 提供当前数值快照。
|
||||
|
||||
所有生成 JSON 中 `pathBase` 为 `repository-root`;文件路径从仓库根目录解析。它与 Markdown 内按当前文档位置解析的相对链接不同。manifest 的版本号描述数据格式,不代表第几套设计。新增字段可保持同一版本;改变字段含义或移除字段时升级版本并更新消费者。
|
||||
|
||||
## 快速验证一次接入
|
||||
|
||||
在仓库根目录执行,Node.js 20+,无需安装依赖:
|
||||
|
||||
```sh
|
||||
node design/examples/render-design.mjs paper lagoon 7
|
||||
```
|
||||
|
||||
它调用共享主题与渲染器,输出设计 ID、主题 ID、色数、棋盘格数、色板和绘制命令数。可更换为 `animals midnight 12`。未知 ID 或不支持的色数会报错,避免 Agent 拼错 ID 后默默使用默认设计。此例验证无 DOM 几何接入,不代替 PNG、CSS 或实机视觉验收。浏览器 Canvas 示例在 shared.md 中。
|
||||
|
||||
## 修改、生成与校验
|
||||
|
||||
```sh
|
||||
npm run design
|
||||
node --test tests/design-packages.test.js tests/art-directions.test.js tests/themes.test.js
|
||||
node scripts/build.mjs
|
||||
```
|
||||
|
||||
- 规范源:本目录 AGENTS.md、README.md、shared.md、各套 design.md,直接编辑且不会被生成脚本覆盖。
|
||||
- 实现源:JS/CSS、已接受的图集;在本次指定的方案范围内修改。
|
||||
- 生成物:manifest、各套 tokens.json、index.html 及旧入口;不要只改生成物,下一次构建会重建。
|
||||
- 新增方案:在 ART_DIRECTIONS 注册稳定 ID,新增 `directions/<id>/design.md`,更新本索引与相关验证,再运行构建。缺少规范时构建会失败。
|
||||
- 校验覆盖文件可发现性、链接、配色导出与运行时一致性,以及可执行示例。视觉与原生范围按 shared.md 验收。
|
||||
|
||||
旧的 `design/directions/<id>.html` 和 `<id>.md` 入口继续可用;新的代码和文档请引用独立目录。根目录 Design.md / Design.html 保留基础组件与历史设计说明,不作为五套独立方案的唯一规范。实验室中的其他玩法原型各有自己的文档,不在这五套主游戏设计的 manifest 中。
|
||||
@@ -1,37 +0,0 @@
|
||||
.direction-review{padding:52px 0 24px}.review-heading{display:flex;align-items:end;justify-content:space-between;gap:30px}.review-heading h1{font-size:clamp(30px,4vw,48px);letter-spacing:-1.5px;margin:14px 0}.review-heading p{max-width:730px;color:#56687A}.review-heading>a{font-size:12px;white-space:nowrap;padding-bottom:22px}
|
||||
.direction-picker{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:16px;margin:28px 0 18px}.direction-card{border:1px solid #273b5020;border-radius:18px;overflow:hidden;background:white}.direction-switch{display:block;background:none;padding:0;width:100%;text-align:left;color:#273B50}.direction-switch canvas{display:block;width:100%;height:auto}.direction-switch[aria-pressed=true]{box-shadow:inset 0 -3px #6652B8}.direction-card:has([aria-pressed=true]){outline:2px solid #6652B8;outline-offset:3px}.direction-card-title{display:flex;gap:8px;align-items:center;justify-content:space-between;padding:14px 12px;font-weight:650;font-size:13px}.direction-card-title small{font-weight:400;font-size:10px;color:#56687A}.keep-design{display:flex;align-items:center;gap:8px;border-top:1px solid #273b5010;padding:12px;font-size:12px;cursor:pointer}.keep-design input{width:17px;height:17px;accent-color:#6652B8}.review-summary-bar{display:flex;align-items:center;justify-content:space-between;gap:20px;font-size:12px}.review-summary-bar p{font-size:12px}.review-summary-bar button,.sheet-link{background:#273B50;color:white;border-radius:10px;padding:12px 16px;font-size:12px;display:inline-block}.direction-detail{margin-top:24px;border-top:1px solid #273b5020;border-bottom:1px solid #273b5020;padding:30px 0;display:grid;grid-template-columns:1.25fr 1fr;gap:60px}.direction-detail h2{font-size:28px;margin:10px 0}.direction-detail p,.direction-detail li{font-size:13px;line-height:1.9}.direction-detail ul{padding-left:18px;color:#56687A;margin-bottom:22px}.review-note{font-size:13px;display:flex;flex-direction:column;gap:12px;padding-top:4px}.review-note textarea{resize:vertical;width:100%;min-height:110px;border:1px solid #273b5030;border-radius:12px;padding:14px;background:white;font:inherit;color:#273B50}.review-note small{font-size:11px;color:#56687A}.intro{padding-top:30px}.intro h1{font-size:34px}.direction-review~.intro .intro-note{max-width:520px}
|
||||
body[data-design=vivid] .phone{border:3px solid #30264C;box-shadow:8px 8px #30264C;border-radius:18px}body[data-design=vivid] .icon-button{background:#4A24E8;border:2px solid #30264C;border-radius:8px;box-shadow:3px 3px #30264C}body[data-design=vivid] .phone-top strong{font-weight:900;letter-spacing:-.6px}body[data-design=vivid] .game-notice{border:2px solid #30264C;border-radius:8px;box-shadow:3px 3px #30264C}
|
||||
body[data-design=toy] .phone{border:8px solid #F9EDCF;border-radius:42px;box-shadow:0 12px 0 #B5A68D,0 20px 30px #273b501f,inset 0 3px 3px #FFFFFF90}body[data-design=toy] .icon-button{background:#4279B7;border-radius:15px;box-shadow:0 4px #244F80,inset 0 2px #82ACD2}body[data-design=toy] .game-notice{background:#FFF9EB;border:2px solid #D8CBB0;box-shadow:0 3px #C4B598}
|
||||
body[data-design=animals] .phone{border:3px solid #718763;border-radius:40px 40px 28px 28px;box-shadow:0 6px 0 #71876330}body[data-design=animals] .icon-button{background:#54795C;border-radius:16px 16px 12px 12px;box-shadow:0 3px #36523C}body[data-design=animals] .game-notice{background:#FFFCED;border:1px solid #71876380;border-radius:18px}.phone canvas{min-width:0}
|
||||
/* Dedicated design sheets use the same tokens and real board renderer. */
|
||||
.sheet-page{background:var(--paper);color:#273B50}.sheet-main{max-width:1320px;padding:40px;margin:auto}.sheet-nav{display:flex;justify-content:space-between;font-size:12px;border-bottom:1px solid #273b5020;padding-bottom:20px}.sheet-hero{display:grid;grid-template-columns:1fr 1fr;gap:60px;padding:44px 0 36px}.sheet-hero h1{font-size:52px;line-height:1.1}.sheet-hero p{font-size:15px}.sheet-token-row{width:100%;height:auto;background:var(--paper);align-self:center}.sheet-themes{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:14px}.sheet-theme{border-radius:18px;background:var(--bg);color:var(--ink);padding:18px 8px;text-align:center}.sheet-theme h3{font-size:15px;margin:9px 0}.sheet-theme small{font-size:11px}.sheet-theme canvas{width:100%;height:auto;display:block}.sheet-swatches{display:flex;justify-content:center;gap:6px;margin:12px 0}.sheet-swatches i{width:18px;height:18px;border-radius:50%}.sheet-components{display:grid;grid-template-columns:1fr 1fr;gap:40px;margin-top:40px}.sheet-panel{border-top:1px solid #273b5020;padding-top:24px}.sheet-panel h2{font-size:22px}.sheet-panel ul{font-size:14px;line-height:2;padding-left:18px}.component-preview{background:var(--bg);padding:28px;border-radius:24px}.sample-controls{display:flex;justify-content:center;gap:12px}.sample-controls button{padding:12px 18px;color:white;background:var(--accent);border-radius:12px;font-size:13px}.sample-modal{background:#FFFCF5;border-radius:24px;padding:24px;margin-top:24px;text-align:center;color:#273B50}.sample-modal .stars{font-size:38px;color:#F7BB32;text-shadow:0 2px #C68525,0 0 16px #F8D776}.sheet-page[data-design=vivid] .sample-modal,.sheet-page[data-design=vivid] .sample-controls button{border:2px solid #30264C;border-radius:10px;box-shadow:4px 4px #30264C}.sheet-page[data-design=toy] .sample-modal,.sheet-page[data-design=toy] .sample-controls button{box-shadow:0 5px #B8A88D,inset 0 3px #FFFFFF55;border-radius:24px}.sheet-page[data-design=animals] .sample-modal{border:2px solid #718763;border-radius:30px}.sheet-page[data-design=animals] .sample-controls button{border-radius:18px;box-shadow:0 3px #36523C}.sheet-caption{font-size:12px;line-height:1.8;color:#56687A;margin:20px 0}
|
||||
@media(max-width:900px){.direction-picker{grid-template-columns:repeat(2,minmax(0,1fr))}.direction-detail{gap:24px}.sheet-themes{grid-template-columns:repeat(2,minmax(0,1fr))}.sheet-hero{gap:20px}.sheet-hero h1{font-size:38px}}
|
||||
@media(max-width:650px){.review-heading{display:block}.review-heading>a{display:inline-block;padding:0}.direction-review{padding-top:30px}.direction-card-title{display:block;font-size:12px}.direction-card-title small{display:block;margin-top:5px}.direction-detail,.sheet-hero,.sheet-components{grid-template-columns:1fr;gap:22px}.review-summary-bar{align-items:start}.review-summary-bar button{flex-shrink:0;padding:10px;font-size:11px}.sheet-main{padding:22px}.sheet-themes{gap:12px}.sheet-theme{padding:12px 5px}}
|
||||
body[data-design=vivid]:not(.editing) .game-shell .game-icon{filter:drop-shadow(3px 3px 0 #30264C)}
|
||||
body[data-design=toy]:not(.editing) .game-shell .game-icon{filter:drop-shadow(0 4px 0 #B5A68D)}
|
||||
body[data-design=animals]:not(.editing) .game-shell .game-icon{filter:sepia(.25) hue-rotate(320deg)}
|
||||
.quick-review{position:sticky;top:0;z-index:10;display:flex;align-items:center;justify-content:center;gap:22px;padding:10px 22px;background:#F7F6F2F5;border-bottom:1px solid #273b501c;backdrop-filter:blur(12px);font-size:12px}.quick-review label{display:flex;align-items:center;gap:9px}.quick-review select{font:inherit;color:#273B50;background:white;border:1px solid #273b5033;border-radius:8px;min-height:36px;padding:5px 10px}.quick-review a{font-size:11px}.direction-picker,.phone{scroll-margin-top:80px}
|
||||
@media(max-width:500px){.quick-review{gap:10px;padding:8px 10px}.quick-review label{gap:5px}.quick-review select{max-width:130px;font-size:11px}.quick-review a{font-size:10px}.review-heading h1{font-size:28px}}
|
||||
|
||||
/* 07 Macaron: white phone chrome and cards on the cream world; controls keep the game-tools rules. */
|
||||
body[data-design=macaron] .phone{border:1px solid #EAD9DE;border-radius:34px;box-shadow:0 20px 40px rgba(110,70,82,.12)}
|
||||
body[data-design=macaron] .phone-top strong{color:#5A3A44}
|
||||
body[data-design=macaron] .moves{color:#5A3A44}
|
||||
body[data-design=macaron] .rotations button{color:#7A5560}
|
||||
.sheet-page[data-design=macaron] .sample-modal{border-radius:28px;box-shadow:0 10px 30px rgba(110,70,82,.12);color:#5A3A44}
|
||||
.sheet-page[data-design=macaron] .sample-controls button{border-radius:999px;box-shadow:0 4px 0 #C96A0E}
|
||||
/* Paper Routes carries the light, flat drawing language of the variants lab. */
|
||||
body[data-design=paper] .phone{border:1px solid #CBD7DD;border-radius:28px;box-shadow:none}
|
||||
body[data-design=paper] .icon-button{background:#607B90;border:1px solid #FFFFFFB8;border-radius:12px;box-shadow:none}
|
||||
body[data-design=paper] .game-notice{background:#FAFBF7;color:#506674;border:1px solid #D3DFE3;box-shadow:none}
|
||||
body[data-design=paper] .rotations button>span,body[data-design=paper]:not(.editing) .rotate-button>.ui-icon{filter:brightness(0) saturate(100%) invert(43%) sepia(12%) saturate(987%) hue-rotate(161deg) brightness(94%) contrast(88%)}
|
||||
body[data-design=paper][data-theme=midnight] .rotations button>span,body[data-design=paper][data-theme=midnight]:not(.editing) .rotate-button>.ui-icon{filter:none}
|
||||
body[data-design=paper] .game-tool{--item-color:#477FC0;--item-border:1px solid #FFFFFFCC;--item-radius:50%}
|
||||
body[data-design=paper] .game-tool[data-tool=restart]{--item-color:#D66C4D}
|
||||
body[data-design=paper] .game-tool[data-tool=hint]{--item-color:#B58943;--item-icon-filter:none}
|
||||
.sheet-reference{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:40px;align-items:center;margin:0 0 48px;padding:28px;background:#EAF0F3;border-radius:24px}
|
||||
.sheet-reference canvas{display:block;width:100%;height:auto}.sheet-reference h2{font-size:28px;margin:14px 0}.sheet-reference p{font-size:13px;color:#506674}.sheet-reference a{font-size:12px;text-decoration:underline;text-underline-offset:4px}
|
||||
.reference-spec{display:grid;grid-template-columns:1fr auto;gap:12px;font-size:12px;padding:18px 0;border-top:1px solid #CBD7DD;border-bottom:1px solid #CBD7DD}.reference-spec dt,.reference-spec dd{margin:0}.reference-spec dd{font-family:ui-monospace,monospace;color:#506674}
|
||||
@media(max-width:650px){.sheet-reference{grid-template-columns:1fr;gap:20px;padding:18px}.sheet-reference h2{font-size:24px}}
|
||||
.sheet-nav{gap:16px;align-items:center;flex-wrap:wrap}.sheet-family-nav{display:flex;flex-wrap:wrap;gap:8px;padding-top:20px}.sheet-family-nav a{font-size:11px;min-height:40px;padding:11px 13px;border:1px solid #CBD7DD;border-radius:10px}.sheet-family-nav a[aria-current=page]{background:#294D60;color:#FFFFFF;border-color:#294D60}
|
||||
.sheet-agent-links{display:flex;flex-wrap:wrap;gap:18px;margin-top:18px;font-size:11px;color:#506674}.sheet-agent-links a{text-decoration:underline;text-underline-offset:4px}
|
||||
@@ -1,7 +0,0 @@
|
||||
/* Version selection uses the existing semantic input and text roles. */
|
||||
.campaign-picker{margin:0 0 12px;font-size:13px}
|
||||
.campaign-picker select{appearance:auto;cursor:pointer;min-height:44px;padding:10px 12px;font-size:14px}
|
||||
.campaign-description{margin:0 0 16px}
|
||||
.campaign-description strong{color:var(--color-text-primary)}
|
||||
.campaign-progress-note{display:block;margin-top:5px}
|
||||
.level-dialog-grid .level-btn small{font-size:10px}
|
||||
@@ -1,12 +0,0 @@
|
||||
:root{font-family:'PingFang SC','Microsoft YaHei',sans-serif;color:#273B50;background:#F7F8F5;font-synthesis:none}
|
||||
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0}a{color:inherit;text-decoration:none}button{font:inherit;cursor:pointer}a:focus-visible,button:focus-visible{outline:3px solid #6652B8;outline-offset:5px}p{font-size:14px;line-height:1.85;color:#56687A}h1,h2,h3{letter-spacing:-.6px}h2{font-size:28px;margin:12px 0}main,.catalog-nav,footer{max-width:1320px;margin:auto;padding-left:40px;padding-right:40px}
|
||||
.catalog-nav{display:flex;justify-content:space-between;align-items:center;gap:20px;padding-top:24px;padding-bottom:24px;border-bottom:1px solid #D7DEDF;font-size:13px}.brand{font-size:19px;font-weight:750}.brand span{font-size:11px;font-weight:500;margin-left:14px}.eyebrow{font-size:10px;letter-spacing:2px;color:#56687A;font-weight:650}
|
||||
.catalog-intro{display:grid;grid-template-columns:1fr 310px;align-items:center;gap:70px;padding:62px 0 50px}.catalog-intro h1{font-size:clamp(38px,5vw,62px);line-height:1.18;margin:18px 0}.catalog-intro p{margin-bottom:0}.latest-design{display:flex;flex-direction:column;gap:14px;border-left:2px solid #A9BDC7;padding:8px 0 8px 26px}.latest-design>span{font-size:12px;color:#56687A}.latest-design strong{font-size:25px}.latest-design small{font-size:13px;line-height:1.85;color:#56687A}.latest-design b{font-size:12px;font-weight:600}
|
||||
.compare-heading{display:flex;justify-content:space-between;align-items:center;gap:22px;border-top:1px solid #D7DEDF;padding-top:32px}.compare-heading p{margin-bottom:0}.compare-heading>a{white-space:nowrap;font-size:12px}.catalog-theme-picker{display:flex;gap:8px;flex-wrap:wrap;margin:24px 0 12px}.catalog-theme-picker button{border:1px solid #BCC9CE;border-radius:24px;min-height:44px;padding:10px 20px;color:#273B50;background:transparent;font-size:13px}.catalog-theme-picker button[aria-pressed=true]{color:#FFF;background:#294D60;border-color:#294D60}.comparison-status{font-size:11px;margin:0 0 20px}
|
||||
.catalog-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:24px}.catalog-card{border:1px solid #D7DEDF;background:#FFF;border-radius:20px;overflow:hidden;scroll-margin-top:24px}.card-preview{position:relative;padding:20px 16px 16px}.design-number{font-size:11px;letter-spacing:1px}.card-preview canvas{display:block;width:100%;height:auto;margin-top:4px}.preview-theme{display:block;text-align:center;font-size:12px}.card-body{padding:24px;display:flex;flex-direction:column}.card-body h3{font-size:22px;margin:10px 0 0;display:flex;align-items:center;gap:10px}.card-body h3 small{font-size:10px;letter-spacing:0;font-weight:500;background:#EAF0F3;border-radius:6px;padding:4px 7px}.card-body p{font-size:13px;min-height:72px;margin:12px 0 20px}.card-actions{display:flex;flex-wrap:wrap;gap:12px;align-items:center;font-size:12px}.card-actions a:first-child{background:#294D60;color:white;padding:12px 14px;border-radius:10px}.card-actions a:last-child{padding:10px 0}
|
||||
.theme-map{padding-top:64px;scroll-margin-top:24px}.theme-matrix{border-top:1px solid #D7DEDF;margin-top:26px}.theme-family{display:grid;grid-template-columns:170px 1fr;align-items:center;border-bottom:1px solid #D7DEDF;padding:20px 0;gap:20px}.theme-family h3{font-size:14px;margin:0}.theme-family h3 span{font-size:11px;color:#56687A;margin-right:8px}.theme-family>div{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:16px}.theme-entry{display:flex;gap:10px;align-items:center;min-width:0;padding:4px 0}.theme-entry i{width:28px;height:38px;border:1px solid #273B5020;border-radius:7px;flex-shrink:0}.theme-entry small,.theme-entry strong{display:block}.theme-entry small{font-size:10px;color:#56687A;margin-bottom:5px}.theme-entry strong{font-size:12px;font-weight:500;line-height:1.5}.theme-entry b{display:none;font-size:12px;font-weight:400}
|
||||
.catalog-notes{display:grid;grid-template-columns:250px 1fr;gap:24px;padding:54px 0}.catalog-notes ul{margin:0;padding-left:18px;font-size:13px;line-height:2.2;color:#56687A}.catalog-notes>a{grid-column:2;font-size:12px;text-decoration:underline;text-underline-offset:5px}footer{display:flex;justify-content:space-between;gap:20px;padding-top:24px;padding-bottom:30px;border-top:1px solid #D7DEDF;font-size:11px;color:#56687A}
|
||||
@media(max-width:1050px){.catalog-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.catalog-intro{gap:36px}.theme-family{grid-template-columns:1fr;gap:16px}}
|
||||
@media(max-width:650px){main,.catalog-nav,footer{padding-left:22px;padding-right:22px}.brand{font-size:17px}.brand span{display:none}.catalog-nav{font-size:12px}.catalog-intro{grid-template-columns:1fr;gap:28px;padding:38px 0}.catalog-intro h1{font-size:40px}.latest-design{padding-left:18px}.latest-design small{display:none}.latest-design{gap:10px}.compare-heading{display:block}.compare-heading>a{display:inline-block;margin-top:16px}h2{font-size:24px}.catalog-theme-picker{gap:6px}.catalog-theme-picker button{padding:9px 13px;font-size:12px}.catalog-grid{grid-template-columns:1fr;gap:22px}.card-body p{min-height:0}.theme-map{padding-top:44px}.theme-family>div{grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.theme-entry b{display:block;margin-left:auto}.theme-entry{padding-right:6px}.catalog-notes{grid-template-columns:1fr;gap:16px;padding:40px 0}.catalog-notes>a{grid-column:auto}footer{flex-direction:column;gap:12px}}
|
||||
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
|
||||
.catalog-nav nav{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:18px;font-size:12px}@media(max-width:650px){.catalog-nav nav{gap:10px;font-size:10px}}
|
||||
@@ -49,72 +49,3 @@ button:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid
|
||||
dialog::backdrop{background:var(--color-scrim);backdrop-filter:blur(5px);-webkit-backdrop-filter:blur(5px)}
|
||||
@media(max-height:700px){.rotate-button>.ui-icon{width:52px;height:52px}.rotate-button{min-height:88px}.board-instruction{font-size:11px}}
|
||||
@media(prefers-reduced-motion:reduce){.rotate-button.hinted{animation:none}}
|
||||
|
||||
/* V2 scenes: environmental ink is independent of modal/utility ink. */
|
||||
.level-ribbon,.moves-bubble strong,.moves-bubble>span,.board-instruction,.rotate-button,.board-tools>button,.theme-caption{color:var(--scene-ink,var(--color-text-primary))}
|
||||
.theme-caption{grid-column:1;text-align:center;font-size:11px;letter-spacing:1px;margin-top:8px}
|
||||
.swatches{grid-template-columns:repeat(4,1fr);padding:0;gap:7px}
|
||||
.swatches button{min-height:36px}
|
||||
.pigment-swatch>.ui-plate{background:var(--pigment)}
|
||||
.pigment-swatch>.ui-plate>.sprite-crop{display:none}
|
||||
.canvas-wrap{overflow:visible}
|
||||
@media(max-height:700px){.canvas-wrap{width:min(100%,max(270px,calc(100dvh - 380px)))}}
|
||||
.canvas-wrap{overflow:hidden}.board-zoom{display:flex;align-items:center;justify-content:center;gap:8px;padding:5px 0;position:relative;z-index:2;color:var(--scene-ink,var(--color-text-primary))}.canvas-wrap{aspect-ratio:auto}.canvas-wrap canvas{aspect-ratio:1;height:auto}.board-zoom button{min-width:38px;min-height:36px;font-size:13px}.board-zoom span{font-size:10px}
|
||||
/* Board-first play screen: HUD, a tall viewport, one compact action row. */
|
||||
.board-zoom{display:none!important}
|
||||
body:not(.editing) .game-shell{height:100dvh;min-height:0;padding:8px 8px max(8px,env(safe-area-inset-bottom))}
|
||||
body:not(.editing) .workspace,body:not(.editing) .game-column{height:100%;min-height:0}
|
||||
body:not(.editing) .game-column{display:grid;grid-template-rows:52px minmax(0,1fr);gap:0}
|
||||
body:not(.editing) .level-heading,body:not(.editing) .theme-caption,body:not(.editing) .board-instruction{display:none}
|
||||
body:not(.editing) .hud{grid-row:1;margin:0;padding:0}
|
||||
body:not(.editing) .moves-bubble{height:48px;display:flex;flex-direction:row;gap:8px}
|
||||
body:not(.editing) .moves-bubble strong{font-size:28px}
|
||||
body:not(.editing) .game-top{top:10px;left:14px;right:14px}
|
||||
body:not(.editing) .game-card{grid-row:2;min-height:0;display:grid;grid-template-columns:repeat(5,1fr);grid-template-rows:minmax(0,1fr) 64px;gap:0}
|
||||
body:not(.editing) .canvas-wrap{grid-column:1/-1;grid-row:1;width:100%;height:100%;min-height:0;margin:0;aspect-ratio:auto}
|
||||
body:not(.editing) .canvas-wrap canvas{width:100%;height:100%;aspect-ratio:auto}
|
||||
body:not(.editing) .rotation-controls,body:not(.editing) .board-tools{display:contents}
|
||||
body:not(.editing) .rotate-button,body:not(.editing) .board-tools>button{grid-row:2;min-width:0;min-height:44px;padding:6px 0 0;margin:0;display:flex;flex-direction:column;justify-content:center;gap:4px}
|
||||
body:not(.editing) .rotate-button>.ui-icon{width:34px;height:34px}
|
||||
body:not(.editing) .rotate-button b,body:not(.editing) .board-tools b{font-size:11px;letter-spacing:0}
|
||||
body:not(.editing) .tool-icon{width:40px;height:36px}
|
||||
body:not(.editing) .tool-icon .ui-icon{width:24px;height:24px}
|
||||
body:not(.editing) .tool-icon small{display:none}
|
||||
body:not(.editing) .return-editor{position:absolute;top:12px;right:12px;margin:0;z-index:4}
|
||||
@media(min-width:700px){body:not(.editing) .game-shell{height:calc(100dvh - 30px)}}
|
||||
/* Restore navigation and float rotation controls over the tall board. */
|
||||
body:not(.editing) .game-column{grid-template-rows:44px 44px minmax(0,1fr)}
|
||||
body:not(.editing) .level-heading{display:block;grid-row:1;align-self:center;margin:0;padding:0 60px}
|
||||
body:not(.editing) .level-ribbon{font-size:24px}
|
||||
body:not(.editing) .hud{grid-row:2}
|
||||
body:not(.editing) .moves-bubble{height:40px}
|
||||
body:not(.editing) .game-card{grid-row:3;grid-template-columns:repeat(3,1fr);position:relative}
|
||||
body:not(.editing) .rotation-controls{display:flex;position:absolute;left:0;right:0;bottom:76px;justify-content:space-around;margin:0;padding:0 24px;gap:50px;z-index:3;pointer-events:none}
|
||||
body:not(.editing) .rotate-button{pointer-events:auto;min-width:80px;min-height:84px;gap:7px;padding:4px}
|
||||
body:not(.editing) .rotate-button>.ui-icon{width:58px;height:58px}
|
||||
body:not(.editing) .rotate-button b{font-size:13px}
|
||||
|
||||
/* Expanded foldables, tablets and desktop windows share a height-aware stage. */
|
||||
@media(min-width:600px){
|
||||
body:not(.editing){padding:16px}
|
||||
body:not(.editing) .game-shell{width:min(100%,960px,calc(100dvh + 80px));height:calc(100dvh - 32px);max-height:1200px;padding:12px 20px 16px;margin:auto}
|
||||
body:not(.editing) .game-column{grid-template-rows:48px 44px minmax(0,1fr)}
|
||||
body:not(.editing) .game-top{top:14px;left:28px;right:28px}
|
||||
body:not(.editing) .game-card{grid-template-rows:minmax(0,1fr) 72px}
|
||||
body:not(.editing) .rotation-controls{bottom:88px;left:4%;right:4%;justify-content:space-between}
|
||||
body:not(.editing) .board-tools>button{justify-self:center;width:96px}
|
||||
body:not(.editing) .level-ribbon{font-size:28px}
|
||||
}
|
||||
@media(min-width:600px) and (max-height:600px){
|
||||
body:not(.editing){padding:6px}
|
||||
body:not(.editing) .game-shell{height:calc(100dvh - 12px);padding:4px 12px}
|
||||
body:not(.editing) .game-column{grid-template-rows:40px 32px minmax(0,1fr)}
|
||||
body:not(.editing) .game-top{top:4px}
|
||||
body:not(.editing) .game-card{grid-template-rows:minmax(0,1fr) 56px}
|
||||
body:not(.editing) .rotation-controls{bottom:66px;left:0;right:0}
|
||||
body:not(.editing) .rotate-button>.ui-icon{width:46px;height:46px}
|
||||
}
|
||||
body:not(.editing) .game-card{align-self:stretch}
|
||||
|
||||
/* Warm gold reward stars with a restrained halo. */
|
||||
.result-emblem .ui-icon[data-icon="star"]{filter:brightness(0) saturate(100%) invert(79%) sepia(85%) saturate(1450%) hue-rotate(350deg) brightness(105%) contrast(102%) drop-shadow(0 2px 1px #c88b2380) drop-shadow(0 0 7px #ffd45c99) drop-shadow(0 0 16px #ffe8a366)}
|
||||
|
||||
+7
-143
@@ -73,25 +73,25 @@
|
||||
},
|
||||
{
|
||||
"label": "分格 / 棋盘",
|
||||
"foreground": "#89867D",
|
||||
"foreground": "#7C8B94",
|
||||
"background": "#F2EEE5",
|
||||
"ratio": 3.143,
|
||||
"ratio": 3.034,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "轨道 / 棋盘",
|
||||
"foreground": "#435F78",
|
||||
"foreground": "#6D808B",
|
||||
"background": "#F2EEE5",
|
||||
"ratio": 5.764,
|
||||
"ratio": 3.549,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "轨道 / 浅色外缘",
|
||||
"foreground": "#435F78",
|
||||
"background": "#F2EEE5",
|
||||
"ratio": 5.764,
|
||||
"foreground": "#6D808B",
|
||||
"background": "#DFE3E2",
|
||||
"ratio": 3.174,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
@@ -126,141 +126,5 @@
|
||||
"ratio": 4.598,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "薄荷浅湾 / 场景文字",
|
||||
"foreground": "#273B50",
|
||||
"background": "#C5E4DF",
|
||||
"ratio": 8.501,
|
||||
"minimum": 4.5,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "杏色午后 / 场景文字",
|
||||
"foreground": "#273B50",
|
||||
"background": "#F1D7B8",
|
||||
"ratio": 8.291,
|
||||
"minimum": 4.5,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "鸢尾花园 / 场景文字",
|
||||
"foreground": "#273B50",
|
||||
"background": "#D8D0EB",
|
||||
"ratio": 7.738,
|
||||
"minimum": 4.5,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "玫瑰暮色 / 场景文字",
|
||||
"foreground": "#273B50",
|
||||
"background": "#E7C3CE",
|
||||
"ratio": 7.165,
|
||||
"minimum": 4.5,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "午夜极光 / 场景文字",
|
||||
"foreground": "#F7F6F2",
|
||||
"background": "#293956",
|
||||
"ratio": 10.706,
|
||||
"minimum": 4.5,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "晴空蓝 / 箭头",
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#2392FD",
|
||||
"ratio": 3.181,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "莓果粉 / 箭头",
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#FC3E80",
|
||||
"ratio": 3.42,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "日光黄 / 箭头",
|
||||
"foreground": "#273B50",
|
||||
"background": "#FDBC28",
|
||||
"ratio": 6.785,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "葡萄紫 / 箭头",
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#874FFD",
|
||||
"ratio": 4.598,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "湖水青 / 箭头",
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#008B83",
|
||||
"ratio": 4.183,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "珊瑚橙 / 箭头",
|
||||
"foreground": "#273B50",
|
||||
"background": "#EF704F",
|
||||
"ratio": 3.885,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "嫩芽绿 / 箭头",
|
||||
"foreground": "#273B50",
|
||||
"background": "#91C95B",
|
||||
"ratio": 5.86,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "鸢尾蓝 / 箭头",
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#5267CF",
|
||||
"ratio": 5,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "玫瑰红 / 箭头",
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#C83F66",
|
||||
"ratio": 4.818,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "蜜桃杏 / 箭头",
|
||||
"foreground": "#273B50",
|
||||
"background": "#F5AA83",
|
||||
"ratio": 5.997,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "冰川青 / 箭头",
|
||||
"foreground": "#273B50",
|
||||
"background": "#58C9D5",
|
||||
"ratio": 5.871,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
},
|
||||
{
|
||||
"label": "兰花紫 / 箭头",
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#AE64C7",
|
||||
"ratio": 3.855,
|
||||
"minimum": 3,
|
||||
"pass": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=animals/index.html"><title>动物弯弯镇 · 设计稿已迁移</title></head><body><p>设计稿已整理到独立目录:<a href="animals/index.html">04 · 动物弯弯镇</a></p></body></html>
|
||||
@@ -1,5 +0,0 @@
|
||||
# 04 · 动物弯弯镇
|
||||
|
||||
本文件为旧入口。完整、人工维护的 Agent 规范已迁移到 [animals/design.md](animals/design.md)。
|
||||
|
||||
[设计稿](animals/index.html) · [配色数据](animals/tokens.json) · [Agent 接入说明](../README.md)
|
||||
@@ -1,52 +0,0 @@
|
||||
# 04 · 动物弯弯镇
|
||||
|
||||
设计 ID:`animals` · 渲染风格:`animals` · 英文名:PAW PARADE。卡通动物候选方案,可与其他方案同时保留。
|
||||
|
||||
[Agent 接入约定](../../shared.md) · [配色数据](tokens.json) · [完整设计稿](index.html) · [试玩与审核](../../../design-showcase.html?design=animals)
|
||||
|
||||
## 设计目标
|
||||
|
||||
猫、熊、兔与青蛙沿轨道出游。颜色来自毛色、草地、木棕和奶油色,保留自然感。表情用来增加性格;玩家通过独立箭头判断方向,不靠动物脸朝向猜规则。
|
||||
|
||||
## 棋盘与棋子怎么画
|
||||
|
||||
复用 [renderer.js](../../../src/renderer.js) 的非 paper 棋盘和 [token-art.js](../../../src/token-art.js) 的 animals 分支。r = 格半径 s × 0.985。
|
||||
|
||||
| 部件 | 当前实现 |
|
||||
| --- | --- |
|
||||
| 分格/轨道 | 分格 max(1, s × 0.024),外缘 max(4, s × 0.16),中心线 max(2.5, s × 0.10) |
|
||||
| 六角底托 | 半径 r × 0.94,奶油白 #FFFCED,浅绿边 #526F5744、线宽 r × 0.035 |
|
||||
| 动物种类 | 经主题映射后的色库索引 % 4:0 猫、1 熊、2 兔、3 蛙 |
|
||||
| 脸部 | 圆脸半径 r × 0.51,中心上移 r × 0.04;耳朵用三角、圆或采样椭圆 |
|
||||
| 表情 | 深色 #263A3A 眼睛与嘴,#EF958B 腮红;不增加数字或文字 |
|
||||
| 方向底 | 下方 y + r × 0.43 的白圆,半径 r × 0.36 |
|
||||
| 方向箭头 | #263A3A 实心箭头,尺度 r × 0.44,位于白圆内 |
|
||||
|
||||
动物轮廓和脸保持正立,方向箭头独立旋转。tokens.json 中 pigments.arrow 是共享颜色 token;**animals 分支的实际箭头固定为 #263A3A,底色是白圆**,不要用颜料色库的 arrow 覆盖脸下方向区。
|
||||
|
||||
角色种类是表现映射,不是游戏功能或阵营。初始棋子索引决定主题色,再决定种类;移除棋子后不可重排剩余动物。全部造型为多边形、线与圆,不需要另生成动物 PNG。
|
||||
|
||||
## 五种主题
|
||||
|
||||
| 主题 ID | 阶段 | 名称 | 独立用色方向 |
|
||||
| --- | --- | --- | --- |
|
||||
| lagoon | 轻松 | 青草野餐 | 草地绿、奶油底与动物毛色 |
|
||||
| apricot | 进阶 | 橡果秋游 | 秋叶黄、橡果棕与麦芽金 |
|
||||
| lavender | 烧脑 | 溪边捉迷藏 | 溪水青、苔绿与暖棕 |
|
||||
| rose | 挑战 | 红土探险 | 红土环境与沙色小径 |
|
||||
| midnight | 每周挑战 | 萤火森林 | 深森林绿与萤火浅黄 |
|
||||
|
||||
完整配色和每主题 4/7/9/12 色有序 palette 见 tokens.json,源为 [art-directions.js](../../../src/art-directions.js)。不要把原版粉紫糖果配色直接套在动物脸上。
|
||||
|
||||
## 控件与边界
|
||||
|
||||
顶部控件与通知延续绿、奶油色与圆润边界。底部道具为苔绿/木棕/黄的纯色底座,圆角比例 44% 44% 36% 36%,3px 奶油边;有轻微点线装饰,无投影或立体厚度。角标与通关星星规则见 shared.md。
|
||||
|
||||
## 验收与接入
|
||||
|
||||
使用 `artDirection('animals')` 和 `directionTheme(direction, themeId, colorCount)`。
|
||||
|
||||
- 在最小棋子尺寸检查耳朵、脸、白圆与箭头,不因表情抢走方向信息。
|
||||
- 检查六个方向、转弯移动、撤销后的动物种类与配色稳定。
|
||||
- 夜间主题中浅色角色与绿板面分离,方向仍靠箭头表达。
|
||||
- 原生适配需核对 circle 与 polygon 的图层顺序;现有 Cocos 示例未完成此套角色的实机验收。
|
||||
File diff suppressed because one or more lines are too long
@@ -1,469 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generated": true,
|
||||
"generatedBy": "scripts/build-art-directions.mjs",
|
||||
"pathBase": "repository-root",
|
||||
"designId": "animals",
|
||||
"artStyle": "animals",
|
||||
"sources": {
|
||||
"directions": "src/art-directions.js",
|
||||
"baseTokens": "src/design-tokens.js",
|
||||
"renderer": "src/renderer.js",
|
||||
"tokenDrawing": "src/token-art.js",
|
||||
"componentStyles": "design/art-directions.css",
|
||||
"itemStyles": "design/game-tools.css"
|
||||
},
|
||||
"accent": "#396D51",
|
||||
"documentBackground": "#FFFCF1",
|
||||
"sharedSemanticColors": {
|
||||
"background": "#A8BECF",
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5",
|
||||
"surface": "#F7F6F2",
|
||||
"textPrimary": "#273B50",
|
||||
"textSecondary": "#314A5F",
|
||||
"primary": "#6652B8",
|
||||
"onPrimary": "#FFFFFF",
|
||||
"secondary": "#E4EAF0",
|
||||
"utility": "#52697E",
|
||||
"onUtility": "#FFFFFF",
|
||||
"selection": "#DFD9F3",
|
||||
"onSelection": "#3F327A",
|
||||
"disabled": "#CBD4DD",
|
||||
"onDisabled": "#526579",
|
||||
"input": "#FFFFFF",
|
||||
"reward": "#B9760C",
|
||||
"warning": "#A44825",
|
||||
"warningSurface": "#F9E3D2",
|
||||
"scrim": "#273B507A",
|
||||
"focus": "#3F327A",
|
||||
"tileBlue": "#2392FD",
|
||||
"tilePink": "#FC3E80",
|
||||
"tileYellow": "#FDBC28",
|
||||
"tilePurple": "#874FFD",
|
||||
"arrowLight": "#FFFFFF",
|
||||
"arrowDark": "#273B50"
|
||||
},
|
||||
"assets": {
|
||||
"tileAtlas": null,
|
||||
"uiIconAtlas": "assets/ui-icons-generated.png"
|
||||
},
|
||||
"pigments": [
|
||||
{
|
||||
"index": 0,
|
||||
"name": "姜黄猫",
|
||||
"color": "#D9934F",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"name": "栗棕熊",
|
||||
"color": "#A4683B",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"name": "麦芽兔",
|
||||
"color": "#E1C58B",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"name": "苔绿蛙",
|
||||
"color": "#6C9D40",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"name": "奶橘猫",
|
||||
"color": "#F1B869",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"name": "可可熊",
|
||||
"color": "#73503F",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"name": "奶油兔",
|
||||
"color": "#F1DCC1",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"name": "溪绿蛙",
|
||||
"color": "#448A67",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 8,
|
||||
"name": "榛果猫",
|
||||
"color": "#B78157",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 9,
|
||||
"name": "赤陶熊",
|
||||
"color": "#BD784F",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 10,
|
||||
"name": "雪白兔",
|
||||
"color": "#F4E5CF",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 11,
|
||||
"name": "嫩叶蛙",
|
||||
"color": "#87B76B",
|
||||
"arrow": "#172D39"
|
||||
}
|
||||
],
|
||||
"themes": [
|
||||
{
|
||||
"id": "lagoon",
|
||||
"label": "轻松",
|
||||
"name": "青草野餐",
|
||||
"background": "#A9CD69",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FFF2D2",
|
||||
"boardGrid": "#A9AC80",
|
||||
"track": "#527345",
|
||||
"trackHalo": "#FFF2D2"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
6,
|
||||
7,
|
||||
10
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
6,
|
||||
7,
|
||||
10
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
9,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 9.183048868633442,
|
||||
"trackOnBoard": 4.8456513485094925
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "apricot",
|
||||
"label": "进阶",
|
||||
"name": "橡果秋游",
|
||||
"background": "#E7B947",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FFEDB5",
|
||||
"boardGrid": "#B6A076",
|
||||
"track": "#79572E",
|
||||
"trackHalo": "#FFEDB5"
|
||||
},
|
||||
"anchorPalette": [
|
||||
1,
|
||||
4,
|
||||
8,
|
||||
5,
|
||||
2,
|
||||
6,
|
||||
11
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
1,
|
||||
4,
|
||||
8,
|
||||
5
|
||||
],
|
||||
"7": [
|
||||
1,
|
||||
4,
|
||||
8,
|
||||
5,
|
||||
2,
|
||||
6,
|
||||
11
|
||||
],
|
||||
"9": [
|
||||
1,
|
||||
4,
|
||||
8,
|
||||
5,
|
||||
2,
|
||||
6,
|
||||
11,
|
||||
0,
|
||||
3
|
||||
],
|
||||
"12": [
|
||||
1,
|
||||
4,
|
||||
8,
|
||||
5,
|
||||
2,
|
||||
6,
|
||||
11,
|
||||
0,
|
||||
3,
|
||||
7,
|
||||
9,
|
||||
10
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 9.028864535418991,
|
||||
"trackOnBoard": 5.607739454320704
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lavender",
|
||||
"label": "烧脑",
|
||||
"name": "溪边捉迷藏",
|
||||
"background": "#72BEB2",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#ECF1D8",
|
||||
"boardGrid": "#9CA987",
|
||||
"track": "#3B7262",
|
||||
"trackHalo": "#ECF1D8"
|
||||
},
|
||||
"anchorPalette": [
|
||||
7,
|
||||
3,
|
||||
6,
|
||||
10,
|
||||
0,
|
||||
4,
|
||||
9
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
7,
|
||||
3,
|
||||
6,
|
||||
10
|
||||
],
|
||||
"7": [
|
||||
7,
|
||||
3,
|
||||
6,
|
||||
10,
|
||||
0,
|
||||
4,
|
||||
9
|
||||
],
|
||||
"9": [
|
||||
7,
|
||||
3,
|
||||
6,
|
||||
10,
|
||||
0,
|
||||
4,
|
||||
9,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"12": [
|
||||
7,
|
||||
3,
|
||||
6,
|
||||
10,
|
||||
0,
|
||||
4,
|
||||
9,
|
||||
1,
|
||||
2,
|
||||
5,
|
||||
8,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 7.6821442549225605,
|
||||
"trackOnBoard": 4.812692332706211
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rose",
|
||||
"label": "挑战",
|
||||
"name": "红土探险",
|
||||
"background": "#C67B47",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#F6DCB2",
|
||||
"boardGrid": "#B19169",
|
||||
"track": "#684835",
|
||||
"trackHalo": "#F6DCB2"
|
||||
},
|
||||
"anchorPalette": [
|
||||
8,
|
||||
5,
|
||||
4,
|
||||
2,
|
||||
7,
|
||||
10,
|
||||
1
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
8,
|
||||
5,
|
||||
4,
|
||||
2
|
||||
],
|
||||
"7": [
|
||||
8,
|
||||
5,
|
||||
4,
|
||||
2,
|
||||
7,
|
||||
10,
|
||||
1
|
||||
],
|
||||
"9": [
|
||||
8,
|
||||
5,
|
||||
4,
|
||||
2,
|
||||
7,
|
||||
10,
|
||||
1,
|
||||
0,
|
||||
3
|
||||
],
|
||||
"12": [
|
||||
8,
|
||||
5,
|
||||
4,
|
||||
2,
|
||||
7,
|
||||
10,
|
||||
1,
|
||||
0,
|
||||
3,
|
||||
6,
|
||||
9,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 4.997261835536376,
|
||||
"trackOnBoard": 6.154627594688633
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "midnight",
|
||||
"label": "每周挑战",
|
||||
"name": "萤火森林",
|
||||
"background": "#183F36",
|
||||
"ink": "#FFFFFF",
|
||||
"materials": {
|
||||
"board": "#355C43",
|
||||
"boardGrid": "#879969",
|
||||
"track": "#E6E9AE",
|
||||
"trackHalo": "#355C43"
|
||||
},
|
||||
"anchorPalette": [
|
||||
6,
|
||||
10,
|
||||
2,
|
||||
4,
|
||||
11,
|
||||
0,
|
||||
9
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
6,
|
||||
10,
|
||||
2,
|
||||
4
|
||||
],
|
||||
"7": [
|
||||
6,
|
||||
10,
|
||||
2,
|
||||
4,
|
||||
11,
|
||||
0,
|
||||
9
|
||||
],
|
||||
"9": [
|
||||
6,
|
||||
10,
|
||||
2,
|
||||
4,
|
||||
11,
|
||||
0,
|
||||
9,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"12": [
|
||||
6,
|
||||
10,
|
||||
2,
|
||||
4,
|
||||
11,
|
||||
0,
|
||||
9,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
8
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 11.64654981527941,
|
||||
"trackOnBoard": 6.018692953375532
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=calm/index.html"><title>柔和原色 · 设计稿已迁移</title></head><body><p>设计稿已整理到独立目录:<a href="calm/index.html">01 · 柔和原色</a></p></body></html>
|
||||
@@ -1,5 +0,0 @@
|
||||
# 01 · 柔和原色
|
||||
|
||||
本文件为旧入口。完整、人工维护的 Agent 规范已迁移到 [calm/design.md](calm/design.md)。
|
||||
|
||||
[设计稿](calm/index.html) · [配色数据](calm/tokens.json) · [Agent 接入说明](../README.md)
|
||||
@@ -1,51 +0,0 @@
|
||||
# 01 · 柔和原色
|
||||
|
||||
设计 ID:`calm` · 渲染风格:`classic` · 英文名:QUIET TRAILS。这是当前默认的基础方案,可与其他候选方案同时保留。
|
||||
|
||||
[Agent 接入约定](../../shared.md) · [配色数据](tokens.json) · [完整设计稿](index.html) · [试玩与审核](../../../design-showcase.html?design=calm)
|
||||
|
||||
## 设计目标
|
||||
|
||||
低饱和环境、暖白底盘和哑光六角棋子,让注意力集中在弯曲轨道与方向。原有棋子是较鲜明的颜色;“柔和”主要指背景和整体气氛,不代表把全部棋子调成灰色。
|
||||
|
||||
## 棋盘与棋子怎么画
|
||||
|
||||
以格半径 s 为单位。复用 [renderer.js](../../../src/renderer.js) 的 classic 回退分支和 [tile-shape.js](../../../src/tile-shape.js),不要用 paper 的细线比例替换。
|
||||
|
||||
| 部件 | 当前实现 |
|
||||
| --- | --- |
|
||||
| 底格 | 正六角面,半径 s + 0.2;轻微重叠消除抗锯齿接缝 |
|
||||
| 分格线 | 半径 s,线宽 max(1, s × 0.024) |
|
||||
| 轨道外缘 | max(4, s × 0.16),颜色为当前 trackHalo |
|
||||
| 轨道中心线 | max(2.5, s × 0.10),边界端点内收;中间轨道保持连接 |
|
||||
| 棋子 | 半径 s × 0.985 的圆角六边形,rounding 由 roundedHex 实现 |
|
||||
| 箭头 | 实心七点形状,尺度为棋子半径 × 0.58;不新增编号 |
|
||||
|
||||
前四个色库索引可使用 [tiles-matte-clean-v8.png](../../../assets/tiles-matte-clean-v8.png) 的原图中心采样,由 [sprites.js](../../../src/sprites.js) 提供裁切框。其余八色或图集未就绪时用纯色回退。保留共享箭头,不把方向烘焙进图集。
|
||||
|
||||
## 五种主题
|
||||
|
||||
| 主题 ID | 阶段 | 名称 | 氛围 |
|
||||
| --- | --- | --- | --- |
|
||||
| lagoon | 轻松 | 薄荷浅湾 | 浅湾背景,蓝青与日光黄 |
|
||||
| apricot | 进阶 | 杏色午后 | 杏底配珊瑚、鸢尾蓝 |
|
||||
| lavender | 烧脑 | 鸢尾花园 | 柔紫背景,绿与冰川青 |
|
||||
| rose | 挑战 | 玫瑰暮色 | 玫瑰背景与明亮暖色 |
|
||||
| midnight | 每周挑战 | 午夜极光 | 深靛蓝环境,棋盘仍是暖白 |
|
||||
|
||||
完整环境色、文字色、棋盘材质与 4/7/9/12 色有序 palette 见 tokens.json。源为 [design-tokens.js](../../../src/design-tokens.js) 的 LEVEL_THEMES / PIGMENTS。五主题共享基础棋盘材质;不能因为 midnight 是夜间环境就擅自把它的棋盘变深色。箭头按该色库的 3:1 对比度门槛选白色或深蓝灰。
|
||||
|
||||
## 控件与边界
|
||||
|
||||
底部道具保持圆形纯色底座:撤销蓝、重来紫、提示黄,均无阴影。顶部是紧凑的蓝灰导航控件。尺寸、通知位置、居中棋盘及金色奖励按 shared.md;角标只在设计示例出现。
|
||||
|
||||
修改此方案的基础语义色可能影响其他设计继承的面板、奖励与组件,需要检查全部五套。不要替换已接受图集,也不要把新增设计的颜料库复制到 PIGMENTS。
|
||||
|
||||
## 验收与接入
|
||||
|
||||
使用 `artDirection('calm')` → `directionTheme(direction, themeId, colorCount)` → `drawScene(..., {theme})`。详细代码和验证命令见 shared.md。
|
||||
|
||||
- 对比前四色的图集版本与纯色回退,确认方向一致且形状没有脏边。
|
||||
- 检查移除、撤销、离场后颜色稳定;白/深箭头按对应色库切换。
|
||||
- 检查五主题文字与轨道识别度,尤其深背景中的暖白棋盘。
|
||||
- 现有 Cocos 示例可参考图集适配,但五套设计切换与当前动画尚未完成原生验收。
|
||||
File diff suppressed because one or more lines are too long
@@ -1,453 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generated": true,
|
||||
"generatedBy": "scripts/build-art-directions.mjs",
|
||||
"pathBase": "repository-root",
|
||||
"designId": "calm",
|
||||
"artStyle": "classic",
|
||||
"sources": {
|
||||
"directions": "src/art-directions.js",
|
||||
"baseTokens": "src/design-tokens.js",
|
||||
"renderer": "src/renderer.js",
|
||||
"tokenDrawing": "src/token-art.js",
|
||||
"componentStyles": "design/art-directions.css",
|
||||
"itemStyles": "design/game-tools.css"
|
||||
},
|
||||
"accent": "#6652B8",
|
||||
"documentBackground": "#F7F6F2",
|
||||
"sharedSemanticColors": {
|
||||
"background": "#A8BECF",
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5",
|
||||
"surface": "#F7F6F2",
|
||||
"textPrimary": "#273B50",
|
||||
"textSecondary": "#314A5F",
|
||||
"primary": "#6652B8",
|
||||
"onPrimary": "#FFFFFF",
|
||||
"secondary": "#E4EAF0",
|
||||
"utility": "#52697E",
|
||||
"onUtility": "#FFFFFF",
|
||||
"selection": "#DFD9F3",
|
||||
"onSelection": "#3F327A",
|
||||
"disabled": "#CBD4DD",
|
||||
"onDisabled": "#526579",
|
||||
"input": "#FFFFFF",
|
||||
"reward": "#B9760C",
|
||||
"warning": "#A44825",
|
||||
"warningSurface": "#F9E3D2",
|
||||
"scrim": "#273B507A",
|
||||
"focus": "#3F327A",
|
||||
"tileBlue": "#2392FD",
|
||||
"tilePink": "#FC3E80",
|
||||
"tileYellow": "#FDBC28",
|
||||
"tilePurple": "#874FFD",
|
||||
"arrowLight": "#FFFFFF",
|
||||
"arrowDark": "#273B50"
|
||||
},
|
||||
"assets": {
|
||||
"tileAtlas": "assets/tiles-matte-clean-v8.png",
|
||||
"uiIconAtlas": "assets/ui-icons-generated.png"
|
||||
},
|
||||
"pigments": [
|
||||
{
|
||||
"index": 0,
|
||||
"name": "晴空蓝",
|
||||
"color": "#2392FD",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"name": "莓果粉",
|
||||
"color": "#FC3E80",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"name": "日光黄",
|
||||
"color": "#FDBC28",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"name": "葡萄紫",
|
||||
"color": "#874FFD",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"name": "湖水青",
|
||||
"color": "#008B83",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"name": "珊瑚橙",
|
||||
"color": "#EF704F",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"name": "嫩芽绿",
|
||||
"color": "#91C95B",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"name": "鸢尾蓝",
|
||||
"color": "#5267CF",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 8,
|
||||
"name": "玫瑰红",
|
||||
"color": "#C83F66",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 9,
|
||||
"name": "蜜桃杏",
|
||||
"color": "#F5AA83",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"index": 10,
|
||||
"name": "冰川青",
|
||||
"color": "#58C9D5",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"index": 11,
|
||||
"name": "兰花紫",
|
||||
"color": "#AE64C7",
|
||||
"arrow": "#FFFFFF"
|
||||
}
|
||||
],
|
||||
"themes": [
|
||||
{
|
||||
"id": "lagoon",
|
||||
"label": "轻松",
|
||||
"name": "薄荷浅湾",
|
||||
"background": "#C5E4DF",
|
||||
"ink": "#273B50",
|
||||
"materials": {
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
4,
|
||||
2
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
6
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 8.500875345312332,
|
||||
"trackOnBoard": 5.763617196441413
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "apricot",
|
||||
"label": "进阶",
|
||||
"name": "杏色午后",
|
||||
"background": "#F1D7B8",
|
||||
"ink": "#273B50",
|
||||
"materials": {
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5"
|
||||
},
|
||||
"anchorPalette": [
|
||||
5,
|
||||
7,
|
||||
4,
|
||||
9
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
5,
|
||||
7,
|
||||
4,
|
||||
9
|
||||
],
|
||||
"7": [
|
||||
5,
|
||||
7,
|
||||
4,
|
||||
9,
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"9": [
|
||||
5,
|
||||
7,
|
||||
4,
|
||||
9,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
6
|
||||
],
|
||||
"12": [
|
||||
5,
|
||||
7,
|
||||
4,
|
||||
9,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 8.290501231652167,
|
||||
"trackOnBoard": 5.763617196441413
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lavender",
|
||||
"label": "烧脑",
|
||||
"name": "鸢尾花园",
|
||||
"background": "#D8D0EB",
|
||||
"ink": "#273B50",
|
||||
"materials": {
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5"
|
||||
},
|
||||
"anchorPalette": [
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
10
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
10
|
||||
],
|
||||
"7": [
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
10,
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"9": [
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
10,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"12": [
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
10,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
5,
|
||||
7,
|
||||
9,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 7.737507893072143,
|
||||
"trackOnBoard": 5.763617196441413
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rose",
|
||||
"label": "挑战",
|
||||
"name": "玫瑰暮色",
|
||||
"background": "#E7C3CE",
|
||||
"ink": "#273B50",
|
||||
"materials": {
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5"
|
||||
},
|
||||
"anchorPalette": [
|
||||
8,
|
||||
7,
|
||||
2,
|
||||
11
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
8,
|
||||
7,
|
||||
2,
|
||||
11
|
||||
],
|
||||
"7": [
|
||||
8,
|
||||
7,
|
||||
2,
|
||||
11,
|
||||
0,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"9": [
|
||||
8,
|
||||
7,
|
||||
2,
|
||||
11,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"12": [
|
||||
8,
|
||||
7,
|
||||
2,
|
||||
11,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
9,
|
||||
10
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 7.164821183322833,
|
||||
"trackOnBoard": 5.763617196441413
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "midnight",
|
||||
"label": "每周挑战",
|
||||
"name": "午夜极光",
|
||||
"background": "#293956",
|
||||
"ink": "#F7F6F2",
|
||||
"materials": {
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5"
|
||||
},
|
||||
"anchorPalette": [
|
||||
10,
|
||||
11,
|
||||
2,
|
||||
1
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
10,
|
||||
11,
|
||||
2,
|
||||
1
|
||||
],
|
||||
"7": [
|
||||
10,
|
||||
11,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"9": [
|
||||
10,
|
||||
11,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6
|
||||
],
|
||||
"12": [
|
||||
10,
|
||||
11,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 10.705759057123668,
|
||||
"trackOnBoard": 5.763617196441413
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=macaron/index.html"><title>马卡龙 · 设计稿已迁移</title></head><body><p>设计稿已整理到独立目录:<a href="macaron/index.html">07 · 马卡龙</a></p></body></html>
|
||||
@@ -1,5 +0,0 @@
|
||||
# 07 · 马卡龙
|
||||
|
||||
本文件为旧入口。完整、人工维护的 Agent 规范已迁移到 [macaron/design.md](macaron/design.md)。
|
||||
|
||||
[设计稿](macaron/index.html) · [配色数据](macaron/tokens.json) · [Agent 接入说明](../README.md)
|
||||
@@ -1,72 +0,0 @@
|
||||
# 07 · 马卡龙
|
||||
|
||||
设计 ID:`macaron` · 渲染风格:`macaron` · 英文名:MACARON。2026-09-14 参考 Meowdoku(喵喵数独)的设计语言制作,可与其他方案同时保留。参考分析与实机对照见 [docs/art-proposal-macaron.html](../../../docs/art-proposal-macaron.html)。
|
||||
|
||||
[Agent 接入约定](../../shared.md) · [配色数据](tokens.json) · [完整设计稿](index.html) · [试玩与审核](../../../design-showcase.html?design=macaron)
|
||||
|
||||
## 设计目标
|
||||
|
||||
从 Meowdoku 借来的是一套"奶油世界 + 白卡片 + 糖果色块 + 白色粗记号"的语言:奶油色世界上托一张白色软托盘,六角格像带白缝的软糖砖,藕紫色轨道压在糖砖上;棋子是糖果色圆角六角,白色贴纸边,十二色统一粗圆头白箭头。所有状态用颜色和弹跳表达,不用描边和阴影:路线点亮成棋子自己的浅色,碰撞处橘红打叉,出场从左上角一波弹开,离场撒星。文字是藕紫褐色,行动色只有一种橙。
|
||||
|
||||
## 棋盘与棋子怎么画
|
||||
|
||||
以格半径 s 为单位,复用 [renderer.js](../../../src/renderer.js) 的 macaron 分支和 [token-art.js](../../../src/token-art.js) 的 macaron 分支。圆角六角由 [tile-shape.js](../../../src/tile-shape.js) 的 `roundedHex(x, y, r, 0.16)` 生成。
|
||||
|
||||
| 部件 | 当前实现 |
|
||||
| --- | --- |
|
||||
| 画布边距 | `layout.pad = 0.3`:布局时每一侧多留 0.3 格半径;同时画布向左右各多伸 8px 到外壳内边距里(`.canvas-wrap` 负外边距),所以棋盘尺寸与其他方案相同,出口处的冲出与消融仍落在画布内 |
|
||||
| 托盘 | 全部格面外扩 0.34s 后取凸包,转角圆化半径 0.9s,纯色 `tray`(白),随棋盘旋转 |
|
||||
| 托盘阴影 | 两层不透明色阶:外层再放大 0.06s、下移 0.20s 用 `shadowSoft`;内层下移 0.10s 用 `shadow`。偏移在屏幕坐标里施加,旋转时保持向下 |
|
||||
| 糖砖(格面) | 圆角六角,半径 0.90s,圆角 0.16;格与格之间是 0.17s 的白缝,不画格线 |
|
||||
| 环带色 | 从棋盘中心格向外按六角距离分环,三色循环 `rings[d % 3]`;只表达位置,旋转后不变 |
|
||||
| 轨道 | `track` 藕紫褐(每个世界一档),单层,宽 clamp(0.11s, 2.2, 6.5),圆头圆接;跨过白缝连续画,路线不断开;只有板边端点内收到 0.90s − 轨宽/√3 |
|
||||
| 棋子 | 圆角六角,半径 0.90s,正好盖满糖砖,圆角 0.16,纯色面;白色贴纸边宽 0.10r,与白缝连成一体。轨道从棋子底下钻过:白缝里的一小段一直画到白边为止,和空砖之间的画法一致,所以看得出哪几条轨道通向这枚棋子;不再画底座 |
|
||||
| 箭头 | 白色线条:杆从 −0.34r 到 0.30r,头两笔到 ±0.30r;线宽 0.20r,圆头,十二色统一 |
|
||||
| 路线点亮 | 预览或行进中路线经过的糖砖改用棋子色调白 80%(行进中 84%);被挡时用 `blush` 橘奶色 |
|
||||
| 预览路线 | 棋子本色一根粗线 1.15 × 轨宽,画在轨道上、棋子下;被挡只画到接触点,末端橘红叉 |
|
||||
| 碰撞 | 接触时被撞格改 `blush`,接触点画橘红 `blocked` 叉,大小随 impact 变化;回弹沿用共用碰撞动画 |
|
||||
| 提示 | 两层实心圆角六角光晕:`hintGlow` 1.02s、`hint` 0.94s,露出棋子外一圈蜂蜜黄 |
|
||||
| 出场 | 新棋盘时糖砖、轨道、棋子按左上到右下的顺序缩放弹入:每格延迟 = 归一化位置 × 0.55,各自 0.45 段,ease-out 回弹 5%,总长 720ms |
|
||||
| 离场 | 滑行沿用共用时序;到达出口后是 640ms 的收束(`exitDuration` 把窗口从共用的 180ms 放宽):前 45% 棋子沿出口方向减速冲出 0.55s(三次 ease-out),大半个身体越过托盘边缘;从 15% 起实心面、白边在 20% 内淡掉,箭头在 25% 内淡掉;面被一层同色圆点阵接管(间距 0.17s、半径 0.115s、六角排列、内缩到 0.82r),圆点跟着棋子走,并从外圈向中心依次化掉:开始时刻 = 0.16 + 0.38 × (1 − 到边缘的比例) + 0.16 × 噪声,各自用 0.28 段缩小到 0、颜色向白调 45%、透明度降到 40%、沿固定随机方向漂 0.14s 并上浮 0.10s。没有尾迹、碎片和飞出的粒子 |
|
||||
| 计数 | 棋子离场后 `.moves-bubble` 弹一次(1 → 1.18 → 1,420ms) |
|
||||
| 通关庆祝 | 最后一枚棋子离场后先在棋盘上放 720ms 的清空涟漪(`state.celebrate`):糖砖按到中心格的环数依次鼓起 8% 并向白调亮 35% 再落回,每环延迟 0.07、各自 0.45 段的正弦脉冲;轨道不随之缩放;结束后才淡入结算 |
|
||||
|
||||
不使用棋子图集,不使用滤镜调色。全部造型由多边形、折线与圆组成;阴影是两层不透明多边形,不是模糊。
|
||||
|
||||
## 五种主题
|
||||
|
||||
| 主题 ID | 阶段 | 名称 | 用色方向 |
|
||||
| --- | --- | --- | --- |
|
||||
| lagoon | 轻松 | 奶油 | 奶油底,蜜桃奶/奶黄/薄荷奶三环,草莓、蓝莓、抹茶领色 |
|
||||
| apricot | 进阶 | 蜜桃 | 蜜桃奶油底,蜜柑与海盐蓝领色 |
|
||||
| lavender | 烧脑 | 香芋 | 香芋奶油底,香芋紫与玫瑰领色 |
|
||||
| rose | 挑战 | 草莓牛奶 | 草莓牛奶底,玫瑰与抹茶对照 |
|
||||
| midnight | 每周挑战 | 可可夜 | 可可色底,白托盘像被灯照亮的甜品盘 |
|
||||
|
||||
完整色值、环带色、托盘与阴影色、每主题 4/7/9/12 色有序 palette 见 tokens.json 与 [art-directions.js](../../../src/art-directions.js)。场景文字用藕紫褐(可可夜用奶白),对世界色 5.5 : 1 以上;十二色白箭头最低 3.30 : 1;轨道对三种糖砖最低 3.28 : 1(奶油世界)。
|
||||
|
||||
主游戏中本方案的主题按旅程切换:五个世界平均铺在整条主线上,最后一段为可可夜;`?theme=` 参数仍可强制指定。
|
||||
|
||||
## 控件与边界
|
||||
|
||||
- 字体:资源圆体 Resource Han Rounded(用户指定,SIL OFL),Medium 500 与 Bold 700 两档子集在 [assets/fonts](../../../assets/fonts/README.md),`@font-face` 写在 game-tools.css 的 macaron 段;其后回落 `ui-rounded`、Arial Rounded、Nunito、PingFang。界面里 600 以上的字重落到 Bold,400–500 落到 Medium。子集之外的字符按字形回落到系统字体,新增文案要补进字符表。
|
||||
- 顶部选关、设置:白色圆底加柔和投影,图标通过遮罩着色为深藕紫;不用滤镜。
|
||||
- 关卡号与待解计数:两列并排放在两枚圆钮之间,小标签在上(关卡 / 待解,淡藕紫 12px),大数字在下(26px 粗体深藕紫);由 `direction.hud` 提供标签,app.js 生成;数字在棋子离场后弹一次。教学关显示 入门 N/3。
|
||||
- 通知:白色气泡,顶部小尾巴指向计数胶囊,前置一枚橙点;位置沿用 shared.md(步数下方)。
|
||||
- 旋转按钮:无底座,图标 60px 用世界色对应的浅藕紫着色,标签 12px 藕紫;位置由 [app.js](../../../src/app.js) 的 `placeRotation` 按棋盘几何计算(`layout.rotation = 'under-board'`,`layout.rim = 0.40`):取下方斜边中点,向下作垂线到道具上缘,按钮中心放在垂线中点。旋转不占独立布局行,与 06 相同,是与 shared.md 的一处出入。
|
||||
- 撤销、重来、提示:参考作品的白色圆钮。白底 64px、柔和投影、无描边;图标通过图集遮罩着色为海盐蓝 #4A91D4 / 玫瑰 #D06E93 / 蜂蜜褐 #C98A0E;标签藕紫;禁用 45% 透明。这是与 shared.md「道具无阴影」的一处有意出入,2026-09-14 用户确认只允许本方案使用,不向其他方案放开。
|
||||
- 结算:参考作品的深色庆祝画面,而且是全屏覆盖层:`<dialog>` 铺满整个视口(inset 0、无最大宽高、无圆角、无卡片),320ms 淡入,遮罩 rgba(40,26,32,.86) 加模糊;内容居中,奶白发光标题 25px,副标题浅奶色,金色发光星星后有 640px 缓慢旋转的奶黄射线和一次糖果色纸屑,全部铺在整屏上不被裁切;主按钮是橙色胶囊 `#E07416`(白字 3.1 : 1)底边 4px 深橙,次按钮是半透明奶白胶囊。失败画面用同一覆盖层。
|
||||
- 选关与设置:白色圆角卡片弹入(0.86 → 1,380ms 回弹),顶部一条蜜桃色标题带,右上角白色圆形关闭钮;当前关橙色胶囊,普通关奶油方块,完成关薄荷奶。
|
||||
- 棋盘居中、金色奖励继承 shared.md。
|
||||
|
||||
## 验收与接入
|
||||
|
||||
使用 `artDirection('macaron')` 和 `directionTheme(direction, themeId, colorCount)`;主游戏 `?design=macaron`。
|
||||
|
||||
- 检查五个世界的托盘、阴影方向与环带色;可可夜下托盘保持奶白。
|
||||
- 检查 37 / 61 / 91 格下白缝与轨道宽度:91 格时白缝约 3px、轨道 2.2px,箭头仍可读。
|
||||
- 检查出场动画在换关、重来、教学三处都播放一次;旋转、撤销时不重播;清空涟漪只播一次且全屏结算在它之后淡入,射线与纸屑不被任何盒子裁切。
|
||||
- 检查棋子砖面上没有轨道露出,白缝里通向棋子的轨道段可见,空格之间的轨道连续不断;提示路线连续画过白缝。
|
||||
- 检查路线点亮只覆盖路线经过的格;被挡路线在接触点结束并打叉。
|
||||
- 检查左右两侧出口的消融完整留在画布内,没有被画布边裁掉;`prefers-reduced-motion` 下取消出场、消融、庆祝与计数弹跳。
|
||||
- 原生端需实现两层不透明阴影、圆角六角与遮罩着色;尚未完成原生实机验收。
|
||||
File diff suppressed because one or more lines are too long
@@ -1,469 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generated": true,
|
||||
"generatedBy": "scripts/build-art-directions.mjs",
|
||||
"pathBase": "repository-root",
|
||||
"designId": "macaron",
|
||||
"artStyle": "macaron",
|
||||
"sources": {
|
||||
"directions": "src/art-directions.js",
|
||||
"baseTokens": "src/design-tokens.js",
|
||||
"renderer": "src/renderer.js",
|
||||
"tokenDrawing": "src/token-art.js",
|
||||
"componentStyles": "design/art-directions.css",
|
||||
"itemStyles": "design/game-tools.css"
|
||||
},
|
||||
"accent": "#E07416",
|
||||
"documentBackground": "#FBF6F0",
|
||||
"sharedSemanticColors": {
|
||||
"background": "#A8BECF",
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5",
|
||||
"surface": "#F7F6F2",
|
||||
"textPrimary": "#273B50",
|
||||
"textSecondary": "#314A5F",
|
||||
"primary": "#6652B8",
|
||||
"onPrimary": "#FFFFFF",
|
||||
"secondary": "#E4EAF0",
|
||||
"utility": "#52697E",
|
||||
"onUtility": "#FFFFFF",
|
||||
"selection": "#DFD9F3",
|
||||
"onSelection": "#3F327A",
|
||||
"disabled": "#CBD4DD",
|
||||
"onDisabled": "#526579",
|
||||
"input": "#FFFFFF",
|
||||
"reward": "#B9760C",
|
||||
"warning": "#A44825",
|
||||
"warningSurface": "#F9E3D2",
|
||||
"scrim": "#273B507A",
|
||||
"focus": "#3F327A",
|
||||
"tileBlue": "#2392FD",
|
||||
"tilePink": "#FC3E80",
|
||||
"tileYellow": "#FDBC28",
|
||||
"tilePurple": "#874FFD",
|
||||
"arrowLight": "#FFFFFF",
|
||||
"arrowDark": "#273B50"
|
||||
},
|
||||
"assets": {
|
||||
"tileAtlas": null,
|
||||
"uiIconAtlas": "assets/ui-icons-generated.png"
|
||||
},
|
||||
"pigments": [
|
||||
{
|
||||
"index": 0,
|
||||
"name": "草莓",
|
||||
"color": "#EE5398",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"name": "蜜柑",
|
||||
"color": "#E5680C",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"name": "蜂蜜",
|
||||
"color": "#AB8716",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"name": "抹茶",
|
||||
"color": "#4C9E5A",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"name": "薄荷",
|
||||
"color": "#369C94",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"name": "蓝莓",
|
||||
"color": "#578BF0",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"name": "香芋",
|
||||
"color": "#937DE4",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"name": "玫瑰",
|
||||
"color": "#D06E93",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 8,
|
||||
"name": "可可",
|
||||
"color": "#B5806A",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 9,
|
||||
"name": "海盐",
|
||||
"color": "#4A91D4",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 10,
|
||||
"name": "葡萄",
|
||||
"color": "#8C68CC",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 11,
|
||||
"name": "洋李",
|
||||
"color": "#C56AC4",
|
||||
"arrow": "#FFFFFF"
|
||||
}
|
||||
],
|
||||
"themes": [
|
||||
{
|
||||
"id": "lagoon",
|
||||
"label": "轻松",
|
||||
"name": "奶油",
|
||||
"background": "#F5EFE7",
|
||||
"ink": "#7A5560",
|
||||
"materials": {
|
||||
"board": "#FADBCB",
|
||||
"boardGrid": "#FFFFFF",
|
||||
"track": "#96707B",
|
||||
"trackHalo": "#FFFFFF"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
5,
|
||||
3,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
4
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
5,
|
||||
3,
|
||||
2
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
5,
|
||||
3,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
4
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
5,
|
||||
3,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
4,
|
||||
7,
|
||||
8
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
5,
|
||||
3,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
4,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 5.577670453960404,
|
||||
"trackOnBoard": 3.277177835431525
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "apricot",
|
||||
"label": "进阶",
|
||||
"name": "蜜桃",
|
||||
"background": "#FBE6DA",
|
||||
"ink": "#7C4E52",
|
||||
"materials": {
|
||||
"board": "#FDE3D3",
|
||||
"boardGrid": "#FFFFFF",
|
||||
"track": "#976A66",
|
||||
"trackHalo": "#FFFFFF"
|
||||
},
|
||||
"anchorPalette": [
|
||||
1,
|
||||
9,
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
10,
|
||||
3
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
1,
|
||||
9,
|
||||
0,
|
||||
4
|
||||
],
|
||||
"7": [
|
||||
1,
|
||||
9,
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
10,
|
||||
3
|
||||
],
|
||||
"9": [
|
||||
1,
|
||||
9,
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
10,
|
||||
3,
|
||||
5,
|
||||
6
|
||||
],
|
||||
"12": [
|
||||
1,
|
||||
9,
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
10,
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 5.681057760459171,
|
||||
"trackOnBoard": 3.7433859071275655
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lavender",
|
||||
"label": "烧脑",
|
||||
"name": "香芋",
|
||||
"background": "#EEE8F6",
|
||||
"ink": "#5F4E78",
|
||||
"materials": {
|
||||
"board": "#E9E0F6",
|
||||
"boardGrid": "#FFFFFF",
|
||||
"track": "#78678F",
|
||||
"trackHalo": "#FFFFFF"
|
||||
},
|
||||
"anchorPalette": [
|
||||
6,
|
||||
7,
|
||||
4,
|
||||
2,
|
||||
11,
|
||||
5,
|
||||
3
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
6,
|
||||
7,
|
||||
4,
|
||||
2
|
||||
],
|
||||
"7": [
|
||||
6,
|
||||
7,
|
||||
4,
|
||||
2,
|
||||
11,
|
||||
5,
|
||||
3
|
||||
],
|
||||
"9": [
|
||||
6,
|
||||
7,
|
||||
4,
|
||||
2,
|
||||
11,
|
||||
5,
|
||||
3,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"12": [
|
||||
6,
|
||||
7,
|
||||
4,
|
||||
2,
|
||||
11,
|
||||
5,
|
||||
3,
|
||||
0,
|
||||
1,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 6.148741738606406,
|
||||
"trackOnBoard": 3.979775627465162
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rose",
|
||||
"label": "挑战",
|
||||
"name": "草莓牛奶",
|
||||
"background": "#F9E2E8",
|
||||
"ink": "#7B4658",
|
||||
"materials": {
|
||||
"board": "#FBDDE5",
|
||||
"boardGrid": "#FFFFFF",
|
||||
"track": "#966076",
|
||||
"trackHalo": "#FFFFFF"
|
||||
},
|
||||
"anchorPalette": [
|
||||
7,
|
||||
3,
|
||||
5,
|
||||
2,
|
||||
11,
|
||||
8,
|
||||
1
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
7,
|
||||
3,
|
||||
5,
|
||||
2
|
||||
],
|
||||
"7": [
|
||||
7,
|
||||
3,
|
||||
5,
|
||||
2,
|
||||
11,
|
||||
8,
|
||||
1
|
||||
],
|
||||
"9": [
|
||||
7,
|
||||
3,
|
||||
5,
|
||||
2,
|
||||
11,
|
||||
8,
|
||||
1,
|
||||
0,
|
||||
4
|
||||
],
|
||||
"12": [
|
||||
7,
|
||||
3,
|
||||
5,
|
||||
2,
|
||||
11,
|
||||
8,
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
6,
|
||||
9,
|
||||
10
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 5.970867897749838,
|
||||
"trackOnBoard": 3.917201236136076
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "midnight",
|
||||
"label": "每周挑战",
|
||||
"name": "可可夜",
|
||||
"background": "#3E2E35",
|
||||
"ink": "#FBEFE6",
|
||||
"materials": {
|
||||
"board": "#F9E3D6",
|
||||
"boardGrid": "#FFFFFF",
|
||||
"track": "#8A6370",
|
||||
"trackHalo": "#FFFFFF"
|
||||
},
|
||||
"anchorPalette": [
|
||||
4,
|
||||
0,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
3
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
4,
|
||||
0,
|
||||
2,
|
||||
6
|
||||
],
|
||||
"7": [
|
||||
4,
|
||||
0,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
3
|
||||
],
|
||||
"9": [
|
||||
4,
|
||||
0,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
3,
|
||||
5,
|
||||
7
|
||||
],
|
||||
"12": [
|
||||
4,
|
||||
0,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
8,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 11.287619453403153,
|
||||
"trackOnBoard": 4.143716175864876
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=paper/index.html"><title>轻线纸境 · 设计稿已迁移</title></head><body><p>设计稿已整理到独立目录:<a href="paper/index.html">05 · 轻线纸境</a></p></body></html>
|
||||
@@ -1,5 +0,0 @@
|
||||
# 05 · 轻线纸境
|
||||
|
||||
本文件为旧入口。完整、人工维护的 Agent 规范已迁移到 [paper/design.md](paper/design.md)。
|
||||
|
||||
[设计稿](paper/index.html) · [配色数据](paper/tokens.json) · [Agent 接入说明](../README.md)
|
||||
@@ -1,57 +0,0 @@
|
||||
# 05 · 轻线纸境
|
||||
|
||||
设计 ID:`paper` · 渲染风格:`paper` · 英文名:PAPER ROUTES。最新新增的候选方案,可与其他方案同时保留。
|
||||
|
||||
[Agent 接入约定](../../shared.md) · [配色数据](tokens.json) · [完整设计稿](index.html) · [试玩与审核](../../../design-showcase.html?design=paper)
|
||||
|
||||
## 来源与设计目标
|
||||
|
||||
用户认可 [玩法变种实验页](../../../labs/variants/index.html) 的棋盘和棋子画法,要求整理成独立设计。提取暖白格面、浅蓝灰细轨道、陶橙/雾蓝纯色六角、细白边和线条箭头。五主题是这套画法的延展。
|
||||
|
||||
独立设计稿里的「双色试航」只保留初始布局作视觉对照;**不绘制棋盘外围彩色标记,不绘制棋子编号**。实验页的出口颜色匹配规则及外围色标不属于本设计,也不改变主游戏玩法。
|
||||
|
||||
## 棋盘与棋子怎么画
|
||||
|
||||
以格半径 s 为单位,复用 [renderer.js](../../../src/renderer.js) 的 paper 分支和 [token-art.js](../../../src/token-art.js) 的 paper 分支。
|
||||
|
||||
| 部件 | 当前实现 |
|
||||
| --- | --- |
|
||||
| 底格 | 正六角,半径 s × 0.97,保留细小格缝 |
|
||||
| 分格线 | max(0.4, s × 0.025),使用主题 boardGrid |
|
||||
| 轨道 | 单层细线 max(0.7, s × 0.055),不画粗 trackHalo、不做其他方案的端点内收 |
|
||||
| 棋子 | 正六角纯色面,半径 s × 0.88,不能换成原版大圆角轮廓 |
|
||||
| 白边 | #FFFFFFCC,线宽 s × 0.035 |
|
||||
| 箭杆 | 局部坐标 (-0.30s, 0) → (0.30s, 0) |
|
||||
| 箭头头部 | (0.08s, -0.17s) → (0.30s, 0) → (0.08s, 0.17s) |
|
||||
| 箭头线条 | 白色、圆头圆接,线宽 s × 0.09;两段开放折线,不是实心三角 |
|
||||
|
||||
头部与箭杆一起按棋子方向或运动切线旋转。绘制分支内部 r = s × 0.88,再用 r / 0.88 还原单位,所以运动缩放时白边和箭头一起缩放。无棋子投影、高光、渐变;不用 PNG 冒充细线箭头。
|
||||
|
||||
## 五种主题
|
||||
|
||||
| 主题 ID | 阶段 | 名称 | 用色方向 |
|
||||
| --- | --- | --- | --- |
|
||||
| lagoon | 轻松 | 雾蓝信纸 | 实验页雾蓝环境、暖白格面、陶橙与雾蓝棋子 |
|
||||
| apricot | 进阶 | 暖砂手札 | 暖砂纸底、灰棕细线 |
|
||||
| lavender | 烧脑 | 鼠尾草页 | 浅灰绿纸底、蓝与苔绿棋子 |
|
||||
| rose | 挑战 | 石墨练习 | 灰白图纸、石墨蓝细线 |
|
||||
| midnight | 每周挑战 | 夜航图纸 | 深蓝灰板面、浅灰蓝轨道与暖色棋子 |
|
||||
|
||||
完整色值和每主题 4/7/9/12 色有序 palette 见 tokens.json,源为 [art-directions.js](../../../src/art-directions.js)。轻松主题关键参考色:环境 #EAF0F3、格面 #FAFBF7、分格 #D3DFE3、轨道 #B2C4CE、陶橙 #D66C4D、雾蓝 #477FC0。全部十二色固定白色箭头,其对比度至少 3:1。
|
||||
|
||||
浅色细轨道低于基础轨道的 3:1 目标,这是保留参考观感的已知取舍,不能为了套用原版指标而擅自加粗、加深或加轮廓。tokens 中的 contrast 是实测比值,不是合规认证。
|
||||
|
||||
## 控件与边界
|
||||
|
||||
顶部使用紧凑蓝灰控件,通知暖白、浅灰蓝边线,均无阴影。底部道具为圆形:撤销雾蓝、重来陶橙、提示赭金,1px 细白边,无阴影。旋转图标在浅主题为蓝灰,midnight 恢复白色;同时设置 body.dataset.design 和 body.dataset.theme。
|
||||
|
||||
通知位置、棋盘居中、大道具、金色发光星星以及示意角标都继承 shared.md。这里的“无阴影”不取消用户要求的奖励星星光感。
|
||||
|
||||
## 验收与接入
|
||||
|
||||
使用 `artDirection('paper')` 和 `directionTheme(direction, themeId, colorCount)`;禁止只换背景而继续使用 classic 的棋子和轨道画法。
|
||||
|
||||
- 对照实验页的细线与六角比例;参考布局没有外围色标与编号。
|
||||
- 检查每个主题的长弯路,移动中仍为开放线条箭头、细白边棋子。
|
||||
- 检查手机小图上的细线不断裂,以及午夜主题的旋转按钮颜色。
|
||||
- 原生适配需检查圆头线端、透明细白边与格缝;尚未完成原生实机验收。
|
||||
File diff suppressed because one or more lines are too long
@@ -1,469 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generated": true,
|
||||
"generatedBy": "scripts/build-art-directions.mjs",
|
||||
"pathBase": "repository-root",
|
||||
"designId": "paper",
|
||||
"artStyle": "paper",
|
||||
"sources": {
|
||||
"directions": "src/art-directions.js",
|
||||
"baseTokens": "src/design-tokens.js",
|
||||
"renderer": "src/renderer.js",
|
||||
"tokenDrawing": "src/token-art.js",
|
||||
"componentStyles": "design/art-directions.css",
|
||||
"itemStyles": "design/game-tools.css"
|
||||
},
|
||||
"accent": "#294D60",
|
||||
"documentBackground": "#F7F9F8",
|
||||
"sharedSemanticColors": {
|
||||
"background": "#A8BECF",
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5",
|
||||
"surface": "#F7F6F2",
|
||||
"textPrimary": "#273B50",
|
||||
"textSecondary": "#314A5F",
|
||||
"primary": "#6652B8",
|
||||
"onPrimary": "#FFFFFF",
|
||||
"secondary": "#E4EAF0",
|
||||
"utility": "#52697E",
|
||||
"onUtility": "#FFFFFF",
|
||||
"selection": "#DFD9F3",
|
||||
"onSelection": "#3F327A",
|
||||
"disabled": "#CBD4DD",
|
||||
"onDisabled": "#526579",
|
||||
"input": "#FFFFFF",
|
||||
"reward": "#B9760C",
|
||||
"warning": "#A44825",
|
||||
"warningSurface": "#F9E3D2",
|
||||
"scrim": "#273B507A",
|
||||
"focus": "#3F327A",
|
||||
"tileBlue": "#2392FD",
|
||||
"tilePink": "#FC3E80",
|
||||
"tileYellow": "#FDBC28",
|
||||
"tilePurple": "#874FFD",
|
||||
"arrowLight": "#FFFFFF",
|
||||
"arrowDark": "#273B50"
|
||||
},
|
||||
"assets": {
|
||||
"tileAtlas": null,
|
||||
"uiIconAtlas": "assets/ui-icons-generated.png"
|
||||
},
|
||||
"pigments": [
|
||||
{
|
||||
"index": 0,
|
||||
"name": "陶橙",
|
||||
"color": "#D66C4D",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"name": "雾蓝",
|
||||
"color": "#477FC0",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"name": "鼠尾草",
|
||||
"color": "#668877",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"name": "赭金",
|
||||
"color": "#B58943",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"name": "雾紫",
|
||||
"color": "#8B7297",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"name": "湖青",
|
||||
"color": "#45868C",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"name": "陶红",
|
||||
"color": "#B76260",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"name": "钢蓝",
|
||||
"color": "#607B90",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 8,
|
||||
"name": "暖木",
|
||||
"color": "#B28168",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 9,
|
||||
"name": "松绿",
|
||||
"color": "#46765F",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 10,
|
||||
"name": "烟蓝",
|
||||
"color": "#6B8AAB",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 11,
|
||||
"name": "藕灰",
|
||||
"color": "#9C7284",
|
||||
"arrow": "#FFFFFF"
|
||||
}
|
||||
],
|
||||
"themes": [
|
||||
{
|
||||
"id": "lagoon",
|
||||
"label": "轻松",
|
||||
"name": "雾蓝信纸",
|
||||
"background": "#EAF0F3",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FAFBF7",
|
||||
"boardGrid": "#D3DFE3",
|
||||
"track": "#B2C4CE",
|
||||
"trackHalo": "#FAFBF7"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
7
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
7
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
7,
|
||||
6,
|
||||
8
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
7,
|
||||
6,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 14.423559313677755,
|
||||
"trackOnBoard": 1.7299985145787213
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "apricot",
|
||||
"label": "进阶",
|
||||
"name": "暖砂手札",
|
||||
"background": "#F3EEE5",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FFFCF5",
|
||||
"boardGrid": "#E3DCD0",
|
||||
"track": "#C4B8A4",
|
||||
"trackHalo": "#FFFCF5"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
9,
|
||||
4
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
6
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
9,
|
||||
4
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
9,
|
||||
4,
|
||||
2,
|
||||
5
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
9,
|
||||
4,
|
||||
2,
|
||||
5,
|
||||
7,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 14.35675892235889,
|
||||
"trackOnBoard": 1.90836044264981
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lavender",
|
||||
"label": "烧脑",
|
||||
"name": "鼠尾草页",
|
||||
"background": "#E8EFEB",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FAFCF8",
|
||||
"boardGrid": "#D3DFD7",
|
||||
"track": "#ADBCB2",
|
||||
"trackHalo": "#FAFCF8"
|
||||
},
|
||||
"anchorPalette": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
9,
|
||||
10,
|
||||
0
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
5
|
||||
],
|
||||
"7": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
9,
|
||||
10,
|
||||
0
|
||||
],
|
||||
"9": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
9,
|
||||
10,
|
||||
0,
|
||||
4,
|
||||
6
|
||||
],
|
||||
"12": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
9,
|
||||
10,
|
||||
0,
|
||||
4,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 14.202869576847103,
|
||||
"trackOnBoard": 1.916933130789821
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rose",
|
||||
"label": "挑战",
|
||||
"name": "石墨练习",
|
||||
"background": "#E7EBEE",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#F8FAFB",
|
||||
"boardGrid": "#D1DBE1",
|
||||
"track": "#A5B6C1",
|
||||
"trackHalo": "#F8FAFB"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
11
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
6
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
11
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
11,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
6,
|
||||
7,
|
||||
10,
|
||||
11,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
8,
|
||||
9
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 13.838133934955545,
|
||||
"trackOnBoard": 1.9936733854132391
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "midnight",
|
||||
"label": "每周挑战",
|
||||
"name": "夜航图纸",
|
||||
"background": "#253B4A",
|
||||
"ink": "#FFFFFF",
|
||||
"materials": {
|
||||
"board": "#304A59",
|
||||
"boardGrid": "#435E6C",
|
||||
"track": "#849FAE",
|
||||
"trackHalo": "#304A59"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
10
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
10
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
10,
|
||||
1,
|
||||
6
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
10,
|
||||
1,
|
||||
6,
|
||||
7,
|
||||
9,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 11.646406631180858,
|
||||
"trackOnBoard": 3.357082701757936
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=signpost/index.html"><title>路标 · 设计稿已迁移</title></head><body><p>设计稿已整理到独立目录:<a href="signpost/index.html">06 · 路标</a></p></body></html>
|
||||
@@ -1,5 +0,0 @@
|
||||
# 06 · 路标
|
||||
|
||||
本文件为旧入口。完整、人工维护的 Agent 规范已迁移到 [signpost/design.md](signpost/design.md)。
|
||||
|
||||
[设计稿](signpost/index.html) · [配色数据](signpost/tokens.json) · [Agent 接入说明](../README.md)
|
||||
@@ -1,59 +0,0 @@
|
||||
# 06 · 路标
|
||||
|
||||
设计 ID:`signpost` · 渲染风格:`signpost` · 英文名:SIGNPOST。2026-09-14 由美术评审后的设计提案接入,可与其他方案同时保留。提案与实机对照见 [docs/art-proposal-signpost.html](../../../docs/art-proposal-signpost.html)。
|
||||
|
||||
[Agent 接入约定](../../shared.md) · [配色数据](tokens.json) · [完整设计稿](index.html) · [试玩与审核](../../../design-showcase.html?design=signpost)
|
||||
|
||||
## 设计目标
|
||||
|
||||
棋盘是一张线路图:奶白卡片托在世界色上,带一圈边框和一层向下偏移的平面底板;浅色路基先铺,墨蓝钢轨再压上去,端点在板边收口。棋子是路标:内缩露出脚下端口,一圈细描边,十二色统一白箭头。控件退到纸面里,一眼看过去重心只在棋盘。
|
||||
|
||||
## 棋盘与棋子怎么画
|
||||
|
||||
以格半径 s 为单位,复用 [renderer.js](../../../src/renderer.js) 的 signpost 分支和 [token-art.js](../../../src/token-art.js) 的 signpost 分支。
|
||||
|
||||
| 部件 | 当前实现 |
|
||||
| --- | --- |
|
||||
| 底板 | 全部格面放大 s + 0.2 + 边框宽,向下偏移 0.12s,纯色 `base`;偏移在屏幕坐标里施加,旋转时保持向下 |
|
||||
| 边框 | 同样放大的格面,纯色 `rim`,内部被格面覆盖只剩外缘;宽 max(1.5, 0.06s) |
|
||||
| 格面 | 正六角 s + 0.2,各主题奶白 `board` |
|
||||
| 格线 | max(0.6, 0.02s),`boardGrid`,约 1.14 : 1,只在旋转时对位 |
|
||||
| 路基 | `trackHalo`,宽 clamp(0.30s, 5, 18) |
|
||||
| 钢轨 | `track` #3A5068,宽 clamp(0.105s, 2.5, 7),圆头圆接;板边端点按路基宽内收,不外伸 |
|
||||
| 棋子 | 圆角六角,半径 0.90s,纯色面,描边 #2E4256 38%、宽 max(1.5, 0.05s) |
|
||||
| 箭头 | 白色七点形,尺度 0.66 × 棋子半径,十二色统一 |
|
||||
| 预览路线 | 画在棋子之上:光晕 1.05 × 路基宽 + 主线 1.5 × 钢轨宽;可出 #2F5FBF / #C9D7F3,被挡 #C4432F / #F3D3CB,末端小叉 |
|
||||
| 提示环 | 单环 #D9A227,半径 1.1s,宽 max(2.5, 0.08s) |
|
||||
|
||||
不使用棋子图集,不使用滤镜调色。全部造型由多边形、折线与圆组成。
|
||||
|
||||
## 五种主题
|
||||
|
||||
| 主题 ID | 阶段 | 名称 | 用色方向 |
|
||||
| --- | --- | --- | --- |
|
||||
| lagoon | 轻松 | 晨雾 | 蓝灰世界色,靛蓝、松石与琥珀领色 |
|
||||
| apricot | 进阶 | 杏仁 | 暖砂世界色,朱砂与靛蓝领色 |
|
||||
| lavender | 烧脑 | 苔原 | 灰绿世界色,紫藤与玫红提亮 |
|
||||
| rose | 挑战 | 暮砂 | 玫瑰灰世界色,玫红与靛蓝对照 |
|
||||
| midnight | 每周挑战 | 夜航 | 深蓝灰世界色,奶白卡片像被灯照亮的图 |
|
||||
|
||||
完整色值、边框与底板色、每主题 4/7/9/12 色有序 palette 见 tokens.json 与 [art-directions.js](../../../src/art-directions.js)。世界色压低明度,棋盘对世界色 1.50–1.62 : 1,边界靠边框与底板而不是色相差;场景文字对世界色 7 : 1 以上;十二色白箭头最低 4.48 : 1。
|
||||
|
||||
主游戏中本方案的主题按旅程切换:五个世界平均铺在整条主线上,最后一段为夜航;`?theme=` 参数仍可强制指定。
|
||||
|
||||
## 控件与边界
|
||||
|
||||
- 顶部选关、设置:底板只比世界色深一档(`--signpost-plate`),图标用场景文字色;图标通过遮罩着色,不用滤镜。
|
||||
- 旋转按钮:无底座,图标 64px,用世界色深一档着色,上 1px 暗、下 1px 亮形成压痕;标签 12px 同色系。位置由 [app.js](../../../src/app.js) 的 `placeRotation` 按棋盘几何计算:取下方斜边中点(棋盘轮廓宽 25% / 75%、高 87.5%),向下作垂线到道具上缘,按钮中心放在垂线中点。旋转不再占独立布局行,这是与 shared.md 的一处出入。
|
||||
- 撤销、重来、提示:沿用原版蓝、紫、金圆底与白边;标签用场景文字色。
|
||||
- 通知位置、棋盘居中、金色奖励继承 shared.md。
|
||||
|
||||
## 验收与接入
|
||||
|
||||
使用 `artDirection('signpost')` 和 `directionTheme(direction, themeId, colorCount)`;主游戏 `?design=signpost`。
|
||||
|
||||
- 检查五个世界的棋盘边框、底板与格线;夜航下棋盘保持奶白。
|
||||
- 检查 37 / 61 / 91 格下钢轨宽度上限与棋子描边,箭头在 19px 格半径可读。
|
||||
- 检查旋转按钮落点:斜边中点与道具上缘的中点;换关、旋转、窗口尺寸变化后位置稳定。
|
||||
- 检查提示路线画在棋子之上、被挡路线只到接触点。
|
||||
- 原生端需实现两次偏移绘制的压痕与白色精灵着色;尚未完成原生实机验收。
|
||||
File diff suppressed because one or more lines are too long
@@ -1,469 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generated": true,
|
||||
"generatedBy": "scripts/build-art-directions.mjs",
|
||||
"pathBase": "repository-root",
|
||||
"designId": "signpost",
|
||||
"artStyle": "signpost",
|
||||
"sources": {
|
||||
"directions": "src/art-directions.js",
|
||||
"baseTokens": "src/design-tokens.js",
|
||||
"renderer": "src/renderer.js",
|
||||
"tokenDrawing": "src/token-art.js",
|
||||
"componentStyles": "design/art-directions.css",
|
||||
"itemStyles": "design/game-tools.css"
|
||||
},
|
||||
"accent": "#2F5FBF",
|
||||
"documentBackground": "#F6F2E9",
|
||||
"sharedSemanticColors": {
|
||||
"background": "#A8BECF",
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5",
|
||||
"surface": "#F7F6F2",
|
||||
"textPrimary": "#273B50",
|
||||
"textSecondary": "#314A5F",
|
||||
"primary": "#6652B8",
|
||||
"onPrimary": "#FFFFFF",
|
||||
"secondary": "#E4EAF0",
|
||||
"utility": "#52697E",
|
||||
"onUtility": "#FFFFFF",
|
||||
"selection": "#DFD9F3",
|
||||
"onSelection": "#3F327A",
|
||||
"disabled": "#CBD4DD",
|
||||
"onDisabled": "#526579",
|
||||
"input": "#FFFFFF",
|
||||
"reward": "#B9760C",
|
||||
"warning": "#A44825",
|
||||
"warningSurface": "#F9E3D2",
|
||||
"scrim": "#273B507A",
|
||||
"focus": "#3F327A",
|
||||
"tileBlue": "#2392FD",
|
||||
"tilePink": "#FC3E80",
|
||||
"tileYellow": "#FDBC28",
|
||||
"tilePurple": "#874FFD",
|
||||
"arrowLight": "#FFFFFF",
|
||||
"arrowDark": "#273B50"
|
||||
},
|
||||
"assets": {
|
||||
"tileAtlas": null,
|
||||
"uiIconAtlas": "assets/ui-icons-generated.png"
|
||||
},
|
||||
"pigments": [
|
||||
{
|
||||
"index": 0,
|
||||
"name": "靛蓝",
|
||||
"color": "#2F5FBF",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"name": "朱砂",
|
||||
"color": "#C4432F",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"name": "松石",
|
||||
"color": "#1C8378",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"name": "紫藤",
|
||||
"color": "#7A4EB8",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"name": "苔绿",
|
||||
"color": "#4A8235",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"name": "琥珀",
|
||||
"color": "#A8690C",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"name": "玫红",
|
||||
"color": "#BF3A6B",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"name": "钢蓝",
|
||||
"color": "#4A6B8A",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 8,
|
||||
"name": "赤陶",
|
||||
"color": "#B0572F",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 9,
|
||||
"name": "墨绿",
|
||||
"color": "#357358",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 10,
|
||||
"name": "藕紫",
|
||||
"color": "#8A5C92",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 11,
|
||||
"name": "铁灰",
|
||||
"color": "#5A6D7C",
|
||||
"arrow": "#FFFFFF"
|
||||
}
|
||||
],
|
||||
"themes": [
|
||||
{
|
||||
"id": "lagoon",
|
||||
"label": "轻松",
|
||||
"name": "晨雾",
|
||||
"background": "#B7CBD3",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#F5F2EA",
|
||||
"boardGrid": "#E9E3D6",
|
||||
"track": "#3A5068",
|
||||
"trackHalo": "#E2DBCC"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
2,
|
||||
5,
|
||||
3,
|
||||
1,
|
||||
8,
|
||||
6
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
2,
|
||||
5,
|
||||
3
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
2,
|
||||
5,
|
||||
3,
|
||||
1,
|
||||
8,
|
||||
6
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
2,
|
||||
5,
|
||||
3,
|
||||
1,
|
||||
8,
|
||||
6,
|
||||
4,
|
||||
7
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
2,
|
||||
5,
|
||||
3,
|
||||
1,
|
||||
8,
|
||||
6,
|
||||
4,
|
||||
7,
|
||||
9,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 9.872709985958306,
|
||||
"trackOnBoard": 7.427567140854274
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "apricot",
|
||||
"label": "进阶",
|
||||
"name": "杏仁",
|
||||
"background": "#DBC4A6",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#F7F2E7",
|
||||
"boardGrid": "#EAE3D3",
|
||||
"track": "#3A5068",
|
||||
"trackHalo": "#E4DCCA"
|
||||
},
|
||||
"anchorPalette": [
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
6,
|
||||
3,
|
||||
9,
|
||||
7
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
6
|
||||
],
|
||||
"7": [
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
6,
|
||||
3,
|
||||
9,
|
||||
7
|
||||
],
|
||||
"9": [
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
6,
|
||||
3,
|
||||
9,
|
||||
7,
|
||||
4,
|
||||
5
|
||||
],
|
||||
"12": [
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
6,
|
||||
3,
|
||||
9,
|
||||
7,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 9.84281455268355,
|
||||
"trackOnBoard": 7.442657598835995
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lavender",
|
||||
"label": "烧脑",
|
||||
"name": "苔原",
|
||||
"background": "#BBCBB1",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#F5F3E9",
|
||||
"boardGrid": "#E8E4D6",
|
||||
"track": "#3A5068",
|
||||
"trackHalo": "#E1DCCC"
|
||||
},
|
||||
"anchorPalette": [
|
||||
3,
|
||||
6,
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
10,
|
||||
2
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
3,
|
||||
6,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"7": [
|
||||
3,
|
||||
6,
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
10,
|
||||
2
|
||||
],
|
||||
"9": [
|
||||
3,
|
||||
6,
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
10,
|
||||
2,
|
||||
5,
|
||||
7
|
||||
],
|
||||
"12": [
|
||||
3,
|
||||
6,
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
10,
|
||||
2,
|
||||
5,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 9.709754954665774,
|
||||
"trackOnBoard": 7.470269532165791
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rose",
|
||||
"label": "挑战",
|
||||
"name": "暮砂",
|
||||
"background": "#D7BAB5",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#F7F1EA",
|
||||
"boardGrid": "#EAE2D8",
|
||||
"track": "#3A5068",
|
||||
"trackHalo": "#E4DBCF"
|
||||
},
|
||||
"anchorPalette": [
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
5,
|
||||
2,
|
||||
11,
|
||||
8
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
5
|
||||
],
|
||||
"7": [
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
5,
|
||||
2,
|
||||
11,
|
||||
8
|
||||
],
|
||||
"9": [
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
5,
|
||||
2,
|
||||
11,
|
||||
8,
|
||||
1,
|
||||
4
|
||||
],
|
||||
"12": [
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
5,
|
||||
2,
|
||||
11,
|
||||
8,
|
||||
1,
|
||||
4,
|
||||
7,
|
||||
9,
|
||||
10
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 9.148840055226982,
|
||||
"trackOnBoard": 7.409208337359319
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "midnight",
|
||||
"label": "每周挑战",
|
||||
"name": "夜航",
|
||||
"background": "#1F2C3B",
|
||||
"ink": "#FFFFFF",
|
||||
"materials": {
|
||||
"board": "#F6F2E9",
|
||||
"boardGrid": "#E9E3D6",
|
||||
"track": "#3A5068",
|
||||
"trackHalo": "#E2DBCC"
|
||||
},
|
||||
"anchorPalette": [
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
3
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
6
|
||||
],
|
||||
"7": [
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
3
|
||||
],
|
||||
"9": [
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
3,
|
||||
4,
|
||||
7
|
||||
],
|
||||
"12": [
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
3,
|
||||
4,
|
||||
7,
|
||||
8,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 14.173029259487338,
|
||||
"trackOnBoard": 7.437303508154617
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=toy/index.html"><title>积木轨道屋 · 设计稿已迁移</title></head><body><p>设计稿已整理到独立目录:<a href="toy/index.html">03 · 积木轨道屋</a></p></body></html>
|
||||
@@ -1,5 +0,0 @@
|
||||
# 03 · 积木轨道屋
|
||||
|
||||
本文件为旧入口。完整、人工维护的 Agent 规范已迁移到 [toy/design.md](toy/design.md)。
|
||||
|
||||
[设计稿](toy/index.html) · [配色数据](toy/tokens.json) · [Agent 接入说明](../README.md)
|
||||
@@ -1,50 +0,0 @@
|
||||
# 03 · 积木轨道屋
|
||||
|
||||
设计 ID:`toy` · 渲染风格:`toy` · 英文名:LITTLE PLAYWORKS。玩具质感候选方案,可与其他方案同时保留。
|
||||
|
||||
[Agent 接入约定](../../shared.md) · [配色数据](tokens.json) · [完整设计稿](index.html) · [试玩与审核](../../../design-showcase.html?design=toy)
|
||||
|
||||
## 设计目标
|
||||
|
||||
圆润积木、红黄蓝绿塑胶零件与原木色轨道板。厚度来自少量同色分层,棋子看起来可以拿在手里;不把整套方案做成灰雾或原版柔紫色系。
|
||||
|
||||
## 棋盘与棋子怎么画
|
||||
|
||||
复用 [renderer.js](../../../src/renderer.js) 的非 paper 棋盘、[token-art.js](../../../src/token-art.js) 的 toy 分支。r = 格半径 s × 0.985;tint 在 RGB 通道上按比例向白或黑混合。
|
||||
|
||||
| 部件 | 当前实现 |
|
||||
| --- | --- |
|
||||
| 轨道 | 分格 max(1, s × 0.024),外缘 max(4, s × 0.16),中心线 max(2.5, s × 0.10) |
|
||||
| 下层厚度 | 半径 r × 0.94,向下偏移 r × 0.09,fill 暗化 30% |
|
||||
| 中间层 | 半径 r × 0.94,fill 暗化 8% |
|
||||
| 顶面 | 半径 r × 0.83,向上偏移 r × 0.06,原始 fill |
|
||||
| 边缘高光 | 半径 r × 0.75 的局部边线,fill 提亮 50%,线宽 r × 0.045 |
|
||||
| 中央压面 | 半径 r × 0.50 的圆,向上偏移 r × 0.04,fill 提亮 11% |
|
||||
| 箭头 | 实心七点箭头,尺度 r × 0.58,保持清楚独立的方向 |
|
||||
|
||||
这套不依赖棋子图集,也不是物理材质或三维光照;所有效果由共享多边形、线与圆组成。移动和碰撞仍复用同一分层画法。
|
||||
|
||||
## 五种主题
|
||||
|
||||
| 主题 ID | 阶段 | 名称 | 独立用色方向 |
|
||||
| --- | --- | --- | --- |
|
||||
| lagoon | 轻松 | 积木黄盒 | 暖黄玩具盒、奶油板面、原色积木 |
|
||||
| apricot | 进阶 | 蓝色装配台 | 亮蓝台面与原木色插板 |
|
||||
| lavender | 烧脑 | 橘红工坊 | 橘红环境、木糖底板、绿蓝零件 |
|
||||
| rose | 挑战 | 绿毯小城 | 绿垫与木色道路 |
|
||||
| midnight | 每周挑战 | 太空玩具柜 | 太空蓝柜体、浅灰塑胶板 |
|
||||
|
||||
完整色值及每主题 4/7/9/12 色搭配见 tokens.json,源为 [art-directions.js](../../../src/art-directions.js)。配色要保留原色塑胶与暖木关系。箭头按 4.5:1 门槛选白或 #172D39,不能给所有黄色积木统一加白箭头。
|
||||
|
||||
## 控件与边界
|
||||
|
||||
现有顶部控件保留玩具边缘和圆润感。底部道具单独使用 24px 圆角、蓝/红/黄底色与奶油色 3px 边框;**没有**棋子的厚度、投影或高光。不要因名称里有“玩具”就重新给底部道具加阴影。尺寸、位置和未来角标按 shared.md。
|
||||
|
||||
## 验收与接入
|
||||
|
||||
使用 `artDirection('toy')` 和 `directionTheme(direction, themeId, colorCount)`,不要用 CSS 滤镜把 calm 染成玩具配色。
|
||||
|
||||
- 缩小到手机尺寸后,分层仍清楚且不遮住箭头。
|
||||
- 蓝色和太空主题保持木色/浅灰板面,不能五套都用同一个奶油背景。
|
||||
- 静态、运动与撤销造型一致;底部道具保持平面。
|
||||
- 原生几何可复用绘制命令,原生控件和实机效果尚未验收。
|
||||
File diff suppressed because one or more lines are too long
@@ -1,469 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generated": true,
|
||||
"generatedBy": "scripts/build-art-directions.mjs",
|
||||
"pathBase": "repository-root",
|
||||
"designId": "toy",
|
||||
"artStyle": "toy",
|
||||
"sources": {
|
||||
"directions": "src/art-directions.js",
|
||||
"baseTokens": "src/design-tokens.js",
|
||||
"renderer": "src/renderer.js",
|
||||
"tokenDrawing": "src/token-art.js",
|
||||
"componentStyles": "design/art-directions.css",
|
||||
"itemStyles": "design/game-tools.css"
|
||||
},
|
||||
"accent": "#245EAF",
|
||||
"documentBackground": "#FFFAEE",
|
||||
"sharedSemanticColors": {
|
||||
"background": "#A8BECF",
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5",
|
||||
"surface": "#F7F6F2",
|
||||
"textPrimary": "#273B50",
|
||||
"textSecondary": "#314A5F",
|
||||
"primary": "#6652B8",
|
||||
"onPrimary": "#FFFFFF",
|
||||
"secondary": "#E4EAF0",
|
||||
"utility": "#52697E",
|
||||
"onUtility": "#FFFFFF",
|
||||
"selection": "#DFD9F3",
|
||||
"onSelection": "#3F327A",
|
||||
"disabled": "#CBD4DD",
|
||||
"onDisabled": "#526579",
|
||||
"input": "#FFFFFF",
|
||||
"reward": "#B9760C",
|
||||
"warning": "#A44825",
|
||||
"warningSurface": "#F9E3D2",
|
||||
"scrim": "#273B507A",
|
||||
"focus": "#3F327A",
|
||||
"tileBlue": "#2392FD",
|
||||
"tilePink": "#FC3E80",
|
||||
"tileYellow": "#FDBC28",
|
||||
"tilePurple": "#874FFD",
|
||||
"arrowLight": "#FFFFFF",
|
||||
"arrowDark": "#273B50"
|
||||
},
|
||||
"assets": {
|
||||
"tileAtlas": null,
|
||||
"uiIconAtlas": "assets/ui-icons-generated.png"
|
||||
},
|
||||
"pigments": [
|
||||
{
|
||||
"index": 0,
|
||||
"name": "积木红",
|
||||
"color": "#DF4033",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"name": "积木黄",
|
||||
"color": "#F2C52E",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"name": "积木蓝",
|
||||
"color": "#2478C5",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"name": "积木绿",
|
||||
"color": "#32945C",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"name": "零件橙",
|
||||
"color": "#EF862D",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"name": "拼装紫",
|
||||
"color": "#7652B2",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"name": "奶油白",
|
||||
"color": "#EFE4C4",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"name": "工具青",
|
||||
"color": "#227B87",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 8,
|
||||
"name": "砖红",
|
||||
"color": "#B63845",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 9,
|
||||
"name": "木棕",
|
||||
"color": "#745B40",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 10,
|
||||
"name": "玻璃蓝",
|
||||
"color": "#73BFDC",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 11,
|
||||
"name": "草绿",
|
||||
"color": "#A7BA56",
|
||||
"arrow": "#172D39"
|
||||
}
|
||||
],
|
||||
"themes": [
|
||||
{
|
||||
"id": "lagoon",
|
||||
"label": "轻松",
|
||||
"name": "积木黄盒",
|
||||
"background": "#F4C548",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FFF7DE",
|
||||
"boardGrid": "#B5A184",
|
||||
"track": "#765238",
|
||||
"trackHalo": "#FFF7DE"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
10
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
5
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
10
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
10,
|
||||
1,
|
||||
6
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
10,
|
||||
1,
|
||||
6,
|
||||
7,
|
||||
9,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 10.212613961554808,
|
||||
"trackOnBoard": 6.463066023255321
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "apricot",
|
||||
"label": "进阶",
|
||||
"name": "蓝色装配台",
|
||||
"background": "#56AFE0",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#F5DFB6",
|
||||
"boardGrid": "#B09C7C",
|
||||
"track": "#386A8D",
|
||||
"trackHalo": "#F5DFB6"
|
||||
},
|
||||
"anchorPalette": [
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
9,
|
||||
6,
|
||||
11
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
3
|
||||
],
|
||||
"7": [
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
9,
|
||||
6,
|
||||
11
|
||||
],
|
||||
"9": [
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
9,
|
||||
6,
|
||||
11,
|
||||
2,
|
||||
5
|
||||
],
|
||||
"12": [
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
9,
|
||||
6,
|
||||
11,
|
||||
2,
|
||||
5,
|
||||
7,
|
||||
8,
|
||||
10
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 6.797539779539623,
|
||||
"trackOnBoard": 4.458036518249096
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lavender",
|
||||
"label": "烧脑",
|
||||
"name": "橘红工坊",
|
||||
"background": "#EA743E",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FFEFCB",
|
||||
"boardGrid": "#BBA27B",
|
||||
"track": "#695037",
|
||||
"trackHalo": "#FFEFCB"
|
||||
},
|
||||
"anchorPalette": [
|
||||
2,
|
||||
3,
|
||||
1,
|
||||
7,
|
||||
10,
|
||||
5,
|
||||
8
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
2,
|
||||
3,
|
||||
1,
|
||||
7
|
||||
],
|
||||
"7": [
|
||||
2,
|
||||
3,
|
||||
1,
|
||||
7,
|
||||
10,
|
||||
5,
|
||||
8
|
||||
],
|
||||
"9": [
|
||||
2,
|
||||
3,
|
||||
1,
|
||||
7,
|
||||
10,
|
||||
5,
|
||||
8,
|
||||
0,
|
||||
4
|
||||
],
|
||||
"12": [
|
||||
2,
|
||||
3,
|
||||
1,
|
||||
7,
|
||||
10,
|
||||
5,
|
||||
8,
|
||||
0,
|
||||
4,
|
||||
6,
|
||||
9,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 5.582585700054348,
|
||||
"trackOnBoard": 6.585478734470914
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rose",
|
||||
"label": "挑战",
|
||||
"name": "绿毯小城",
|
||||
"background": "#439A73",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#F2D6A6",
|
||||
"boardGrid": "#AC987A",
|
||||
"track": "#476556",
|
||||
"trackHalo": "#F2D6A6"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
6,
|
||||
9,
|
||||
11
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
4
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
6,
|
||||
9,
|
||||
11
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
6,
|
||||
9,
|
||||
11,
|
||||
3,
|
||||
5
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
6,
|
||||
9,
|
||||
11,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
8,
|
||||
10
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 4.82593081470767,
|
||||
"trackOnBoard": 4.578974741098264
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "midnight",
|
||||
"label": "每周挑战",
|
||||
"name": "太空玩具柜",
|
||||
"background": "#244584",
|
||||
"ink": "#FFFFFF",
|
||||
"materials": {
|
||||
"board": "#D4E4E6",
|
||||
"boardGrid": "#8DA4B2",
|
||||
"track": "#35516F",
|
||||
"trackHalo": "#D4E4E6"
|
||||
},
|
||||
"anchorPalette": [
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
6,
|
||||
10,
|
||||
3,
|
||||
8
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
6
|
||||
],
|
||||
"7": [
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
6,
|
||||
10,
|
||||
3,
|
||||
8
|
||||
],
|
||||
"9": [
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
6,
|
||||
10,
|
||||
3,
|
||||
8,
|
||||
2,
|
||||
5
|
||||
],
|
||||
"12": [
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
6,
|
||||
10,
|
||||
3,
|
||||
8,
|
||||
2,
|
||||
5,
|
||||
7,
|
||||
9,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 9.29429328953417,
|
||||
"trackOnBoard": 6.2705655843638315
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=vivid/index.html"><title>高彩游乐场 · 设计稿已迁移</title></head><body><p>设计稿已整理到独立目录:<a href="vivid/index.html">02 · 高彩游乐场</a></p></body></html>
|
||||
@@ -1,5 +0,0 @@
|
||||
# 02 · 高彩游乐场
|
||||
|
||||
本文件为旧入口。完整、人工维护的 Agent 规范已迁移到 [vivid/design.md](vivid/design.md)。
|
||||
|
||||
[设计稿](vivid/index.html) · [配色数据](vivid/tokens.json) · [Agent 接入说明](../README.md)
|
||||
@@ -1,49 +0,0 @@
|
||||
# 02 · 高彩游乐场
|
||||
|
||||
设计 ID:`vivid` · 渲染风格:`vivid` · 英文名:CHROMA CLUB。高饱和候选方案,可与其他方案同时保留。
|
||||
|
||||
[Agent 接入约定](../../shared.md) · [配色数据](tokens.json) · [完整设计稿](index.html) · [试玩与审核](../../../design-showcase.html?design=vivid)
|
||||
|
||||
## 设计目标
|
||||
|
||||
鲜明撞色、深色轮廓与贴纸棋子,像可操作的彩色海报。用户明确要求五个主题都有高饱和感,不能只有轻松主题鲜艳,其余退回原版蓝紫粉背景。
|
||||
|
||||
## 棋盘与棋子怎么画
|
||||
|
||||
复用 [renderer.js](../../../src/renderer.js) 的非 paper 棋盘和 [token-art.js](../../../src/token-art.js) 的 vivid 分支。以格半径 s、棋子基准半径 r = s × 0.985 为单位。
|
||||
|
||||
| 部件 | 当前实现 |
|
||||
| --- | --- |
|
||||
| 分格/轨道 | 分格 max(1, s × 0.024),轨道外缘 max(4, s × 0.16),中心线 max(2.5, s × 0.10) |
|
||||
| 棋子正面 | 半径 r × 0.94 的圆角六边形,独立颜料色纯色填充 |
|
||||
| 硬边底层 | 同形向右 r × 0.04、向下 r × 0.07 偏移,颜色 #30264C |
|
||||
| 深色描边 | #30264C,线宽 r × 0.065 |
|
||||
| 白色短划 | 左上方短线,线宽 r × 0.055;用于贴纸感 |
|
||||
| 箭头 | 实心七点箭头,尺度 r × 0.58,颜色取本套 pigments.arrow |
|
||||
|
||||
棋子全部由多边形和线绘制,不使用 calm 的棋子 PNG。轨道几何与主玩法一致,颜色取该主题展开后的 materials,不能把装饰短线当作新路径。
|
||||
|
||||
## 五种主题
|
||||
|
||||
| 主题 ID | 阶段 | 名称 | 独立用色方向 |
|
||||
| --- | --- | --- | --- |
|
||||
| lagoon | 轻松 | 青柠派对 | 青柠大背景与奶油棋盘 |
|
||||
| apricot | 进阶 | 爆橙热浪 | 亮橙环境、明黄棋盘与冷色棋子 |
|
||||
| lavender | 烧脑 | 钴蓝电场 | 纯钴蓝环境、荧光青柠棋盘 |
|
||||
| rose | 挑战 | 荧粉冲刺 | 荧光粉舞台与明黄、蓝绿 |
|
||||
| midnight | 每周挑战 | 黑光嘉年华 | 深紫黑底、荧光绿轨道 |
|
||||
|
||||
完整色值和每个主题的 4/7/9/12 色有序 palette 见 tokens.json;源为 [art-directions.js](../../../src/art-directions.js)。12 色独立于原版。主题背景保留较高 HSL 饱和度;当前测试要求至少 0.65。箭头按 4.5:1 门槛在白与 #172D39 中选取。
|
||||
|
||||
## 控件与边界
|
||||
|
||||
顶部控件与通知沿用深轮廓和贴纸风格。底部道具服从共用的扁平要求:撤销电青、重来亮粉、提示明黄,3px 深色边线,不加棋子的偏移硬阴影。顶部风格不能覆盖 game-tools.css 的最后加载规则。
|
||||
|
||||
## 验收与接入
|
||||
|
||||
使用 `artDirection('vivid')` 和 `directionTheme(direction, themeId, colorCount)`;完整流程见 shared.md。
|
||||
|
||||
- 五主题都应与原版明显不同,保持高纯度用色,棋子与底盘容易分离。
|
||||
- 黑光主题检查浅色轨道和深色板面,其他主题检查深线与亮板面的关系。
|
||||
- 静态、移动、碰撞时都使用同一贴纸轮廓和箭头。
|
||||
- 底部道具无阴影;原生端尚未接入并实机验收此套风格。
|
||||
File diff suppressed because one or more lines are too long
@@ -1,469 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generated": true,
|
||||
"generatedBy": "scripts/build-art-directions.mjs",
|
||||
"pathBase": "repository-root",
|
||||
"designId": "vivid",
|
||||
"artStyle": "vivid",
|
||||
"sources": {
|
||||
"directions": "src/art-directions.js",
|
||||
"baseTokens": "src/design-tokens.js",
|
||||
"renderer": "src/renderer.js",
|
||||
"tokenDrawing": "src/token-art.js",
|
||||
"componentStyles": "design/art-directions.css",
|
||||
"itemStyles": "design/game-tools.css"
|
||||
},
|
||||
"accent": "#4A24E8",
|
||||
"documentBackground": "#FFFCF0",
|
||||
"sharedSemanticColors": {
|
||||
"background": "#A8BECF",
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5",
|
||||
"surface": "#F7F6F2",
|
||||
"textPrimary": "#273B50",
|
||||
"textSecondary": "#314A5F",
|
||||
"primary": "#6652B8",
|
||||
"onPrimary": "#FFFFFF",
|
||||
"secondary": "#E4EAF0",
|
||||
"utility": "#52697E",
|
||||
"onUtility": "#FFFFFF",
|
||||
"selection": "#DFD9F3",
|
||||
"onSelection": "#3F327A",
|
||||
"disabled": "#CBD4DD",
|
||||
"onDisabled": "#526579",
|
||||
"input": "#FFFFFF",
|
||||
"reward": "#B9760C",
|
||||
"warning": "#A44825",
|
||||
"warningSurface": "#F9E3D2",
|
||||
"scrim": "#273B507A",
|
||||
"focus": "#3F327A",
|
||||
"tileBlue": "#2392FD",
|
||||
"tilePink": "#FC3E80",
|
||||
"tileYellow": "#FDBC28",
|
||||
"tilePurple": "#874FFD",
|
||||
"arrowLight": "#FFFFFF",
|
||||
"arrowDark": "#273B50"
|
||||
},
|
||||
"assets": {
|
||||
"tileAtlas": null,
|
||||
"uiIconAtlas": "assets/ui-icons-generated.png"
|
||||
},
|
||||
"pigments": [
|
||||
{
|
||||
"index": 0,
|
||||
"name": "电蓝",
|
||||
"color": "#2455E8",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"name": "热粉",
|
||||
"color": "#E52879",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"name": "柠檬黄",
|
||||
"color": "#FFE13E",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"name": "电紫",
|
||||
"color": "#7136D8",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"name": "深青",
|
||||
"color": "#007C70",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"name": "火橙",
|
||||
"color": "#FF622C",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"name": "荧光绿",
|
||||
"color": "#BBE929",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"name": "钴蓝",
|
||||
"color": "#074DFF",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"index": 8,
|
||||
"name": "警示红",
|
||||
"color": "#EB174E",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 9,
|
||||
"name": "亮橘",
|
||||
"color": "#FF9500",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 10,
|
||||
"name": "电光青",
|
||||
"color": "#08E8E1",
|
||||
"arrow": "#172D39"
|
||||
},
|
||||
{
|
||||
"index": 11,
|
||||
"name": "激光紫",
|
||||
"color": "#A92BFF",
|
||||
"arrow": "#FFFFFF"
|
||||
}
|
||||
],
|
||||
"themes": [
|
||||
{
|
||||
"id": "lagoon",
|
||||
"label": "轻松",
|
||||
"name": "青柠派对",
|
||||
"background": "#B8F34A",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FFFBE7",
|
||||
"boardGrid": "#AB9C82",
|
||||
"track": "#30264C",
|
||||
"trackHalo": "#FFFBE7"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
6
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
6
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 12.60682592893418,
|
||||
"trackOnBoard": 13.40477966198369
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "apricot",
|
||||
"label": "进阶",
|
||||
"name": "爆橙热浪",
|
||||
"background": "#FF771B",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FFEF45",
|
||||
"boardGrid": "#B78335",
|
||||
"track": "#462654",
|
||||
"trackHalo": "#FFEF45"
|
||||
},
|
||||
"anchorPalette": [
|
||||
7,
|
||||
3,
|
||||
10,
|
||||
8,
|
||||
2,
|
||||
0,
|
||||
11
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
7,
|
||||
3,
|
||||
10,
|
||||
8
|
||||
],
|
||||
"7": [
|
||||
7,
|
||||
3,
|
||||
10,
|
||||
8,
|
||||
2,
|
||||
0,
|
||||
11
|
||||
],
|
||||
"9": [
|
||||
7,
|
||||
3,
|
||||
10,
|
||||
8,
|
||||
2,
|
||||
0,
|
||||
11,
|
||||
1,
|
||||
4
|
||||
],
|
||||
"12": [
|
||||
7,
|
||||
3,
|
||||
10,
|
||||
8,
|
||||
2,
|
||||
0,
|
||||
11,
|
||||
1,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
9
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 6.246500288112486,
|
||||
"trackOnBoard": 10.616992375930863
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lavender",
|
||||
"label": "烧脑",
|
||||
"name": "钴蓝电场",
|
||||
"background": "#3E42EE",
|
||||
"ink": "#FFFFFF",
|
||||
"materials": {
|
||||
"board": "#C9F849",
|
||||
"boardGrid": "#789344",
|
||||
"track": "#252269",
|
||||
"trackHalo": "#C9F849"
|
||||
},
|
||||
"anchorPalette": [
|
||||
2,
|
||||
9,
|
||||
1,
|
||||
10,
|
||||
6,
|
||||
5,
|
||||
8
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
2,
|
||||
9,
|
||||
1,
|
||||
10
|
||||
],
|
||||
"7": [
|
||||
2,
|
||||
9,
|
||||
1,
|
||||
10,
|
||||
6,
|
||||
5,
|
||||
8
|
||||
],
|
||||
"9": [
|
||||
2,
|
||||
9,
|
||||
1,
|
||||
10,
|
||||
6,
|
||||
5,
|
||||
8,
|
||||
0,
|
||||
3
|
||||
],
|
||||
"12": [
|
||||
2,
|
||||
9,
|
||||
1,
|
||||
10,
|
||||
6,
|
||||
5,
|
||||
8,
|
||||
0,
|
||||
3,
|
||||
4,
|
||||
7,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 6.524329011511401,
|
||||
"trackOnBoard": 11.251830170037788
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rose",
|
||||
"label": "挑战",
|
||||
"name": "荧粉冲刺",
|
||||
"background": "#FF3588",
|
||||
"ink": "#12202A",
|
||||
"materials": {
|
||||
"board": "#FFF4CE",
|
||||
"boardGrid": "#C491A1",
|
||||
"track": "#502369",
|
||||
"trackHalo": "#FFF4CE"
|
||||
},
|
||||
"anchorPalette": [
|
||||
0,
|
||||
6,
|
||||
10,
|
||||
2,
|
||||
7,
|
||||
4,
|
||||
9
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
0,
|
||||
6,
|
||||
10,
|
||||
2
|
||||
],
|
||||
"7": [
|
||||
0,
|
||||
6,
|
||||
10,
|
||||
2,
|
||||
7,
|
||||
4,
|
||||
9
|
||||
],
|
||||
"9": [
|
||||
0,
|
||||
6,
|
||||
10,
|
||||
2,
|
||||
7,
|
||||
4,
|
||||
9,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"12": [
|
||||
0,
|
||||
6,
|
||||
10,
|
||||
2,
|
||||
7,
|
||||
4,
|
||||
9,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
8,
|
||||
11
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 4.83248512643413,
|
||||
"trackOnBoard": 10.688104062178175
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "midnight",
|
||||
"label": "每周挑战",
|
||||
"name": "黑光嘉年华",
|
||||
"background": "#1B104D",
|
||||
"ink": "#FFFFFF",
|
||||
"materials": {
|
||||
"board": "#35225D",
|
||||
"boardGrid": "#837B9F",
|
||||
"track": "#D9FF55",
|
||||
"trackHalo": "#35225D"
|
||||
},
|
||||
"anchorPalette": [
|
||||
10,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
11,
|
||||
5
|
||||
],
|
||||
"palettes": {
|
||||
"4": [
|
||||
10,
|
||||
2,
|
||||
6,
|
||||
1
|
||||
],
|
||||
"7": [
|
||||
10,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
11,
|
||||
5
|
||||
],
|
||||
"9": [
|
||||
10,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
11,
|
||||
5,
|
||||
0,
|
||||
3
|
||||
],
|
||||
"12": [
|
||||
10,
|
||||
2,
|
||||
6,
|
||||
1,
|
||||
9,
|
||||
11,
|
||||
5,
|
||||
0,
|
||||
3,
|
||||
4,
|
||||
7,
|
||||
8
|
||||
]
|
||||
},
|
||||
"contrast": {
|
||||
"sceneText": 17.102604907549345,
|
||||
"trackOnBoard": 11.952226494271752
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Run from the repository root: node design/examples/render-design.mjs paper lagoon 7
|
||||
// This engine-independent example records geometry; it does not validate PNG pixels or UI.
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { ART_DIRECTIONS, directionTheme } from '../../src/art-directions.js';
|
||||
import { drawScene } from '../../src/renderer.js';
|
||||
import { layout } from '../../src/geometry.js';
|
||||
import { createStudyLevel } from '../../src/study-levels.js';
|
||||
|
||||
const level = createStudyLevel(3);
|
||||
|
||||
export function recordDesign(designId = 'paper', themeId = 'lagoon', colorCount = 7) {
|
||||
const direction = ART_DIRECTIONS.find(d => d.id === designId);
|
||||
if (!direction) throw new Error(`Unknown design: ${designId}`);
|
||||
if (!direction.themes.some(t => t.id === themeId)) throw new Error(`Unknown theme: ${themeId}`);
|
||||
if (![4, 7, 9, 12].includes(colorCount)) throw new Error(`Unsupported color count: ${colorCount}`);
|
||||
const theme = directionTheme(direction, themeId, colorCount), commands = [];
|
||||
const painter = {
|
||||
polygon: (points, fill) => commands.push({ type: 'polygon', points, fill }),
|
||||
line: (points, color, width) => commands.push({ type: 'line', points, color, width }),
|
||||
circle: (x, y, radius, fill) => commands.push({ type: 'circle', x, y, radius, fill }),
|
||||
};
|
||||
drawScene(painter, level, level.tiles, layout(level.cells, 600, 600), { theme });
|
||||
return { designId, themeId, colorCount, background: theme.background, palette: theme.palette, cellCount: level.cells.length, commands };
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||
const [designId = 'paper', themeId = 'lagoon', count = '7'] = process.argv.slice(2);
|
||||
const { commands, ...summary } = recordDesign(designId, themeId, Number(count));
|
||||
console.log(JSON.stringify({ ...summary, commandCount: commands.length }, null, 2));
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
/* Flat gameplay items: solid fills, no shadows, bevels or highlights. */
|
||||
.game-tool{--item-color:#7198D0;--item-edge:#FFFFFFB8;--item-radius:50%;--item-border:2px solid var(--item-edge);--item-size:64px}
|
||||
.game-tool[data-tool=restart]{--item-color:#A28ACC;}
|
||||
.game-tool[data-tool=hint]{--item-color:#EABB55;}
|
||||
:is(.phone .phone-tools,body:not(.editing) .board-tools,.item-samples,.guide-tools) .game-tool{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-width:80px;min-height:96px;margin:0;padding:4px 0;background:none;color:inherit;border:0;box-shadow:none;border-radius:18px;line-height:1.2}
|
||||
:is(.phone .phone-tools,body:not(.editing) .board-tools,.item-samples,.guide-tools) .game-tool>.item-face{position:relative;isolation:isolate;display:grid;place-items:center;width:var(--item-size);height:var(--item-size);padding:16px;flex:none;border:0;border-radius:var(--item-radius);background:none;filter:none;overflow:visible}
|
||||
.game-tool .item-face::before{content:'';position:absolute;inset:0;z-index:-1;border-radius:inherit;border:var(--item-border);background:var(--item-color);box-shadow:none}
|
||||
.game-tool .item-face>.ui-plate{display:none!important}
|
||||
body:not(.editing) .game-tool .item-face>.ui-icon,.game-tool .item-face>.icon{width:32px;height:32px;margin:0;filter:var(--item-icon-filter,none)}
|
||||
.game-tool[data-tool=hint]{--item-icon-filter:brightness(0) saturate(100%) invert(25%) sepia(20%) saturate(1391%) hue-rotate(357deg) brightness(93%) contrast(90%)}
|
||||
:is(.phone .phone-tools,body:not(.editing) .board-tools,.item-samples,.guide-tools) .game-tool>b{font-size:13px;font-weight:650;letter-spacing:.04em;line-height:1.3}
|
||||
:is(.phone .phone-tools,body:not(.editing) .board-tools) .game-tool:disabled{opacity:.5;cursor:default}
|
||||
.game-tool .item-face>.item-glyph{width:32px;height:32px}.game-tool .item-face>.art-icon{filter:var(--item-icon-filter,none)}
|
||||
|
||||
body[data-design=vivid] .game-tool{--item-color:#00BEEA;--item-border:3px solid #30264C;--item-radius:50%}
|
||||
body[data-design=vivid] .game-tool[data-tool=restart]{--item-color:#F62A83;}
|
||||
body[data-design=vivid] .game-tool[data-tool=hint]{--item-color:#FFCE19;}
|
||||
body[data-design=toy] .game-tool{--item-color:#187DCE;--item-border:3px solid #FFF5D9;--item-radius:24px}
|
||||
body[data-design=toy] .game-tool[data-tool=restart]{--item-color:#E8523D;}
|
||||
body[data-design=toy] .game-tool[data-tool=hint]{--item-color:#F5C637;}
|
||||
body[data-design=animals] .game-tool{--item-color:#79945B;--item-border:3px solid #FFF9DE;--item-radius:44% 44% 36% 36%}
|
||||
body[data-design=animals] .game-tool[data-tool=restart]{--item-color:#C1804C;}
|
||||
body[data-design=animals] .game-tool[data-tool=hint]{--item-color:#D4B647;}
|
||||
body[data-design=animals] .game-tool .item-face::after{content:'';position:absolute;top:7px;left:17px;right:17px;height:4px;border-radius:50%;border-top:2px dotted #FFFFFF95;pointer-events:none}
|
||||
|
||||
/* Reserve real rows for rotations and items so the canvas is truly centered
|
||||
between the notification area and controls, including on short screens. */
|
||||
body:not(.editing) .game-card{grid-template-rows:minmax(0,1fr) 76px 108px}
|
||||
body:not(.editing) .rotation-controls{position:static;grid-row:2;grid-column:1/-1;display:flex;align-items:center;justify-content:space-around;padding:0 20px;gap:32px;pointer-events:auto}
|
||||
body:not(.editing) .rotation-controls .rotate-button{min-height:68px;padding:0;gap:4px}
|
||||
body:not(.editing) .rotate-button>.ui-icon{width:48px;height:48px}
|
||||
body:not(.editing) .board-tools>.game-tool{grid-row:3;justify-self:center;width:100%}
|
||||
.phone{grid-template-rows:44px 40px 64px minmax(0,1fr) 76px 108px}
|
||||
.phone .rotations{position:static;grid-row:5;grid-column:1/-1;display:flex;align-items:center;justify-content:space-around;margin:0;padding:0 12px;gap:32px;pointer-events:auto}
|
||||
.phone .rotations button{min-height:68px;padding:0;gap:4px}
|
||||
.phone .rotations button>span{width:48px;height:48px}
|
||||
.phone .phone-tools>.game-tool{grid-row:6;justify-self:center;width:100%}
|
||||
@media(min-width:600px){.game-tool{--item-size:68px}body:not(.editing) .game-card{grid-template-rows:minmax(0,1fr) 80px 116px}.phone{grid-template-rows:44px 40px 64px minmax(0,1fr) 80px 116px}}
|
||||
@media(max-height:600px){
|
||||
.phone .game-tool,body:not(.editing) .game-tool{--item-size:56px}
|
||||
body:not(.editing) .game-card{grid-template-rows:minmax(0,1fr) 62px 88px}
|
||||
.phone{grid-template-rows:44px 40px 64px minmax(0,1fr) 62px 88px}
|
||||
body:not(.editing) .rotation-controls .rotate-button,.phone .rotations button{min-height:58px}
|
||||
body:not(.editing) .rotate-button>.ui-icon,.phone .rotations button>span{width:40px;height:40px}
|
||||
:is(.phone .phone-tools,body:not(.editing) .board-tools) .game-tool{min-height:84px;gap:10px}
|
||||
:is(.phone .phone-tools,body:not(.editing) .board-tools) .game-tool>.item-face{padding:12px}
|
||||
}
|
||||
|
||||
/* Future inventory examples are documentation only; gameplay has no badges. */
|
||||
.item-samples,.guide-tools{display:flex;justify-content:space-evenly;align-items:center;gap:16px;padding:16px 0 10px;text-align:center;color:var(--scene-ink,var(--ink,#273B50))}
|
||||
.item-badge{position:absolute;right:-7px;top:-5px;z-index:2;display:grid;place-items:center;min-width:27px;height:27px;padding:0 7px;border:2px solid #FFFCF5;border-radius:14px;background:#334B60;color:white;font:750 12px/1 system-ui,sans-serif;box-shadow:none}
|
||||
.item-badge.ad{right:-12px;min-width:42px;background:#5C478C;gap:3px;display:flex;align-items:center;justify-content:center;font-size:10px}
|
||||
.item-badge.ad::before{content:'▶';font-size:8px}
|
||||
.item-future{margin-top:28px;border-top:1px solid #273B5020;padding-top:24px}
|
||||
.item-future h3{font-size:18px;margin:8px 0}.item-future p{font-size:12px;color:#56687A}
|
||||
.item-future .item-samples{border-radius:20px;background:#E9EDE5;padding:22px 8px 16px;color:#273B50}
|
||||
.item-spec{font-size:12px;line-height:1.9;color:#56687A}
|
||||
.item-study{padding:44px 0;border-bottom:1px solid #273B5020;scroll-margin-top:80px}
|
||||
.item-study-content{max-width:640px;margin:auto}.item-study-content>.item-samples{background:var(--scene-bg,#E9EDE5);border-radius:24px;padding:24px 12px 18px}
|
||||
@media(max-width:380px){.item-samples,.guide-tools{gap:4px}.component-preview{padding:16px}.game-tool{min-width:72px}}
|
||||
|
||||
/* 06 路标 (signpost): controls recede into the paper; rotation hangs under the board. Values: design/directions/signpost/design.md */
|
||||
body[data-design=signpost]{--signpost-rotate:#8AA1AD;--signpost-label:#5C7280;--signpost-plate:#9AAEB9;--signpost-plate-ink:#22354A;--signpost-hi:rgba(255,255,255,.6);--signpost-lo:rgba(34,53,74,.28)}
|
||||
body[data-design=signpost][data-theme=apricot]{--signpost-rotate:#A79378;--signpost-label:#6B5A44;--signpost-plate:#BFA98A}
|
||||
body[data-design=signpost][data-theme=lavender]{--signpost-rotate:#8E9F86;--signpost-label:#56664F;--signpost-plate:#A2B398}
|
||||
body[data-design=signpost][data-theme=rose]{--signpost-rotate:#A58C89;--signpost-label:#6A5453;--signpost-plate:#BC9F9B}
|
||||
body[data-design=signpost][data-theme=midnight]{--signpost-rotate:#4E6376;--signpost-label:#8FA3B4;--signpost-plate:#33465A;--signpost-plate-ink:#DCE5EE;--signpost-hi:rgba(255,255,255,.14);--signpost-lo:rgba(0,0,0,.55)}
|
||||
/* White atlas icons are tinted through a mask (the CSS form of tinting a white sprite); mask geometry derives from ICONS in src/ui-skin.js. Shared by 06 signpost and 07 macaron. */
|
||||
body:is([data-design=signpost],[data-design=macaron]) :is(.rotate-button>.ui-icon,.game-icon>.ui-icon,.rotations button>[data-icon],.icon-button[data-icon])>.sprite-crop{-webkit-mask:url(../assets/ui-icons-generated.png) no-repeat;mask:url(../assets/ui-icons-generated.png) no-repeat;background:currentColor}
|
||||
body:is([data-design=signpost],[data-design=macaron]) :is(.rotate-button>.ui-icon,.game-icon>.ui-icon,.rotations button>[data-icon],.icon-button[data-icon])>.sprite-crop>img{visibility:hidden}
|
||||
body:is([data-design=signpost],[data-design=macaron]) :is(.rotate-button>.ui-icon,.game-icon>.ui-icon,.rotations button>[data-icon],.icon-button[data-icon])[data-icon=left]>.sprite-crop{-webkit-mask-size:540.517% 540.517%;mask-size:540.517% 540.517%;-webkit-mask-position:4.207% 36.008%;mask-position:4.207% 36.008%}
|
||||
body:is([data-design=signpost],[data-design=macaron]) :is(.rotate-button>.ui-icon,.game-icon>.ui-icon,.rotations button>[data-icon],.icon-button[data-icon])[data-icon=right]>.sprite-crop{-webkit-mask-size:552.423% 552.423%;mask-size:552.423% 552.423%;-webkit-mask-position:36.125% 37.196%;mask-position:36.125% 37.196%}
|
||||
body:is([data-design=signpost],[data-design=macaron]) :is(.rotate-button>.ui-icon,.game-icon>.ui-icon,.rotations button>[data-icon],.icon-button[data-icon])[data-icon=grid]>.sprite-crop{-webkit-mask-size:620.792% 620.792%;mask-size:620.792% 620.792%;-webkit-mask-position:35.361% 8.270%;mask-position:35.361% 8.270%}
|
||||
body:is([data-design=signpost],[data-design=macaron]) :is(.rotate-button>.ui-icon,.game-icon>.ui-icon,.rotations button>[data-icon],.icon-button[data-icon])[data-icon=gear]>.sprite-crop{-webkit-mask-size:547.598% 547.598%;mask-size:547.598% 547.598%;-webkit-mask-position:5.659% 6.829%;mask-position:5.659% 6.829%}
|
||||
body:is([data-design=signpost],[data-design=macaron]) :is(.rotate-button>.ui-icon,.game-icon>.ui-icon,.rotations button>[data-icon],.icon-button[data-icon])[data-icon=close]>.sprite-crop{-webkit-mask-size:646.392% 646.392%;mask-size:646.392% 646.392%;-webkit-mask-position:94.245% 8.679%;mask-position:94.245% 8.679%}
|
||||
body[data-design=signpost] .rotations button>[data-icon],body[data-design=signpost]:not(.editing) .rotate-button>.ui-icon{color:var(--signpost-rotate);filter:drop-shadow(0 1px 0 var(--signpost-hi)) drop-shadow(0 -1px 0 var(--signpost-lo))}
|
||||
body[data-design=signpost]:not(.editing) .rotate-button b{color:var(--signpost-label)}
|
||||
body[data-design=signpost]:not(.editing) .game-icon>.ui-icon{color:var(--signpost-plate-ink)}
|
||||
body[data-design=signpost] .icon-button[data-icon]{color:var(--signpost-plate-ink);background:var(--signpost-plate);border:0;box-shadow:none;border-radius:12px}
|
||||
body[data-design=signpost]:not(.editing) .game-icon>.ui-plate{background:var(--signpost-plate);border-radius:12px}
|
||||
body[data-design=signpost]:not(.editing) .game-icon>.ui-plate .sprite-crop{display:none}
|
||||
body[data-design=signpost]:not(.editing) .game-tool>b{color:var(--scene-ink,#273B50)}
|
||||
/* Rotation belongs to the board: app.js sets --rot-x / --rot-x2 / --rot-y from the board geometry. */
|
||||
body[data-design=signpost]:not(.editing) .game-card{grid-template-rows:minmax(0,1fr) 108px}
|
||||
body[data-design=signpost]:not(.editing) .board-tools>.game-tool{grid-row:2}
|
||||
body[data-design=signpost]:not(.editing) .rotation-controls{position:absolute;inset:0;grid-row:1/-1;grid-column:1/-1;display:block;padding:0;margin:0;pointer-events:none;z-index:3}
|
||||
body[data-design=signpost]:not(.editing) .rotate-button{position:absolute;left:var(--rot-x,25%);top:var(--rot-y,82%);margin:-41px 0 0 -42px;width:84px;min-width:0;min-height:0;padding:0;gap:2px;display:flex;flex-direction:column;align-items:center;pointer-events:auto}
|
||||
body[data-design=signpost]:not(.editing) #rotate-right{left:var(--rot-x2,75%)}
|
||||
body[data-design=signpost]:not(.editing) .rotate-button>.ui-icon{width:64px;height:64px}
|
||||
body[data-design=signpost]:not(.editing) .rotate-button b{font-size:12px;letter-spacing:0}
|
||||
|
||||
/* 07 马卡龙 (macaron): cream world, white objects with soft elevation, mauve ink, one orange action. Values: design/directions/macaron/design.md */
|
||||
/* Resource Han Rounded (SIL OFL), subset to the game's own characters; see assets/fonts/README.md. */
|
||||
@font-face{font-family:'Resource Han Rounded';font-weight:500;font-display:swap;src:url(../assets/fonts/ResourceHanRoundedCN-Medium.subset.woff2) format('woff2')}
|
||||
@font-face{font-family:'Resource Han Rounded';font-weight:700;font-display:swap;src:url(../assets/fonts/ResourceHanRoundedCN-Bold.subset.woff2) format('woff2')}
|
||||
body[data-design=macaron]{--mac-ink:#7A5560;--mac-ink-strong:#5A3A44;--mac-muted:#A98590;--mac-rotate:#B4939C;--mac-card:#FFFFFF;--mac-elev:0 4px 14px rgba(110,70,82,.14);--mac-cta:#E07416;--mac-cta-edge:#B95C0C;--mac-scrim:rgba(62,46,53,.5);font-family:'Resource Han Rounded',ui-rounded,'Arial Rounded MT Bold','Nunito','PingFang SC','Microsoft YaHei',sans-serif}
|
||||
body[data-design=macaron][data-theme=apricot]{--mac-ink:#7C4E52;--mac-rotate:#BC9A97}
|
||||
body[data-design=macaron][data-theme=lavender]{--mac-ink:#5F4E78;--mac-rotate:#A79BC0}
|
||||
body[data-design=macaron][data-theme=rose]{--mac-ink:#7B4658;--mac-rotate:#BE9AA6}
|
||||
body[data-design=macaron][data-theme=midnight]{--mac-ink:#FBEFE6;--mac-ink-strong:#FBEFE6;--mac-muted:#C4A9B0;--mac-rotate:#9E8189;--mac-elev:0 6px 18px rgba(0,0,0,.35);--mac-scrim:rgba(20,12,16,.62)}
|
||||
/* Top row: two white discs at the sides, two stat columns (关卡 / 待解) in the middle, the notice bubble on the row below. */
|
||||
body[data-design=macaron]:not(.editing) .game-column{grid-template-rows:64px 64px minmax(0,1fr);grid-template-columns:1fr 1fr;column-gap:40px}
|
||||
body[data-design=macaron]:not(.editing) .level-heading{grid-row:1;grid-column:1;justify-self:end;align-self:center;margin:0;padding:0}
|
||||
body[data-design=macaron]:not(.editing) .hud{grid-row:1;grid-column:2;justify-self:start;align-self:center;margin:0;padding:0}
|
||||
body[data-design=macaron]:not(.editing) .notice-slot{grid-row:2;grid-column:1/-1}
|
||||
body[data-design=macaron]:not(.editing) .game-card{grid-row:3;grid-column:1/-1}
|
||||
body[data-design=macaron]:not(.editing) .level-ribbon{display:flex;flex-direction:column;align-items:center;gap:3px;font-size:26px;line-height:1;letter-spacing:0;color:var(--mac-ink-strong)}
|
||||
body[data-design=macaron]:not(.editing) .level-ribbon small{font-size:12px;font-weight:600;letter-spacing:.04em;color:var(--mac-muted)}
|
||||
body[data-design=macaron]:not(.editing) .level-ribbon b{font-weight:800}
|
||||
body[data-design=macaron]:not(.editing) .level-ribbon b i{font-style:normal;font-size:14px;font-weight:600;color:var(--mac-muted)}
|
||||
body[data-design=macaron]:not(.editing) .moves-bubble{background:none;box-shadow:none;padding:0;height:auto;flex-direction:column;align-items:center;gap:3px;min-width:0;width:auto;transform-origin:center}
|
||||
body[data-design=macaron]:not(.editing) .moves-bubble>span{font-size:12px;font-weight:600;letter-spacing:.04em;color:var(--mac-muted);margin:0}
|
||||
body[data-design=macaron]:not(.editing) .moves-bubble strong{font-size:26px;line-height:1;font-weight:800;color:var(--mac-ink-strong)}
|
||||
body[data-design=macaron] .moves-bubble.pop{animation:mac-pill-pop .42s cubic-bezier(.34,1.56,.64,1)}
|
||||
@keyframes mac-pill-pop{0%{transform:scale(1)}35%{transform:scale(1.18)}100%{transform:scale(1)}}
|
||||
body[data-design=macaron]:not(.editing) .game-icon>.ui-plate{background:var(--mac-card);border-radius:50%;box-shadow:var(--mac-elev)}
|
||||
body[data-design=macaron]:not(.editing) .game-icon>.ui-plate .sprite-crop{display:none}
|
||||
body[data-design=macaron]:not(.editing) .game-icon>.ui-icon{color:#5A3A44}
|
||||
body[data-design=macaron] .icon-button[data-icon]{color:#5A3A44;background:var(--mac-card);border:0;box-shadow:var(--mac-elev);border-radius:50%}
|
||||
/* Notices are white speech bubbles with a tail towards the stats and an orange dot instead of the "i" badge. */
|
||||
body[data-design=macaron] .game-notice{position:relative;background:var(--mac-card);color:#5A3A44;border:0;border-radius:16px;box-shadow:var(--mac-elev);font-weight:600}
|
||||
body[data-design=macaron] .game-notice::before{content:'';flex:0 0 8px;width:8px;height:8px;border-radius:50%;background:var(--mac-cta)}
|
||||
body[data-design=macaron] .game-notice::after{content:'';position:absolute;left:50%;top:-6px;margin-left:-6px;border:6px solid transparent;border-top:0;border-bottom:6px solid var(--mac-card)}
|
||||
/* Rotation hangs under the tray like 06; plain ink-tinted sprites, no plate. */
|
||||
body[data-design=macaron] .rotations button>[data-icon],body[data-design=macaron]:not(.editing) .rotate-button>.ui-icon{color:var(--mac-rotate)}
|
||||
body[data-design=macaron]:not(.editing) .rotate-button b{color:var(--mac-ink)}
|
||||
/* The canvas bleeds 8px into the shell padding on each side, so the exit dissolve has room without shrinking the board. */
|
||||
body[data-design=macaron]:not(.editing) .canvas-wrap{margin-inline:-8px;width:calc(100% + 16px)}
|
||||
body[data-design=macaron]:not(.editing) .game-card{grid-template-rows:minmax(0,1fr) 108px}
|
||||
body[data-design=macaron]:not(.editing) .board-tools>.game-tool{grid-row:2}
|
||||
body[data-design=macaron]:not(.editing) .rotation-controls{position:absolute;inset:0;grid-row:1/-1;grid-column:1/-1;display:block;padding:0;margin:0;pointer-events:none;z-index:3}
|
||||
body[data-design=macaron]:not(.editing) .rotate-button{position:absolute;left:var(--rot-x,25%);top:var(--rot-y,82%);margin:-41px 0 0 -42px;width:84px;min-width:0;min-height:0;padding:0;gap:2px;display:flex;flex-direction:column;align-items:center;pointer-events:auto}
|
||||
body[data-design=macaron]:not(.editing) #rotate-right{left:var(--rot-x2,75%)}
|
||||
body[data-design=macaron]:not(.editing) .rotate-button>.ui-icon{width:60px;height:60px}
|
||||
body[data-design=macaron]:not(.editing) .rotate-button b{font-size:12px;letter-spacing:0}
|
||||
/* Tools are the reference's white discs: soft elevation, a candy-coloured glyph tinted through the atlas mask, mauve labels. */
|
||||
body[data-design=macaron] .game-tool{--item-color:var(--mac-card);--item-border:0;--item-radius:50%;--item-icon-filter:none}
|
||||
body[data-design=macaron] .game-tool .item-face::before{box-shadow:var(--mac-elev)}
|
||||
body[data-design=macaron] .game-tool .item-face{color:#4A91D4}
|
||||
body[data-design=macaron] .game-tool[data-tool=restart] .item-face{color:#D06E93}
|
||||
body[data-design=macaron] .game-tool[data-tool=hint] .item-face{color:#C98A0E}
|
||||
body[data-design=macaron] .game-tool .item-face :is(.ui-icon>.sprite-crop,.art-icon){-webkit-mask:url(../assets/ui-icons-generated.png) no-repeat;mask:url(../assets/ui-icons-generated.png) no-repeat;background:currentColor;filter:none}
|
||||
body[data-design=macaron] .game-tool .item-face :is(.ui-icon>.sprite-crop,.art-icon)>img{visibility:hidden}
|
||||
body[data-design=macaron] .game-tool[data-tool=undo] .item-face :is(.ui-icon>.sprite-crop,.art-icon){-webkit-mask-size:577.880% 577.880%;mask-size:577.880% 577.880%;-webkit-mask-position:65.574% 38.380%;mask-position:65.574% 38.380%}
|
||||
body[data-design=macaron] .game-tool[data-tool=restart] .item-face :is(.ui-icon>.sprite-crop,.art-icon){-webkit-mask-size:540.517% 540.517%;mask-size:540.517% 540.517%;-webkit-mask-position:95.890% 36.008%;mask-position:95.890% 36.008%}
|
||||
body[data-design=macaron] .game-tool[data-tool=hint] .item-face :is(.ui-icon>.sprite-crop,.art-icon){-webkit-mask-size:533.617% 533.617%;mask-size:533.617% 533.617%;-webkit-mask-position:4.220% 66.045%;mask-position:4.220% 66.045%}
|
||||
body[data-design=macaron]:not(.editing) .game-tool>b,body[data-design=macaron] .phone-tools .game-tool>b,body[data-design=macaron] .item-samples .game-tool>b{color:var(--mac-ink)}
|
||||
:is(.phone .phone-tools,body[data-design=macaron]:not(.editing) .board-tools) .game-tool:disabled{opacity:.45}
|
||||
/* Result screen: the reference's dark celebration. No card; cream glowing title on the scrim, rays and confetti behind the stars, one orange pill. */
|
||||
/* Full-screen result: the dialog covers the viewport, so rays, confetti and text are never clipped by a card edge. */
|
||||
body[data-design=macaron] .win-overlay{background:transparent!important;box-shadow:none;position:fixed;inset:0;width:100%;max-width:none;height:100%;max-height:none;margin:0;padding:24px 20px;border-radius:0;overflow:hidden}
|
||||
body[data-design=macaron] .win-overlay[open]{display:flex;flex-direction:column;justify-content:center;align-items:center;animation:mac-veil .32s ease-out both}
|
||||
@keyframes mac-veil{from{opacity:0}to{opacity:1}}
|
||||
body[data-design=macaron] .win-overlay>.ui-plate{display:none!important}
|
||||
body[data-design=macaron] .win-overlay::backdrop{background:rgba(40,26,32,.86);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
|
||||
body[data-design=macaron] .win-overlay .eyebrow{color:#C9AEB6}
|
||||
body[data-design=macaron] .win-overlay h3{color:#FFF3E6;font-size:25px;letter-spacing:.01em;text-shadow:0 0 22px rgba(255,214,150,.55),0 2px 0 rgba(0,0,0,.25)}
|
||||
body[data-design=macaron] .win-overlay p{color:#E9D2C4}
|
||||
body[data-design=macaron] .win-overlay .text-button{color:#FBEFE6;background:rgba(255,255,255,.14)!important;border-radius:999px;min-height:44px;padding:10px 26px;margin-top:12px}
|
||||
body[data-design=macaron] .win-overlay .text-button>.ui-plate{display:none!important}
|
||||
body[data-design=macaron] .win-overlay .result-emblem{position:relative;isolation:isolate;overflow:visible;margin-bottom:6px}
|
||||
body[data-design=macaron] .win-overlay[open] .result-emblem::before{content:'';position:absolute;left:50%;top:50%;width:640px;height:640px;margin:-320px 0 0 -320px;border-radius:50%;background:repeating-conic-gradient(from 0deg,rgba(255,200,96,.40) 0 7deg,transparent 7deg 18deg);-webkit-mask:radial-gradient(circle,#000 10%,transparent 60%);mask:radial-gradient(circle,#000 10%,transparent 60%);animation:mac-rays 40s linear infinite;z-index:-1;pointer-events:none}
|
||||
@keyframes mac-rays{to{transform:rotate(360deg)}}
|
||||
body[data-design=macaron] .win-overlay[open] .result-emblem::after{content:'';position:absolute;left:50%;top:-6px;width:7px;height:11px;border-radius:2px;background:#EE5398;box-shadow:-84px 6px 0 #578BF0,-48px -12px 0 #F7C948,-120px 16px 0 #4C9E5A,36px -10px 0 #937DE4,72px 8px 0 #E5680C,112px -2px 0 #369C94,-18px 18px 0 #C56AC4,96px 24px 0 #D06E93,-140px -4px 0 #F7C948,140px 10px 0 #EE5398;animation:mac-confetti 1.6s .3s ease-out both;pointer-events:none;z-index:-1}
|
||||
@keyframes mac-confetti{from{opacity:0;transform:translateY(-40px) rotate(0)}30%{opacity:1}to{opacity:0;transform:translateY(110px) rotate(200deg)}}
|
||||
body[data-design=macaron] .primary{color:#FFFFFF;font-weight:800;font-size:16px;min-height:52px;padding:12px 30px}
|
||||
body[data-design=macaron] .primary>.ui-plate{background:var(--mac-cta);border-radius:999px;box-shadow:0 4px 0 var(--mac-cta-edge);filter:none}
|
||||
body[data-design=macaron] .primary>.ui-plate .sprite-crop{display:none}
|
||||
/* Menus and the level map: a white card with a peach title band, like the reference's settings sheet. */
|
||||
body[data-design=macaron] #info-dialog::backdrop{background:var(--mac-scrim)}
|
||||
body[data-design=macaron] #info-dialog>.ui-plate{background:#FFFFFF;border-radius:28px}
|
||||
body[data-design=macaron] #info-dialog>.ui-plate .sprite-crop{display:none}
|
||||
body[data-design=macaron] #info-dialog>#dialog-content{margin:-32px -25px 0;padding:30px 25px 0;background:linear-gradient(#FBE6DA 0,#FBE6DA 104px,transparent 104px);border-radius:28px 28px 0 0}
|
||||
body[data-design=macaron] #info-dialog>#dialog-content>.eyebrow{text-align:center;display:block}
|
||||
body[data-design=macaron] #info-dialog>#dialog-content>h2{text-align:center;margin:8px 0 34px}
|
||||
body[data-design=macaron] dialog h2{color:#5A3A44}
|
||||
body[data-design=macaron] dialog p,body[data-design=macaron] dialog li,body[data-design=macaron] dialog .eyebrow{color:#8A6670}
|
||||
body[data-design=macaron] #info-dialog[open]{animation:mac-pop .38s cubic-bezier(.34,1.56,.64,1) both}
|
||||
@keyframes mac-pop{from{opacity:0;transform:scale(.86)}to{opacity:1;transform:scale(1)}}
|
||||
body[data-design=macaron] .text-button{color:var(--mac-muted)}
|
||||
body[data-design=macaron] .dialog-close.game-icon{z-index:2}
|
||||
body[data-design=macaron] .dialog-close.game-icon>.ui-plate{background:#FFFFFF;border-radius:50%;box-shadow:0 2px 8px rgba(110,70,82,.16)}
|
||||
body[data-design=macaron] .dialog-close.game-icon>.ui-plate .sprite-crop{display:none}
|
||||
body[data-design=macaron] .dialog-close.game-icon>.ui-icon{color:#7A5560}
|
||||
body[data-design=macaron] .level-btn>.ui-plate{background:#F7EFE8;border-radius:16px}
|
||||
body[data-design=macaron] .level-btn.done>.ui-plate{background:#E4F3EA}
|
||||
body[data-design=macaron] .level-btn.current>.ui-plate{background:var(--mac-cta)}
|
||||
body[data-design=macaron] .level-btn>.ui-plate .sprite-crop{display:none}
|
||||
body[data-design=macaron] .level-btn{color:#7A5560}
|
||||
@media(prefers-reduced-motion:reduce){body[data-design=macaron] .moves-bubble.pop,body[data-design=macaron] .win-overlay[open] .result-emblem::before,body[data-design=macaron] .win-overlay[open] .result-emblem::after{animation:none}}
|
||||
@@ -16,18 +16,16 @@ button{transition-duration:var(--pressMs)}button:active:enabled{transform:scale(
|
||||
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*,*::before,*::after{animation:none!important;transition:none!important}.pressed,button:active:enabled{transform:none!important}.rotate-example:active .icon{transform:none}dialog::backdrop{animation:none!important}}
|
||||
@media print{.topbar,.hero-actions,.search-box,.status,.print-hidden,dialog{display:none!important}.page{max-width:none;padding:0}.hero{grid-template-columns:1fr 300px;padding:20px 0;gap:25px}.hero h1{font-size:36px}.section{padding:25px 0}.swatch-grid{grid-template-columns:repeat(4,1fr)}.card,.swatch,.icon-item,.pair-card,.type-sample{break-inside:avoid}.section-head{break-after:avoid}.table-scroll{overflow:visible}tr{break-inside:avoid}.spec h3{break-after:avoid}body{-webkit-print-color-adjust:exact;print-color-adjust:exact}.footer{padding-bottom:0}}
|
||||
@media print{.swatch[hidden]{display:block!important}.empty{display:none!important}}
|
||||
.mini-stars .icon.icon-star{filter:brightness(0) saturate(100%) invert(79%) sepia(85%) saturate(1450%) hue-rotate(350deg) brightness(105%) contrast(102%) drop-shadow(0 2px 1px #c88b2380) drop-shadow(0 0 7px #ffd45c99) drop-shadow(0 0 16px #ffe8a366)}
|
||||
{{GAME_TOOLS_CSS}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{{TILE_IMAGE}}
|
||||
<header class="topbar"><div class="page"><a class="brand" href="#overview"><span></span>HEX TRAILS</a><nav class="nav" aria-label="设计手册目录"><a href="#colors">颜色</a><a href="#components">组件</a><a href="#icons">图标</a><a href="#type">排版</a><a href="#motion">动效</a><a href="#specification">完整规范</a></nav></div></header>
|
||||
<main class="page">
|
||||
<section class="hero" id="overview"><div><p class="eyebrow">视觉设计手册 · 1.0 / 2026.09.08</p><h1>让每一种颜色<br><span>各司其职。</span></h1><p>HEX TRAILS 的视觉语言:冷蓝灰承托环境,暖白勾勒棋盘,紫色强调操作。把最明快的颜色,留给棋子。</p><div class="scheme-strip" aria-label="核心配色"><span style="background:var(--background)"></span><span style="background:var(--board)"></span><span style="background:var(--utility)"></span><span style="background:var(--primary)"></span><span style="background:var(--tileYellow)"></span></div><div class="hero-actions"><a class="button primary" href="#colors">查看颜色体系</a><button class="button" id="print-guide">打印 / 存为 PDF</button></div><p class="hero-note">适用:游戏界面、手机触摸操作、Cocos 移植。<br>本文件可离线打开,包含完整规范与原始图片。</p></div><div><div class="phone-stage" aria-label="当前主界面静态组合示例"><div class="phone-top"><span class="icon-ground"><span class="icon icon-grid" aria-hidden="true"></span></span><span class="phone-level">LEVEL 02</span><span class="icon-ground"><span class="icon icon-gear" aria-hidden="true"></span></span></div><div class="phone-moves">剩余步数<b>{{MOVES}}</b></div>{{BOARD}}<div class="phone-rotate"><div><span class="icon icon-left" aria-hidden="true"></span><small>左转</small></div><div><span class="icon icon-right" aria-hidden="true"></span><small>右转</small></div></div><div class="guide-tools">{{GAME_ITEMS_ROW}}</div></div><p class="preview-caption">静态组合示意 · 使用实际关卡绘制与当前生成素材</p></div></section>
|
||||
<section class="hero" id="overview"><div><p class="eyebrow">视觉设计手册 · 1.0 / 2026.09.08</p><h1>让每一种颜色<br><span>各司其职。</span></h1><p>HEX TRAILS 的视觉语言:冷蓝灰承托环境,暖白勾勒棋盘,紫色强调操作。把最明快的颜色,留给棋子。</p><div class="scheme-strip" aria-label="核心配色"><span style="background:var(--background)"></span><span style="background:var(--board)"></span><span style="background:var(--utility)"></span><span style="background:var(--primary)"></span><span style="background:var(--tileYellow)"></span></div><div class="hero-actions"><a class="button primary" href="#colors">查看颜色体系</a><button class="button" id="print-guide">打印 / 存为 PDF</button></div><p class="hero-note">适用:游戏界面、手机触摸操作、Cocos 移植。<br>本文件可离线打开,包含完整规范与原始图片。</p></div><div><div class="phone-stage" aria-label="当前主界面静态组合示例"><div class="phone-top"><span class="icon-ground"><span class="icon icon-grid" aria-hidden="true"></span></span><span class="phone-level">LEVEL 02</span><span class="icon-ground"><span class="icon icon-gear" aria-hidden="true"></span></span></div><div class="phone-moves">剩余步数<b>{{MOVES}}</b></div>{{BOARD}}<div class="phone-rotate"><div><span class="icon icon-left" aria-hidden="true"></span><small>左转</small></div><div><span class="icon icon-right" aria-hidden="true"></span><small>右转</small></div></div><div class="phone-tools"><div class="demo-disabled"><span class="icon-ground"><span class="icon icon-undo" aria-hidden="true"></span></span><small>撤销</small></div><div><span class="icon-ground"><span class="icon icon-restart" aria-hidden="true"></span></span><small>重来</small></div><div><span class="icon-ground"><span class="icon icon-bulb" aria-hidden="true"></span></span><small>提示</small></div></div></div><p class="preview-caption">静态组合示意 · 使用实际关卡绘制与当前生成素材</p></div></section>
|
||||
<div class="principles"><article class="principle"><h3>01 · 先分角色,再选颜色</h3><p>环境、内容、操作与状态各有用途。同一层级的工具使用同一组颜色。</p></article><article class="principle"><h3>02 · 一个界面,一个重点</h3><p>紫色留给主要确认与选中状态;蓝灰工具安静地服务棋盘。</p></article><article class="principle"><h3>03 · 让信息看得清楚</h3><p>配对检查文字和图形的对比度;用文字、图标与反馈共同表达状态。</p></article></div>
|
||||
<section class="section" id="colors" style="margin-top:60px"><div class="section-head"><div><span class="section-num">01 / COLOR</span><h2>有职责的色板</h2><p>点击色块复制 HEX。先看用途,再选颜色;不要把棋子色直接套到普通按钮上。</p></div><span class="pill">固定浅色主题</span></div><div class="search-box"><input id="color-search" type="search" placeholder="搜索颜色用途、Token 或 HEX" aria-label="搜索颜色"><span id="color-count"></span></div><div class="swatch-grid" id="swatches">{{SWATCHES}}</div><p class="empty" id="empty-colors" hidden>没有找到匹配颜色,请换一个关键词。</p><p class="note">棋子 HEX 是已接受图片的代表采样值,不保证每个像素完全一致。遮罩色含透明度,展示时会与手册底色混合。</p><div class="pair-grid"><div class="pair-card primary-pair"><b>下一关</b><p>主操作:紫底 + 白字<br>一张弹窗只放一个高强调主操作。</p><code>primary / onPrimary</code></div><div class="pair-card utility-pair"><b>设置</b><p>导航:蓝灰底 + 白色图标<br>底部游戏道具使用更大的独立彩色底座。</p><code>utility / onUtility</code></div><div class="pair-card warning-pair"><b>路线被挡住了</b><p>反馈:浅暖底 + 深警告色<br>搭配明确原因,不依赖颜色表达阻挡。</p><code>warningSurface / warning</code></div></div><h3>配对对比度</h3><p class="note" style="margin:0 0 20px">下表检查不透明 Token 配对:文字 4.5:1,必要图形 3:1。蓝棋子上的白箭头通过图形标准,不适合据此放白色小字。透明图标、阴影和真实字体仍需画面验收。</p><div class="table-scroll"><table class="pair-table"><thead><tr><th>实际配对</th><th>前景 / 背景</th><th>对比度</th><th>最低要求</th><th>Token 检查</th></tr></thead><tbody>{{PAIR_ROWS}}</tbody></table></div></section>
|
||||
<section class="section" id="components"><div class="section-head"><div><span class="section-num">02 / COMPONENTS</span><h2>把规范放到控件上</h2><p>真实图标、明确层级和可识别状态。以下按钮可点击查看反馈,禁用示例确实不可点击。</p></div></div><div class="component-grid"><article class="card"><h3>操作层级</h3><div class="demo-row"><button class="button primary" data-feedback="主操作:primary / onPrimary">下一关 <span class="icon icon-play" aria-hidden="true"></span></button><button class="button" data-feedback="次操作:secondary / textPrimary">再走一遍</button></div><div class="demo-row"><button class="button utility" data-feedback="工具:utility / onUtility"><span class="icon icon-gear" aria-hidden="true"></span>设置</button><button class="button utility demo-disabled" disabled><span class="icon icon-grid" aria-hidden="true"></span>选关</button></div><p>网页禁用态是在正常控件上应用 55% 透明度。<code>disabled / onDisabled</code> 是原生参考色,二者不要混用。</p></article><article class="card"><h3>按压与键盘焦点</h3><div class="demo-row"><div class="demo-column"><button class="button utility" data-feedback="默认状态">设置</button><small>默认</small></div><div class="demo-column"><button class="button utility pressed" data-feedback="按压示意:缩放至 94%">设置</button><small>按压示意</small></div><div class="demo-column"><button class="button utility focus-demo" data-feedback="使用 Tab 键查看真实焦点">设置</button><small>焦点示意</small></div></div><p>按压反馈为 150ms。使用 Tab 键可查看真实焦点;轮廓与形状共同标识交互状态。</p></article><article class="card"><h3>旋转:留出呼吸空间</h3><div class="demo-row rotation-demo"><button class="rotate-example" data-feedback="左转控件:无矩形底板"><span class="icon icon-left" aria-hidden="true"></span>左转</button><button class="rotate-example" data-feedback="右转控件:无矩形底板"><span class="icon icon-right" aria-hidden="true"></span>右转</button></div><p>保留生成图标造型,放大显示并附文字。轮廓使用轻微蓝灰阴影;它不属于上面的纯色对比度检查。</p></article><article class="card"><h3>选中:颜色加状态文字</h3><div class="level-samples" aria-label="关卡选中状态演示"><button class="level-sample" aria-pressed="false">01<small>选择关卡</small></button><button class="level-sample" aria-pressed="true">02<small>当前关卡</small></button><button class="level-sample" aria-pressed="false">03<small>选择关卡</small></button></div><p>点击切换选中示例。普通关卡用中性底色和深色数字,当前关卡用紫底白字,并有明确状态。</p></article></div><article class="card" style="margin-top:24px"><h3>游戏道具:独立于顶部导航</h3>{{GAME_ITEMS}}<p>棋盘以通知区和旋转区之间的可用区域为中心,上下留白相等。旋转、道具分行排列,不覆盖棋盘。</p></article><article class="card tile-panel"><div>{{TILES}}</div><div><h3>四种棋子,一套规则</h3><p>使用当前棋子图片与共享圆角六边形遮罩,方向箭头沿用游戏绘制。颜色不代表功能、品质或阵营。</p><p><b>黄色必须使用深色箭头。</b><br>白箭头保留在蓝、粉、紫棋子上。各色棋子均通过位置、方向和运动判断。</p></div></article></section>
|
||||
<section class="section" id="colors" style="margin-top:60px"><div class="section-head"><div><span class="section-num">01 / COLOR</span><h2>有职责的色板</h2><p>点击色块复制 HEX。先看用途,再选颜色;不要把棋子色直接套到普通按钮上。</p></div><span class="pill">固定浅色主题</span></div><div class="search-box"><input id="color-search" type="search" placeholder="搜索颜色用途、Token 或 HEX" aria-label="搜索颜色"><span id="color-count"></span></div><div class="swatch-grid" id="swatches">{{SWATCHES}}</div><p class="empty" id="empty-colors" hidden>没有找到匹配颜色,请换一个关键词。</p><p class="note">棋子 HEX 是已接受图片的代表采样值,不保证每个像素完全一致。遮罩色含透明度,展示时会与手册底色混合。</p><div class="pair-grid"><div class="pair-card primary-pair"><b>下一关</b><p>主操作:紫底 + 白字<br>一张弹窗只放一个高强调主操作。</p><code>primary / onPrimary</code></div><div class="pair-card utility-pair"><b>提示</b><p>工具:蓝灰底 + 白色图标<br>选关、设置、撤销、重来、提示统一。</p><code>utility / onUtility</code></div><div class="pair-card warning-pair"><b>路线被挡住了</b><p>反馈:浅暖底 + 深警告色<br>搭配明确原因,不依赖颜色表达阻挡。</p><code>warningSurface / warning</code></div></div><h3>配对对比度</h3><p class="note" style="margin:0 0 20px">下表检查不透明 Token 配对:文字 4.5:1,必要图形 3:1。蓝棋子上的白箭头通过图形标准,不适合据此放白色小字。透明图标、阴影和真实字体仍需画面验收。</p><div class="table-scroll"><table class="pair-table"><thead><tr><th>实际配对</th><th>前景 / 背景</th><th>对比度</th><th>最低要求</th><th>Token 检查</th></tr></thead><tbody>{{PAIR_ROWS}}</tbody></table></div></section>
|
||||
<section class="section" id="components"><div class="section-head"><div><span class="section-num">02 / COMPONENTS</span><h2>把规范放到控件上</h2><p>真实图标、明确层级和可识别状态。以下按钮可点击查看反馈,禁用示例确实不可点击。</p></div></div><div class="component-grid"><article class="card"><h3>操作层级</h3><div class="demo-row"><button class="button primary" data-feedback="主操作:primary / onPrimary">下一关 <span class="icon icon-play" aria-hidden="true"></span></button><button class="button" data-feedback="次操作:secondary / textPrimary">再走一遍</button></div><div class="demo-row"><button class="button utility" data-feedback="工具:utility / onUtility"><span class="icon icon-bulb" aria-hidden="true"></span>提示</button><button class="button utility demo-disabled" disabled><span class="icon icon-undo" aria-hidden="true"></span>撤销</button></div><p>网页禁用态是在正常控件上应用 55% 透明度。<code>disabled / onDisabled</code> 是原生参考色,二者不要混用。</p></article><article class="card"><h3>按压与键盘焦点</h3><div class="demo-row"><div class="demo-column"><button class="button utility" data-feedback="默认状态">提示</button><small>默认</small></div><div class="demo-column"><button class="button utility pressed" data-feedback="按压示意:缩放至 94%">提示</button><small>按压示意</small></div><div class="demo-column"><button class="button utility focus-demo" data-feedback="使用 Tab 键查看真实焦点">提示</button><small>焦点示意</small></div></div><p>按压反馈为 150ms。使用 Tab 键可查看真实焦点;轮廓与形状共同标识交互状态。</p></article><article class="card"><h3>旋转:留出呼吸空间</h3><div class="demo-row rotation-demo"><button class="rotate-example" data-feedback="左转控件:无矩形底板"><span class="icon icon-left" aria-hidden="true"></span>左转</button><button class="rotate-example" data-feedback="右转控件:无矩形底板"><span class="icon icon-right" aria-hidden="true"></span>右转</button></div><p>保留生成图标造型,放大显示并附文字。轮廓使用轻微蓝灰阴影;它不属于上面的纯色对比度检查。</p></article><article class="card"><h3>选中:颜色加状态文字</h3><div class="level-samples" aria-label="关卡选中状态演示"><button class="level-sample" aria-pressed="false">01<small>选择关卡</small></button><button class="level-sample" aria-pressed="true">02<small>当前关卡</small></button><button class="level-sample" aria-pressed="false">03<small>选择关卡</small></button></div><p>点击切换选中示例。普通关卡用中性底色和深色数字,当前关卡用紫底白字,并有明确状态。</p></article></div><article class="card tile-panel"><div>{{TILES}}</div><div><h3>四种棋子,一套规则</h3><p>使用当前棋子图片与共享圆角六边形遮罩,方向箭头沿用游戏绘制。颜色不代表功能、品质或阵营。</p><p><b>黄色必须使用深色箭头。</b><br>白箭头保留在蓝、粉、紫棋子上。各色棋子均通过位置、方向和运动判断。</p></div></article></section>
|
||||
<section class="section" id="icons"><div class="section-head"><div><span class="section-num">03 / ASSETS</span><h2>同一套图标,同一套语气</h2><p>当前使用的 16 个生成图标,按实际图形边界裁成正方形并等比居中。这里保留原始 PNG 的像素与造型。</p></div><span class="pill">原图 1254 × 1254</span></div><div class="icon-grid">{{ICONS}}</div><p class="note">原图:<code>ui-icons-generated.png</code>;裁切:<code>src/ui-skin.js → ICONS</code>。不要用代码重绘版、字符或另一套图标替换。透明边缘仍需实机验收。</p></section>
|
||||
<section class="section" id="type"><div class="section-head"><div><span class="section-num">04 / TYPOGRAPHY & SPACING</span><h2>简单、有秩序的细节</h2><p>文字靠尺寸和字重建立层级,辅助文字仍保持可读对比。以下字号是游戏控件规范,手册正文为阅读做了适当放大。</p></div></div><div class="type-layout"><div><div class="type-sample"><b style="font-size:28px">LEVEL 02</b><code>28px / 粗体</code></div><div class="type-sample"><b style="font-size:32px">9</b><code>步数 32px / 粗体</code></div><div class="type-sample"><b style="font-size:24px">漂亮,全部过关!</b><code>标题 24px</code></div><div class="type-sample"><span style="font-size:14px">轻点箭头,沿着轨道出发。</span><code>正文 13–14px<br>行高 1.75</code></div><div class="type-sample"><span style="font-size:12px">撤销 · 重来 · 提示</span><code>标签 12–13px</code></div></div><div><h3>4px 基础间距</h3><div class="space-row" aria-label="4、8、12、16、24、32 像素间距"><span style="--space:4px" data-size="4"></span><span style="--space:8px" data-size="8"></span><span style="--space:12px" data-size="12"></span><span style="--space:16px" data-size="16"></span><span style="--space:24px" data-size="24"></span><span style="--space:32px" data-size="32"></span></div><h3 style="margin-top:40px">统一圆角</h3><div class="shape-row"><div class="shape" style="border-radius:8px">8px<br>小角标</div><div class="shape" style="border-radius:14px">14px<br>控件</div><div class="shape" style="border-radius:24px">24px<br>弹窗</div></div><p class="note">常规触摸区至少 44 × 44px。中文使用 PingFang SC / Microsoft YaHei;原生端如需一致字宽,须统一授权字体资源。</p></div></div></section>
|
||||
<section class="section" id="motion"><div class="section-head"><div><span class="section-num">05 / MOTION</span><h2>轻快地出现,清楚地反馈</h2><p>打开演示,查看遮罩、弹窗入场和三颗星星的顺序。遵循系统“减少动态效果”设置。</p></div></div><div class="motion-layout"><div class="motion-preview"><div class="mini-modal"><div class="mini-stars" aria-hidden="true"><span class="icon icon-star"></span><span class="icon icon-star"></span><span class="icon icon-star"></span></div><h3>漂亮,全部过关!</h3><button class="button primary" id="show-motion">播放弹窗动效</button></div></div><div class="timings"><div class="timing"><span>按钮按压</span><b>150 <small>ms</small></b></div><div class="timing"><span>弹窗从上方进入</span><b>420 <small>ms</small></b></div><div class="timing"><span>星星依次开始</span><b><small>300 / 490 / 680 ms</small></b></div><div class="timing"><span>碰撞反馈总长</span><b>1250 <small>ms</small></b></div><p class="note">碰撞顺序:接近 → 接触停顿与阻挡棋子轻震 → 原路弹回。该顺序在游戏中执行,此处只演示弹窗;游戏音效在首次手势后启动,可在设置关闭。</p></div></div></section>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,121 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generated": true,
|
||||
"generatedBy": "scripts/build-art-directions.mjs",
|
||||
"pathBase": "repository-root",
|
||||
"entry": "design/README.md",
|
||||
"agentGuide": "design/AGENTS.md",
|
||||
"sharedRules": "design/shared.md",
|
||||
"catalog": "design/index.html",
|
||||
"example": "design/examples/render-design.mjs",
|
||||
"defaultDesignId": "calm",
|
||||
"latestDesignId": "macaron",
|
||||
"selectionPolicy": "multiple-candidates",
|
||||
"themeIds": [
|
||||
"lagoon",
|
||||
"apricot",
|
||||
"lavender",
|
||||
"rose",
|
||||
"midnight"
|
||||
],
|
||||
"paletteCounts": [
|
||||
4,
|
||||
7,
|
||||
9,
|
||||
12
|
||||
],
|
||||
"sources": {
|
||||
"directions": "src/art-directions.js",
|
||||
"baseTokens": "src/design-tokens.js",
|
||||
"renderer": "src/renderer.js",
|
||||
"tokenDrawing": "src/token-art.js",
|
||||
"componentStyles": "design/art-directions.css",
|
||||
"itemStyles": "design/game-tools.css"
|
||||
},
|
||||
"designs": [
|
||||
{
|
||||
"id": "calm",
|
||||
"code": "01",
|
||||
"name": "柔和原色",
|
||||
"artStyle": "classic",
|
||||
"status": "existing-default",
|
||||
"directory": "design/directions/calm",
|
||||
"designDoc": "design/directions/calm/design.md",
|
||||
"tokens": "design/directions/calm/tokens.json",
|
||||
"preview": "design/directions/calm/index.html",
|
||||
"legacyPreview": "design/directions/calm.html"
|
||||
},
|
||||
{
|
||||
"id": "vivid",
|
||||
"code": "02",
|
||||
"name": "高彩游乐场",
|
||||
"artStyle": "vivid",
|
||||
"status": "review-candidate",
|
||||
"directory": "design/directions/vivid",
|
||||
"designDoc": "design/directions/vivid/design.md",
|
||||
"tokens": "design/directions/vivid/tokens.json",
|
||||
"preview": "design/directions/vivid/index.html",
|
||||
"legacyPreview": "design/directions/vivid.html"
|
||||
},
|
||||
{
|
||||
"id": "toy",
|
||||
"code": "03",
|
||||
"name": "积木轨道屋",
|
||||
"artStyle": "toy",
|
||||
"status": "review-candidate",
|
||||
"directory": "design/directions/toy",
|
||||
"designDoc": "design/directions/toy/design.md",
|
||||
"tokens": "design/directions/toy/tokens.json",
|
||||
"preview": "design/directions/toy/index.html",
|
||||
"legacyPreview": "design/directions/toy.html"
|
||||
},
|
||||
{
|
||||
"id": "animals",
|
||||
"code": "04",
|
||||
"name": "动物弯弯镇",
|
||||
"artStyle": "animals",
|
||||
"status": "review-candidate",
|
||||
"directory": "design/directions/animals",
|
||||
"designDoc": "design/directions/animals/design.md",
|
||||
"tokens": "design/directions/animals/tokens.json",
|
||||
"preview": "design/directions/animals/index.html",
|
||||
"legacyPreview": "design/directions/animals.html"
|
||||
},
|
||||
{
|
||||
"id": "paper",
|
||||
"code": "05",
|
||||
"name": "轻线纸境",
|
||||
"artStyle": "paper",
|
||||
"status": "review-candidate",
|
||||
"directory": "design/directions/paper",
|
||||
"designDoc": "design/directions/paper/design.md",
|
||||
"tokens": "design/directions/paper/tokens.json",
|
||||
"preview": "design/directions/paper/index.html",
|
||||
"legacyPreview": "design/directions/paper.html"
|
||||
},
|
||||
{
|
||||
"id": "signpost",
|
||||
"code": "06",
|
||||
"name": "路标",
|
||||
"artStyle": "signpost",
|
||||
"status": "review-candidate",
|
||||
"directory": "design/directions/signpost",
|
||||
"designDoc": "design/directions/signpost/design.md",
|
||||
"tokens": "design/directions/signpost/tokens.json",
|
||||
"preview": "design/directions/signpost/index.html",
|
||||
"legacyPreview": "design/directions/signpost.html"
|
||||
},
|
||||
{
|
||||
"id": "macaron",
|
||||
"code": "07",
|
||||
"name": "马卡龙",
|
||||
"artStyle": "macaron",
|
||||
"status": "review-candidate",
|
||||
"directory": "design/directions/macaron",
|
||||
"designDoc": "design/directions/macaron/design.md",
|
||||
"tokens": "design/directions/macaron/tokens.json",
|
||||
"preview": "design/directions/macaron/index.html",
|
||||
"legacyPreview": "design/directions/macaron.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/* A reserved status row keeps notifications stable and clear of the board. */
|
||||
.notice-slot{grid-column:1/-1;display:flex;align-items:center;justify-content:center;min-width:0;padding:3px 12px 7px;pointer-events:none}
|
||||
.game-notice{max-width:480px;width:fit-content;display:flex;align-items:center;gap:9px;padding:9px 14px;border:1px solid #52697e24;border-radius:14px;background:#f7faf7ed;color:#334c61;box-shadow:0 3px 10px #273b5008;font-size:12px;font-weight:500;line-height:1.5;text-align:left;overflow-wrap:anywhere;opacity:0;transform:translateY(-4px);transition:opacity .18s ease,transform .18s ease}
|
||||
.game-notice::before{content:'i';display:grid;place-items:center;flex:0 0 18px;width:18px;height:18px;border-radius:6px;background:#e0e9ee;color:#435f78;font-size:12px;font-weight:750;font-family:Georgia,serif}
|
||||
.game-notice.visible{opacity:1;transform:translateY(0)}
|
||||
.game-notice:empty{visibility:hidden}
|
||||
body:not(.editing) .game-column{grid-template-rows:44px 44px 64px minmax(0,1fr)}
|
||||
body:not(.editing) .notice-slot{grid-row:3;align-self:stretch}
|
||||
body:not(.editing) .game-card{grid-row:4}
|
||||
.editing .notice-slot{grid-column:1/-1;min-height:64px}
|
||||
.phone{grid-template-rows:44px 40px 64px minmax(0,1fr) 60px}
|
||||
.phone .notice-slot{grid-row:3}
|
||||
.phone canvas{grid-row:4}
|
||||
.phone .phone-tools button{grid-row:5}
|
||||
@media(min-width:600px){body:not(.editing) .game-column{grid-template-rows:48px 44px 64px minmax(0,1fr)}.game-notice{font-size:13px}}
|
||||
@media(min-width:600px) and (max-height:600px){body:not(.editing) .game-column{grid-template-rows:40px 32px 56px minmax(0,1fr)}.game-notice{padding:6px 11px;font-size:12px}}
|
||||
@media(prefers-reduced-motion:reduce){.game-notice{transition:none;transform:none}}
|
||||
@@ -1,116 +0,0 @@
|
||||
# 五套设计的接入与维护约定
|
||||
|
||||
适用于主游戏的 01–05 五套设计。先读 [方案目录](README.md),确定设计 ID,再读对应的 `design.md`。本文和各套 design.md 是人工维护的设计规则;数值以实现源及其生成的 tokens.json 为准。发现文档与实现不一致时核对用户已确认要求并同步修正,不能用旧说明撤回新要求。
|
||||
|
||||
## 选择一个设计与主题
|
||||
|
||||
三个参数分别控制不同的事:
|
||||
|
||||
| 参数 | 合法值 | 作用 |
|
||||
| --- | --- | --- |
|
||||
| `design` | `calm` / `vivid` / `toy` / `animals` / `paper` / `signpost` / `macaron` | 棋子造型、轨道画法、配色库和控件风格 |
|
||||
| `theme` | `lagoon` / `apricot` / `lavender` / `rose` / `midnight` | 轻松、进阶、烧脑、挑战、每周挑战的视觉主题 |
|
||||
| `colors` | 4 / 7 / 9 / 12 | 主游戏单关使用的棋子配色数量,默认 7 |
|
||||
|
||||
在根目录执行 `npm run dev`。打开 [paper 的轻松主题](../index.html?design=paper&theme=lagoon&colors=7),或 [paper 的夜间审核](../design-showcase.html?design=paper&theme=midnight#phone)。审核页用控件切换色数;`colors` URL 参数由主游戏读取。设计总览的主题切换只用于视觉对照。
|
||||
|
||||
不传 design 时使用 calm。主游戏不传 theme 时按关卡评分选前四种主题;midnight 需显式指定。主题名与配色不改变难度或玩法。编辑模式和工坊试玩使用基础自由配色,不能拿它们判断设计参数是否生效。审核记录保存在 `hex-trails-art-review-v1`,与游戏存档分开。
|
||||
|
||||
## Agent 如何读取数据
|
||||
|
||||
1. 读取 [manifest.json](manifest.json),确认 `schemaVersion === 1`。
|
||||
2. 按 `designs[].id` 找方案,读取 `designDoc` 与 `tokens`。manifest 的所有路径字段均从仓库根目录解析,不从当前 JSON 目录拼接。
|
||||
3. tokens 中的 `themes` 给出环境、文字和已展开的棋盘材质。`palettes["7"]` 是 7 色时的**有序色库索引**;索引指向本文件的 `pigments`,不能借用另一套设计的色库。
|
||||
4. tokens 是当前实现的只读数值导出,不能单独描述完整造型或所有 CSS 控件。几何和组件规则仍需读取 design.md、共享渲染器及 CSS。`design/tokens.json` 是旧有基础语义 token 导出,不包含五套方案全集。
|
||||
|
||||
manifest 不存用户审核意见,也不表示最新方案已被选为默认。文档中的“最新”只表示新增顺序。
|
||||
|
||||
## 复用现有渲染器
|
||||
|
||||
浏览器页面已有 `<canvas id="board" width="600" height="600"></canvas>` 时,可在仓库根目录页面的 ES module 中运行以下代码;通过 HTTP 加载,不直接双击文件:
|
||||
|
||||
```js
|
||||
import { artDirection, directionTheme } from './src/art-directions.js';
|
||||
import { CanvasPainter, drawScene } from './src/renderer.js';
|
||||
import { layout } from './src/geometry.js';
|
||||
import { createStudyLevel } from './src/study-levels.js';
|
||||
import { TILE_ATLAS } from './src/sprites.js';
|
||||
|
||||
const direction = artDirection('paper');
|
||||
const theme = directionTheme(direction, 'lagoon', 7);
|
||||
const level = createStudyLevel(3);
|
||||
const canvas = document.querySelector('#board');
|
||||
const painter = new CanvasPainter(canvas.getContext('2d'));
|
||||
const atlas = new Image();
|
||||
atlas.src = TILE_ATLAS;
|
||||
await atlas.decode();
|
||||
painter.atlas = atlas;
|
||||
canvas.style.background = theme.background;
|
||||
canvas.style.color = theme.ink;
|
||||
painter.ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
drawScene(painter, level, level.tiles,
|
||||
layout(level.cells, canvas.width, canvas.height), { theme });
|
||||
```
|
||||
|
||||
`drawScene` 只画棋盘、轨道与棋子,不画画布背景,也不自动清屏。响应式画布使用实际显示尺寸和 DPR,复用 [board-viewport.js](../src/board-viewport.js) / app.js 的适配逻辑。不要根据每枚棋子的位置另设显示比例。
|
||||
|
||||
整盘绘制时传入完整的 `level.tiles` 与当前剩余 tiles。`drawScene` 以棋子在初始 `level.tiles` 中的索引映射主题 palette,因此移除、撤销与运动不换色;不要按“剩余棋子第几个”重新编号。独立棋子样本才使用 `appearanceTile({color: pigmentIndex, dir}, theme)` 再调用 `drawTile`,这里的 color 已是该设计的色库索引。
|
||||
|
||||
所有方向以弧度 `-Math.PI / 2 + dir * Math.PI / 3` 绘制,dir 为 0–5。移动中的棋子经共享 `drawExit` / `drawTile` 保持同一造型。不要复制静态棋子绘制代码实现另一套移动画法。
|
||||
|
||||
## 接入完整游戏界面
|
||||
|
||||
| 接入点 | 实际来源 | 注意事项 |
|
||||
| --- | --- | --- |
|
||||
| 设计与主题定义 | [src/art-directions.js](../src/art-directions.js) | ID、12 色库、五主题、artStyle;calm 复用基础色库 |
|
||||
| 基础语义色、字体、动效 | [src/design-tokens.js](../src/design-tokens.js) | 被各设计继承;不能用基础色覆盖新方案的独立色库 |
|
||||
| 场景几何与运动绘制 | [src/renderer.js](../src/renderer.js)、[src/token-art.js](../src/token-art.js) | 使用同一套命令和曲线路径 |
|
||||
| 主游戏选择逻辑 | [src/app.js](../src/app.js) | 设置 body.dataset.design / theme,应用场景背景与文字色 |
|
||||
| 控件风格 | [art-directions.css](art-directions.css) | 用 body[data-design] 限定,避免影响其他方案 |
|
||||
| 底部道具及布局 | [game-tools.css](game-tools.css) | 最后加载,保证扁平道具覆盖既有立体风格 |
|
||||
| 通知与通用组件 | [notifications.css](notifications.css)、[components.css](components.css) | 通知位于剩余步数下方,奖励为金色发光星星 |
|
||||
| 图集与裁切 | [src/sprites.js](../src/sprites.js)、[src/ui-skin.js](../src/ui-skin.js) | 棋子图集只在 calm 分支使用;UI 图标各套共享 |
|
||||
|
||||
主游戏 CSS 加载顺序参考 [index.html](../index.html):style.css → tokens.css → components.css → notifications.css → campaign.css → art-directions.css → game-tools.css。只有设置 CSS 主题而没给 drawScene 传 theme,棋盘仍会使用基础画法。只有给画布传 theme 而没设置 body.dataset.design,控件不会切换。
|
||||
|
||||
## 所有方案共用的产品要求
|
||||
|
||||
- 棋盘在通知区与旋转区之间垂直居中。旋转与道具占真实布局行,不绝对定位压住棋盘。适配手机、Pad、折叠屏和桌面。
|
||||
- 撤销、重来、提示是游戏道具,与顶部紧凑导航分开。常规底座 64px,宽度至少 600px 时为 68px,短屏高度不超过 600px 时为 56px;图标 32px、标签 13px。底座无阴影、立体底边或渐变高光,方案的棋子材质不覆盖这条要求。唯一例外:07 `macaron` 的道具是参考作品的白色圆钮带柔和投影,2026-09-14 用户确认只允许该方案使用,其他方案(含新增方案)继续保持扁平,不得引用这条例外。
|
||||
- 次数和“▶ AD”角标只用于设计示例,当前不接入真实库存、广告或付费获取逻辑。
|
||||
- 奖励星星为黄色/金色并带光感。通知固定在剩余步数下方,不能挪回棋盘下方。
|
||||
- 路线以弯曲路径为主要观看内容。动画复用 [exit-animation.js](../src/exit-animation.js) 和 [collision-animation.js](../src/collision-animation.js)。离场时长按实际路径长度计算,不把旧文档中的固定时长或上下限当作当前速度公式。
|
||||
- 设计切换不改规则、关卡布局、编号、关卡版本或存档。设计编号 01–05 与关卡 v0.1–v0.5 是两套不同的标识。
|
||||
|
||||
## 修改与验证
|
||||
|
||||
只改配色:编辑 art-directions.js 中指定设计;calm 的色库及基础主题在 design-tokens.js。改造型:编辑 token-art.js 的指定分支,必要时改 renderer.js 的相关绘制,并同步该套 design.md。改控件:编辑对应 CSS 的作用域规则;共用道具约束仍需保留。
|
||||
|
||||
文档整理不需要重新生成关卡。根目录执行:
|
||||
|
||||
```sh
|
||||
npm run design
|
||||
node --test tests/design-packages.test.js tests/art-directions.test.js tests/themes.test.js
|
||||
node design/examples/render-design.mjs paper lagoon 7
|
||||
node scripts/build.mjs
|
||||
```
|
||||
|
||||
`npm run design` 会刷新 manifest、每套 tokens、HTML 和旧入口;**不覆盖人工维护的 design.md、shared.md、README.md**。文档测试检查目录与链接、数值导出与运行时一致性,并执行接入示例。视觉修改另检查五主题、长弯路离场、碰撞、旋转与撤销;至少查看 390×844 手机、短屏、平板和桌面。纯文档修改检查链接和预览能加载即可。原生验证单独报告。
|
||||
|
||||
## 跨引擎范围与已知限制
|
||||
|
||||
绘制抽象只要求 polygon、line、circle,calm 可额外使用 sprite 图集。路径单位是格半径;不能把示例画布尺寸当作固定像素规范。实际应用背景和 UI 布局由宿主引擎实现。
|
||||
|
||||
[cocos/HexTrailsBoard.ts](../cocos/HexTrailsBoard.ts) 是适配示例,当前没有传入这五套设计的 theme,且动画时序仍有旧值;[cocos/CandyUiSkin.ts](../cocos/CandyUiSkin.ts) 也不是五套设计的完整原生控件实现。移植时需显式接入主题、核对圆头线条与图层,并按浏览器参考画面验收;本目录不代表原生移植已完成。
|
||||
|
||||
paper 的浅色轨道是用户认可的特例,轨道与棋盘对比度低于基础 3:1 目标;不要为通过基础轨道指标自行加深。文字和方向需保持可读。各套 design.md 标明具体差异。
|
||||
|
||||
## 实现依据与旧文档
|
||||
|
||||
| 依据 | 确认的事实 | 修改/复现入口 |
|
||||
| --- | --- | --- |
|
||||
| art-directions.js 导出的五个 ID | 五套方案共存且都有五种主题 | manifest.json、每套 tokens.json |
|
||||
| renderer.js 的 visualTile 与 paper 分支 | 固定初始索引配色,paper 使用更细轨道 | render-design.mjs、art-directions.test.js |
|
||||
| game-tools.css 的最后加载覆盖 | 道具保持扁平且分行布局 | 各套 index.html、主游戏 |
|
||||
|
||||
[根目录 Design.md](../Design.md) / Design.html 保留基础组件规范与历史说明,[docs/art-direction.md](../docs/art-direction.md) 保留较早的制作简报。它们的“唯一色源”、轨道对比度和动画旧值不能无差别套用到五套设计。新增方案的接入从本目录开始。
|
||||
File diff suppressed because one or more lines are too long
+3
-3
@@ -2,9 +2,9 @@
|
||||
:root{
|
||||
--color-background:#A8BECF;
|
||||
--color-board:#F2EEE5;
|
||||
--color-board-grid:#89867D;
|
||||
--color-track:#435F78;
|
||||
--color-track-halo:#F2EEE5;
|
||||
--color-board-grid:#7C8B94;
|
||||
--color-track:#6D808B;
|
||||
--color-track-halo:#DFE3E2;
|
||||
--color-surface:#F7F6F2;
|
||||
--color-text-primary:#273B50;
|
||||
--color-text-secondary:#314A5F;
|
||||
|
||||
+4
-153
@@ -2,9 +2,9 @@
|
||||
"theme": {
|
||||
"background": "#A8BECF",
|
||||
"board": "#F2EEE5",
|
||||
"boardGrid": "#89867D",
|
||||
"track": "#435F78",
|
||||
"trackHalo": "#F2EEE5",
|
||||
"boardGrid": "#7C8B94",
|
||||
"track": "#6D808B",
|
||||
"trackHalo": "#DFE3E2",
|
||||
"surface": "#F7F6F2",
|
||||
"textPrimary": "#273B50",
|
||||
"textSecondary": "#314A5F",
|
||||
@@ -30,144 +30,6 @@
|
||||
"arrowLight": "#FFFFFF",
|
||||
"arrowDark": "#273B50"
|
||||
},
|
||||
"pigments": [
|
||||
{
|
||||
"name": "晴空蓝",
|
||||
"color": "#2392FD",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "莓果粉",
|
||||
"color": "#FC3E80",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "日光黄",
|
||||
"color": "#FDBC28",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"name": "葡萄紫",
|
||||
"color": "#874FFD",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "湖水青",
|
||||
"color": "#008B83",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "珊瑚橙",
|
||||
"color": "#EF704F",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"name": "嫩芽绿",
|
||||
"color": "#91C95B",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"name": "鸢尾蓝",
|
||||
"color": "#5267CF",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "玫瑰红",
|
||||
"color": "#C83F66",
|
||||
"arrow": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "蜜桃杏",
|
||||
"color": "#F5AA83",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"name": "冰川青",
|
||||
"color": "#58C9D5",
|
||||
"arrow": "#273B50"
|
||||
},
|
||||
{
|
||||
"name": "兰花紫",
|
||||
"color": "#AE64C7",
|
||||
"arrow": "#FFFFFF"
|
||||
}
|
||||
],
|
||||
"levelThemes": [
|
||||
{
|
||||
"id": "lagoon",
|
||||
"name": "薄荷浅湾",
|
||||
"label": "轻松",
|
||||
"range": "0–29",
|
||||
"background": "#C5E4DF",
|
||||
"ink": "#273B50",
|
||||
"palette": [
|
||||
0,
|
||||
4,
|
||||
2
|
||||
],
|
||||
"description": "冷润的浅湾,配蓝、青与一点日光黄。"
|
||||
},
|
||||
{
|
||||
"id": "apricot",
|
||||
"name": "杏色午后",
|
||||
"label": "进阶",
|
||||
"range": "30–49",
|
||||
"background": "#F1D7B8",
|
||||
"ink": "#273B50",
|
||||
"palette": [
|
||||
5,
|
||||
7,
|
||||
4,
|
||||
9
|
||||
],
|
||||
"description": "温暖杏底,以珊瑚、鸢尾蓝和湖水青平衡。"
|
||||
},
|
||||
{
|
||||
"id": "lavender",
|
||||
"name": "鸢尾花园",
|
||||
"label": "烧脑",
|
||||
"range": "50–69",
|
||||
"background": "#D8D0EB",
|
||||
"ink": "#273B50",
|
||||
"palette": [
|
||||
3,
|
||||
6,
|
||||
8,
|
||||
10
|
||||
],
|
||||
"description": "柔紫空间,用嫩芽绿与冰川青拉开层次。"
|
||||
},
|
||||
{
|
||||
"id": "rose",
|
||||
"name": "玫瑰暮色",
|
||||
"label": "挑战",
|
||||
"range": "70–100",
|
||||
"background": "#E7C3CE",
|
||||
"ink": "#273B50",
|
||||
"palette": [
|
||||
8,
|
||||
7,
|
||||
2,
|
||||
11
|
||||
],
|
||||
"description": "低饱和玫瑰底,深色棋子与日光黄形成节奏。"
|
||||
},
|
||||
{
|
||||
"id": "midnight",
|
||||
"name": "午夜极光",
|
||||
"label": "每周挑战",
|
||||
"range": "特别主题",
|
||||
"background": "#293956",
|
||||
"ink": "#F7F6F2",
|
||||
"palette": [
|
||||
10,
|
||||
11,
|
||||
2,
|
||||
1
|
||||
],
|
||||
"description": "深靛蓝舞台,冰川青、兰花紫和明亮暖色。"
|
||||
}
|
||||
],
|
||||
"surfaces": {
|
||||
"surface": "surface",
|
||||
"primary": "primary",
|
||||
@@ -196,18 +58,7 @@
|
||||
"modalMs": 420,
|
||||
"starStartMs": 300,
|
||||
"starGapMs": 190,
|
||||
"collisionMs": 800,
|
||||
"rotationMs": 240,
|
||||
"exitMsPerUnit": 120,
|
||||
"exitRampMs": 80,
|
||||
"exitMinTravelMs": 140,
|
||||
"exitMaxTravelMs": 800,
|
||||
"exitEffectMs": 180,
|
||||
"exitLongBaseMs": 550,
|
||||
"exitLongCellMs": 85,
|
||||
"exitLongMaxMs": 1700,
|
||||
"exitLongStartCells": 2,
|
||||
"exitLongFullCells": 5
|
||||
"collisionMs": 1250
|
||||
},
|
||||
"radii": {
|
||||
"control": 14,
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
# HEX TRAILS · 1000 关制作体系与难度曲线
|
||||
|
||||
讨论稿 · 2026-09-12
|
||||
|
||||
本方案以现有规则和[新版设计准则](level-design-principles-v2.md)为基础:箭头决定起步、轨道决定后续路线;底盘旋转时棋子与箭头不动;成功消除减少占用,试路和旋转免费,保留撤销与快速连点。正文保留制作前的方案与假设,不替代实际验收记录。
|
||||
|
||||
实施更新(2026-09-12):已据此制作独立 v0.5 千关首版,20 章 × 50 关。完整规则求解、每关 20 种策略、核心放行与主长路门槛已通过;原操作运行时和历史版本保留。实际配额、逐关证据、静态审阅及浏览器样本见[千关制作报告](v0.5-production-report.md)。真人连续章节试玩、熟练度曲线与长期疲劳仍未校准;客户端当前按章展示,但一次读取完整关卡模块,尚未实现按章下载。
|
||||
|
||||
**目标是让玩家持续体验“看得懂的发现、轻巧的释放、值得观看的长路和有变化的图案”。平均推理负担在中期趋稳,后半程通过组合、空间形态和释放过程持续提供新内容。**
|
||||
|
||||
下文的关数配额、难度档位、频率和检查数量均为首轮生产假设,需由基准样关、连续章节试玩和实际玩家数据校准;不是已经验证的满意度、留存或真人难度结论。
|
||||
|
||||
研究补充(2026-09-12):已完成[论文与竞品调研报告](level-design-research-report.md),并建立[关卡设计知识库](level-design-knowledge/README.md)。研究支持意图/空间共同生成、分类候选库与独立编排的方向;本文精确配额继续作为试验假设。“后期平台”应理解为目标玩家体感的校准目标,不能固定结构难度而忽略熟练度提高;花瓣关也允许空间草图与体验关系共同输入。具体论据、限制和修正见报告第 7 节。
|
||||
|
||||
## 1. 从已有实验保留什么,先改什么
|
||||
|
||||
已有成果:
|
||||
|
||||
- v0.4 的 20 关已有固定制作来源、最少旋转参考解、作者体验解、真实路径统计,以及清挡、反差和往返旋转的具体断言。参考解含 199 次消除、89 条至少 6 弯的路径;“6 弯”只是该批样关的统计口径。
|
||||
- 花形实验已证明可以先设计实际路线,再连接环带、布置棋子。其 91 格、十二瓣与三道环带有 177 段强调连接参与参考解;最长离场为 59 个格步骤、37 弯。
|
||||
- 现有模型、扫掠碰撞、求解器、反向布子、连点队列和回放能力均应复用。
|
||||
|
||||
首先修正评价与生成顺序:
|
||||
|
||||
1. `src/core.js` 的 `analyze.score` 仍把长路两项合计最多计入 34 分。当前首关 4 枚棋子全可出、无需旋转,仍得到 34 分/“进阶”。不能拿这个总分排序 1000 关。
|
||||
2. `src/experience-generator.js` 仍先随机配轨,再偏向长路径选择棋子。它适合提供布子候选,不能独自保证有形状的路线、清楚的放行关系或不同的关内节奏。
|
||||
3. 不同种子、不同布局甚至同样可解,都不代表不同体验。现在需要增加体验差异评审和整段节奏编排。
|
||||
|
||||
## 2. 每关分别记录四个维度
|
||||
|
||||
| 维度 | 真正要看什么 | 在制作中如何使用 |
|
||||
| --- | --- | --- |
|
||||
| 推理负担 | 找到下一步需要辨认什么因果;是否需要预判换路;关键关系是否跨区 | 决定难度档位和章节位置 |
|
||||
| 视觉辨认负担 | 轨道能否跟随、交叉是否清楚、阻挡是否能解释、关键棋子是否被埋没 | 决定可读性是否合格,不能当作加难奖励 |
|
||||
| 操作与播放量 | 成功点击、重复清理、空转、真实动画长度、相似路径反复播放、队列等待 | 控制单关与相邻关的疲劳 |
|
||||
| 观看与释放回报 | 长巡游的空间展开、轻巧反差、一次放开一组、图案逐步显现 | 决定本关为什么值得玩,以及什么时候兑现 |
|
||||
|
||||
四项分别记录,不重新揉成一个“质量总分”。长路长度是观赏内容和可能的跟线负担,不能自动变成推理难度。清楚的 A→B→C 不一定难;若多个合法选择效果等价,也不能把选择多当作深推理。
|
||||
|
||||
求解器的状态数、最少旋转数、释放波次只作结构诊断。难度档位先用基准关对照判断,再用同类玩家的实际表现校准。
|
||||
|
||||
## 3. 难度档位与 1000 关总体分布
|
||||
|
||||
| 档位 | 预期体验 | 初始预算 |
|
||||
| --- | --- | ---: |
|
||||
| D1 | 看见就能启动;可以有很丰富的长绕行 | 150 |
|
||||
| D2 | 找一个清楚的挡子,或理解一次直接换路 | 350 |
|
||||
| D3 | 组合两段熟悉关系,例如清挡后换路、不同区域依次放行 | 350 |
|
||||
| D4 | 少量跨区关系或旋转选择,需要主动观察,但关键变化可解释 | 130 |
|
||||
| D5 | 少量后期综合挑战;判断更深入,仍保持线索、试路与可恢复性 | 20 |
|
||||
| 合计 | 轻松约 50%,适中约 35%,挑战约 15% | 1000 |
|
||||
|
||||
这是内容预算,不要求把每个候选强行塞入某档。若实际试玩与设计评级不一致,重排、修改或淘汰候选。
|
||||
|
||||
**全程保留轻松关。第 800 关的玩家仍应经常获得“我已经很熟练,轻轻一动就通了”的体验。第 1000 关可以是漂亮的庆祝关,不要求它成为最难的一关。**
|
||||
|
||||
### 五个制作阶段
|
||||
|
||||
采用 20 章 × 50 关管理,每章内部使用长度错开的 6–10 关小段。章节有主要路线语汇,但需交叉使用多种形态,不连续做 50 关同一朵花。
|
||||
|
||||
| 范围 | 主要内容进展 | 难度方向 |
|
||||
| --- | --- | --- |
|
||||
| 1–50 | 建立点击、转弯、交叉不换轨、清挡和转盘的直觉;前 10 关就看到长巡游、轻巧反差与有层次的图案 | D1–D2 为主,一次突出一个理解点 |
|
||||
| 51–200 | 熟练区分箭头与出口,理解一枚让一组、清挡再转、简单分段释放 | 逐步增加 D3,少量 D4 |
|
||||
| 201–500 | 跨区连接、内外层穿行、转过去再回来、多个熟悉结构组合 | 推理基线缓慢增加,保留大量舒缓内容 |
|
||||
| 501–800 | 用不同路线形态和不同放行时机重组熟悉规则;加强作品关 | 平均负担趋稳,少量 D5 |
|
||||
| 801–1000 | 熟练感、旧主题的新连接、跨主题组合与阶段庆祝 | 主要增加内容变化,保持难度平台 |
|
||||
|
||||
预算展开如下,用于检查前后期是否真的有变化,而非作为发布前的机械排号规则:
|
||||
|
||||
| 范围 | D1 | D2 | D3 | D4 | D5 | 合计 |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||
| 1–50 | 25 | 20 | 5 | 0 | 0 | 50 |
|
||||
| 51–200 | 30 | 60 | 50 | 10 | 0 | 150 |
|
||||
| 201–500 | 35 | 110 | 115 | 40 | 0 | 300 |
|
||||
| 501–800 | 35 | 100 | 110 | 45 | 10 | 300 |
|
||||
| 801–1000 | 25 | 60 | 70 | 35 | 10 | 200 |
|
||||
| 合计 | 150 | 350 | 350 | 130 | 20 | 1000 |
|
||||
|
||||
### 小段曲线示例
|
||||
|
||||
一个成熟期十关片段可以是:
|
||||
|
||||
**D2 → D2 → D3 → D3 → D2 → D3 → D4 → D1 → D3 → D2**
|
||||
|
||||
| 相对关位 | 主体验 | 推理档 |
|
||||
| --- | --- | --- |
|
||||
| 1 | 熟悉入口,直接放出一条跨盘长路 | D2 |
|
||||
| 2 | 朝内起步却能沿轨直接出去,兑现路径反差 | D2 |
|
||||
| 3 | 理解两个区域的占用关系,分别让路后释放内层长路 | D3 |
|
||||
| 4 | 清理一侧后换路,让另一侧开始放行 | D3 |
|
||||
| 5 | 路线有层次的花纹关,关键动作很少 | D2 |
|
||||
| 6 | 回访熟悉形态,但关键挡子换到另一区域 | D3 |
|
||||
| 7 | 两个区域的因果关系组合成局部挑战 | D4 |
|
||||
| 8 | 出口大方开放,轻松观看长巡游 | D1 |
|
||||
| 9 | 转到另一侧清挡、再转回来,放出朝内目标 | D3 |
|
||||
| 10 | 图案逐步展开,以顺畅巡游收束 | D2 |
|
||||
|
||||
第 7 关的推理高点之后,第 8 关立即减轻判断;第 10 关的观赏高潮无需同时成为难度高潮。不同小段要改变峰值位置、长度、释放方式和形态,不能让玩家猜到“每第七关一定难”。
|
||||
|
||||
示例中的 D3 意图是让玩家理解组合关系;若实际画面使动作一眼明确、无需组合判断,试玩后应下调档位,不能仅因转了两次或长路较多坚持评为 D3。
|
||||
|
||||
## 4. 内容预算:体验主角与路线形态分开安排
|
||||
|
||||
每关只设一个主体验,其他爽点作为辅助。首轮 1000 关预算:
|
||||
|
||||
| 主体验 | 关数 | 主要任务 |
|
||||
| --- | ---: | --- |
|
||||
| 直接巡游 | 240 | 让长路本身成为可立即获得的奖励 |
|
||||
| 清挡放行 | 260 | 移走关键棋子,清楚地放出后续长路或一组棋子 |
|
||||
| 轻巧反差 | 220 | 用很少的动作解决第一眼觉得棘手的目标 |
|
||||
| 旋转换路与分段释放 | 180 | 改变出路关系,交替清理与观看 |
|
||||
| 综合收束 | 100 | 组合已学内容,组织完整开局、中段和漂亮收尾 |
|
||||
| 合计 | 1000 | |
|
||||
|
||||
形态、长路和旋转是可重叠标签,不与上述主体验类别相加。初始目标为:
|
||||
|
||||
- 约 800 关包含至少一段经过实际回放审阅、值得跟随的长巡游。按路线家族制定制作带,不统一用“≥6 弯”或“≥18 弯”判断全部内容。
|
||||
- 约 200 关具有可辨认的花瓣、环纹、星芒、编织或其他有秩序的路线图案;其中约 60 关作为重点精修作品,其余融入日常关卡。
|
||||
- 约 600 关让旋转承担实际放行作用。旋转角色应变化,不给每关硬凑转数。
|
||||
- 轻巧反差除作为 220 关的主角,也可以出现在其他类型的中段或收尾。
|
||||
|
||||
这些标签不能仅由作者声明。长路需要实际行驶证据,反差需要改变前后的路线证据,图案需要完整画面与实际路线参与证据。
|
||||
|
||||
### 长路怎样不腻
|
||||
|
||||
轮换绕中心、横跨棋盘、内外层穿梭、左右区域交换、花瓣往返等空间过程。关注整关路线分布与重复覆盖,不能只追求单条最大弯数。
|
||||
|
||||
一关可以用少量主角长路配若干有用的短出口。短路负责开局、让路和即时反馈;无需每枚都走最长路线。轻松巡游关则可以让多条各有观感的路线直接畅通。
|
||||
|
||||
保留完整行驶与原游戏速度逻辑。若连续点选后出现疲劳,先审查是否把相同长路重复过多、是否缺少新的放行变化,再讨论交互;不要把动画时间一概当作等待,也不要用慢放增加内容长度。
|
||||
|
||||
### 反差怎样不变成公式
|
||||
|
||||
至少轮换以下来源:朝内却直接出去;中央棋子比边缘棋子容易释放;外表复杂的图案只需一个关键动作;清掉一枚后整组畅通;旋转一次接上另一侧出口。
|
||||
|
||||
简单动作后立即兑现目标。若还要清三层阻挡,就不应把该目标作为“轻巧反差”宣传。
|
||||
|
||||
玩家学会“一转就出”后,再遇相同关系可能主要获得熟练感。这个内容仍有价值,但应按复习或舒缓编排,不能把重复套路持续算作新惊喜。
|
||||
|
||||
### 图案怎样承担不同玩法
|
||||
|
||||
同样的重瓣花语汇可以形成不同作品,但必须重新设计路线连接和放行关系:
|
||||
|
||||
| 花形变体意图 | 关键动作 | 玩家实际看到什么 |
|
||||
| --- | --- | --- |
|
||||
| 舒缓巡游 | 少量棋子直接启动 | 从内层沿不同花瓣向外展开 |
|
||||
| 清挡放行 | 一个短出口先让开 | 花心中的目标穿过内外层长路 |
|
||||
| 轻巧反差 | 一次旋转后点朝内棋子 | 起步方向未变,却从另一片花瓣绕出 |
|
||||
| 分段组合 | 清一侧、换路、再放另一侧 | 花纹逐段显现,最后顺畅收束 |
|
||||
|
||||
早期图案可以维持丰富、有秩序的路线,通过减少需要判断的阻挡关系降低难度,不必退回稀疏的几根花瓣线。后期图案也不默认增加棋子数量或让人盲目跟线。
|
||||
|
||||
## 5. 把生成器升级为按体验制作
|
||||
|
||||
目标流程:
|
||||
|
||||
**制作卡 → 路线与放行骨架 → 约束构造与反向布子 → 补齐轨道 → 自动验证与多策略回放 → 差异筛选 → 章节编排 → 试玩校准。**
|
||||
|
||||
### 5.1 制作卡必须先于种子
|
||||
|
||||
每张卡至少说明:
|
||||
|
||||
- 主体验、目标难度、路线家族、章节角色。
|
||||
- 关键棋子是谁,第一眼预期是什么。
|
||||
- 哪个点击或旋转改变谁的出路。
|
||||
- 奖励在开局、中段还是收尾发生。
|
||||
- 哪些长路、哪些连接必须保留。
|
||||
- 和相邻关、同一母版前例有什么实质区别。
|
||||
|
||||
示例:“中期 D2;重瓣图案;外侧短出口释放一枚朝内目标;目标沿内外花瓣离场;关键奖励在前半段兑现;其余棋子提供顺畅收尾。”
|
||||
|
||||
### 5.2 先设计运动与因果,再求具体布局
|
||||
|
||||
把路线构造与棋子布置拆成可协作的两部分:路线决定形态和运动内容;放行骨架决定清挡、旋转和阶段关系。先保留关键端口和出口,再用约束搜索、反向布子和局部修改找到可实现布局;无法实现就改卡或换结构,不在后面编造标签。
|
||||
|
||||
常用放行结构包括独立出口、一枚让一条、一枚让一组、多个区域分别放行、换向连接、去一侧清理再返回。不同结构可以组合,但不把清楚的因果链简单计成难度。
|
||||
|
||||
图案应优先做在真实轨道内部。现有全盘旋转要求底格集合旋转后仍然合法,不能任意裁成轮廓而破坏规则。颜色和装饰不参与路线规则。
|
||||
|
||||
反向布子时保存完整的构造解,再用求解器和实际回放交叉核验。补齐剩余端口时保持完整配对,并重新检查是否改变主路径、形成意外闭环或引入难解释的碰撞。
|
||||
|
||||
### 5.3 用路线家族和体验母版支撑数量
|
||||
|
||||
先验证约 8–12 类路线构造方式,例如回廊、中心绕行、双区穿梭、内外环带、回折、编织、放射、单瓣/重瓣、波纹和左右镜像图形。每类再形成不同放行关系和节奏的体验母版。
|
||||
|
||||
中期目标是积累约 60–80 套经过审阅的体验母版,探索多个有效变体。不要规定每套必须产出同样数量;母版没有新变化就停,数量缺口用新增结构补齐。
|
||||
|
||||
一个变体至少需要改变两个影响体验的维度,其中至少一个涉及真实路线组织或放行关系。只改颜色、名称、镜像、全局旋转,或添加几枚无作用的直出棋子,不算充分的新内容。
|
||||
|
||||
### 5.4 候选池按类别竞争
|
||||
|
||||
按“主体验 × 推理档 × 路线家族 × 释放阶段”保留不同候选,各自在相近类别中比较清晰度和回报。不要按一个全局分数取前 1000 名,否则容易留下大量相同风格的长路关。
|
||||
|
||||
对每个目标位置可以从数十个候选开始搜索,记录通过率、淘汰原因和计算成本。稀缺类别扩充路线模板;候选不足时不降低正确性、可读性和体验门槛。是否需要上百个候选,以实际产率决定。
|
||||
|
||||
## 6. 去重与防疲劳
|
||||
|
||||
两层一起做:
|
||||
|
||||
1. **布局去重。** 忽略名称、ID、颜色,将整局场景连同棋子、箭头一起旋转/镜像归一。仅转底盘会改变玩法,不能因此把两个不同状态当作同一个布局。
|
||||
2. **体验近似检查。** 比较关键放行关系、成功路径形态、旋转节奏、开局入口、关键奖励出现时机,以及完整行驶的重复程度。
|
||||
|
||||
编排初始规则:同一关键套路不连续用三关;同一具体母版的近似变体初始间隔约 30 关;刻意的教学重复在制作卡中说明目的。这些规则需随试玩调整,不能替代连续游玩评审。
|
||||
|
||||
每 50 关都要回答:这一章增加了什么可感知的新内容?哪些关虽然布局不同,却玩起来相同?若回答不清楚,该批次尚未完成。
|
||||
|
||||
## 7. 四道入库验收
|
||||
|
||||
### A. 规则正确性:全部 1000 关覆盖
|
||||
|
||||
格式、端口、旋转坐标合法;完整构造解与参考解回放通关;实际扫掠碰撞、交叉不换轨、撤销、免费试路和连点一致。搜索到上限只能记录为未确定,不能当作困难但已验证。
|
||||
|
||||
对替代合法操作检查仍可继续完成。当前规则下成功消除只减少占用、旋转可恢复,不能人为制造“正确消除后反而无解”的惩罚。
|
||||
|
||||
### B. 体验证据:全部 1000 关覆盖
|
||||
|
||||
记录实际成功路径的几何长度、格步骤、转弯与空间展开;记录清挡和旋转改变了谁的出路;记录主奖励出现阶段。图案关检查强调连接的参与情况与闭环,不能由装饰线撑起形状。
|
||||
|
||||
检查第一段回报是否过晚、收尾是否重复、反差目标是否兑现。记录完整播放量和相似路径重复度,不能只看最大长路。
|
||||
|
||||
### C. 自然玩法覆盖与差异:全部 1000 关覆盖
|
||||
|
||||
为外圈优先、短路优先、长路优先、较早旋转、顺着局部连续点选等代表策略做回放,并加入随机扰动。初始按每关至少 20 轮设计检查量;新母版、图案、挑战和异常关加密检查。
|
||||
|
||||
除了通关,还要统计这些策略是否仍能看到主长路和关键放行。若关键奖励只存在于作者指定顺序中,修改布局、调整奖励位置或重新归类。可先把约 80% 代表回放能遇到主奖励作为复审参考线,待样关确认;这不是对真实玩家曝光率的保证。
|
||||
|
||||
对关键转盘前后、可能发生格外接触的区域进行额外检查。抽样覆盖必须标明范围,不能宣称穷尽全部玩家行为。
|
||||
|
||||
### D. 人工审阅与真人校准
|
||||
|
||||
每关都应有画面/回放审阅记录;所有新母版、重点图案和挑战关要完整手玩,常规变体做分层实玩抽检,章节要连续试玩。
|
||||
|
||||
真人测试重点关注是否愿意跟完路线、是否理解放行因果、是否认出图案、反差是否成立、连续几关是否感到重复。不能把“全部自动通过”表述为“全部已证明好玩”。
|
||||
|
||||
首轮可以用小规模新手与熟练玩家发现明显问题;样本充足后再估难度和行为分布。记录主动思考、路线动画、错误原因、空转、提示与重开、退出位置,并按玩家熟练度和设备区分。初期不统一给全体关卡设定未经标定的通关秒数或成功率门槛。
|
||||
|
||||
## 8. 量产工具与稳定运行
|
||||
|
||||
制作侧需要一张可筛选的关卡总表:缩略图、体验卡、难度档、实际路线摘要、参考解、替代策略报告、近似关、审阅状态、版本信息。支持直接观看关键放行前后与整段回放,减少在 JSON 和游戏界面之间来回查找。
|
||||
|
||||
所有关卡使用同一套运行时、输入、连点、碰撞、动画与撤销。不同图案作为数据与绘制配置,不另写不同的操作逻辑。
|
||||
|
||||
发布包应冻结关卡快照,并保留关卡稳定 ID、关卡修订号、规则/生成器/模板版本、种子与制作参数。仅保存种子不能保证生成器更新后仍生成同一关。序号与稳定 ID 分开,更新已发布关卡时检查存档兼容。
|
||||
|
||||
生成和筛选离线完成,客户端按章节加载已验证数据;不让玩家进入每一关时等待大规模生成或求解。棋盘大小由手机可点性、可读性和体验需要决定,当前引擎最大 127 格是边界,不是后期制作目标。
|
||||
|
||||
## 9. 实施顺序与完成标准
|
||||
|
||||
| 阶段 | 具体产出 | 继续扩量的前提 |
|
||||
| --- | --- | --- |
|
||||
| 50 个基准样关 | 覆盖不同体验、形态和难度,含后期候选;不等同于主线前 50 关 | 分离难度与回报的评价成立,新母版能兑现制作卡 |
|
||||
| 完整前 100 关 | 两个连续章节、稳定制作卡和审阅工具 | 教学、反差、长路和难关后释放在连续试玩中成立 |
|
||||
| 扩到 300 关 | 扩充母版、自动验证与差异检查 | 常规生成产率可接受,不能靠几个模板反复填数 |
|
||||
| 扩到 600 关 | 验证成熟期的平台曲线与跨章变化 | 熟练玩家在多次游玩后仍能感到变化,播放量没有持续疲劳 |
|
||||
| 扩到 1000 关 | 按每 50 关完成验收包,组织后期回访与最终庆祝 | 全部规则与体验证据齐全,逐关审阅、分层试玩和整段节奏检查完成 |
|
||||
|
||||
先完成评价拆分、路线/放行骨架、差异筛选和统一运行时这几项生产能力,再扩大布局数量。整套工程量和候选倍率应在首批样关测量后估算,不以“生成 1000 个文件很快”推断 1000 个关卡的制作成本。
|
||||
|
||||
初始讨论阶段的产出是制作方案;目前已经完成可玩千关首版。本文中的真人校准、连续长线体验和满意度目标仍需实测,不能仅凭首版数量与自动通过宣称全部成立。
|
||||
|
||||
## 10. 方法参考与项目依据
|
||||
|
||||
以设计者预先定义的目标组织具体空间结构,可参考 [Mixed-Initiative Design of Game Levels: Integrating Mission and Space into Level Generation](https://research.hva.nl/en/publications/mixed-initiative-design-of-game-levels-integrating-mission-and-sp/)。保留多个不同类型的优质候选、在相近类别中比较,而不是只优化单一总分,可参考 [Procedural Content Generation through Quality Diversity](https://antoniosliapis.com/articles/pcgqd.php)。本项目先采用可解释的约束构造和分类候选池,无需为了使用这些思路先引入强化学习系统。
|
||||
|
||||
上述研究提供方法参考,不证明本文配额、难度曲线或 HEX TRAILS 的玩家体验已经成立。项目自身依据为 [新版准则](level-design-principles-v2.md)、[v0.4 回放报告](v0.4-experience-review.md)、[花形实验](flower-study.md)、[生成器](../src/experience-generator.js)、[规则与评分](../src/core.js)及对应测试。
|
||||
@@ -1,267 +0,0 @@
|
||||
# HEX TRAILS 美术方向与制作简报
|
||||
|
||||
> 历史简报,保留 2026-09-11 的核查背景。当前五套主游戏设计的 Agent 入口已整理到 [design/README.md](../design/README.md),规则见 [shared.md](../design/shared.md) 与各套 design.md,数值见对应 tokens.json。下文“唯一数值来源”、数量、时序和设计债描述可能属于旧快照,不应覆盖当前五套方案的独立规则。
|
||||
|
||||
版本:2026-09-11。本文面向承担本项目**美术设计**工作的会话或成员,说明角色边界、设计系统事实、改色与素材流程、已知设计债,以及三条工作线的入手点。
|
||||
|
||||
本文是**工作简报**,不是设计规范本身。数值与规则的唯一来源仍是 `src/design-tokens.js` 与 [Design.md](../Design.md);本文负责把"怎么改、别踩什么、先做什么"讲清楚。
|
||||
|
||||
---
|
||||
|
||||
## 1. 角色边界
|
||||
|
||||
**职责**
|
||||
|
||||
- 配色、主题、图标、动效时长、布局与响应式表现
|
||||
- 素材生成与裁切:图集、图标、背景,以及 `src/sprites.js` / `src/ui-skin.js` 中的裁切框
|
||||
- 设计规范与生成产物的一致性:`Design.md` / `Design.html` / `design/*` / `assets/ui-surfaces.png`
|
||||
- 视觉验收:改动后提供实机证据,而不只是"测试通过"
|
||||
- 原生端视觉对齐:`cocos/`、`wechat/HexTrail/`
|
||||
|
||||
**不做**
|
||||
|
||||
- 不修改玩法规则、求解器、碰撞数学(`src/core.js`、`src/path-math.js`)
|
||||
- 不修改关卡布局与生成参数(`levels/*-seeds.json`、生成脚本)
|
||||
- 不静默替换已接受的素材,不另写一套 HEX,不用滤镜临时拼配色(见 [Design.md](../Design.md) §3.5)
|
||||
|
||||
**前置阅读**:[Design.md](../Design.md)(设计规范全文)· [cocos-port.md](cocos-port.md)(移植约束)· [level-design-principles-v2.md](level-design-principles-v2.md)(了解产品方向,避免设计脱离玩法)
|
||||
|
||||
---
|
||||
|
||||
## 2. 设计系统事实(当前状态)
|
||||
|
||||
### 2.1 单一来源
|
||||
|
||||
`src/design-tokens.js`(80 行)是颜色、字体、动效、圆角的**唯一数值来源**。
|
||||
|
||||
| 导出 | 内容 | 规模 |
|
||||
| --- | --- | --- |
|
||||
| `THEME` | 语义角色 | 30 个 |
|
||||
| `SURFACES` | 面板角色(对应 `ui-surfaces.png` 的色块) | 13 个 |
|
||||
| `PIGMENTS` | 棋子色库,箭头色按对比度自动选白/深蓝灰 | 12 色 |
|
||||
| `LEVEL_THEMES` | 场景主题,按难度分数选取 | 5 套 |
|
||||
| `TYPOGRAPHY` | level 28 / moves 32 / dialogTitle 24 / body 14 / label 12 / caption 11 | 6 档 |
|
||||
| `MOTION` | 动效时长,见 §6 债务 D3 | 17 项 |
|
||||
| `RADII` | control 14 / dialog 24 / small 8 | 3 档 |
|
||||
|
||||
### 2.2 主题按难度分数选取
|
||||
|
||||
`themeForScore(score)` 的分档与 `analyze().label` **同构**(已穷举 0–120 分及 140 关实测,零不一致):
|
||||
|
||||
| 分数 | 标签 | 主题 | 背景 | 棋子搭配 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 0–29 | 轻松 | 薄荷浅湾 lagoon | `#C5E4DF` | 晴空蓝、湖水青、日光黄 |
|
||||
| 30–49 | 进阶 | 杏色午后 apricot | `#F1D7B8` | 珊瑚橙、鸢尾蓝、湖水青、蜜桃杏 |
|
||||
| 50–69 | 烧脑 | 鸢尾花园 lavender | `#D8D0EB` | 葡萄紫、嫩芽绿、玫瑰红、冰川青 |
|
||||
| 70–100 | 挑战 | 玫瑰暮色 rose | `#E7C3CE` | 玫瑰红、鸢尾蓝、日光黄、兰花紫 |
|
||||
| 特别主题 | 每周挑战 | 午夜极光 midnight | `#293956` | 冰川青、兰花紫、日光黄、莓果粉 |
|
||||
|
||||
**`midnight` 不被 `themeForScore` 返回**,只能通过 `?theme=midnight` 或 showcase 进入。周赛功能尚未接入([Design.md](../Design.md) 已声明)。
|
||||
|
||||
### 2.3 取色机制(容易搞错)
|
||||
|
||||
`src/renderer.js:23` 取的是**棋子序号**,不是棋子自带的 `color` 字段:
|
||||
|
||||
```js
|
||||
pigmentIndex(state.theme
|
||||
? Math.max(0, level.tiles.findIndex(t => t.id === tile.id)) // 棋子序号
|
||||
: tile.color, state.theme) // 仅 edit/trial 用 color
|
||||
```
|
||||
|
||||
因此主线是**调色板循环分配**:20 枚棋子、7 色主题 → 只有 7 种颜色,多枚同色是设计如此。换来的是 `Design.md` 承诺的稳定性:**移走棋子、旋转、撤销都不会让剩余棋子变色**(已端到端验证,逐棋子变化数 0)。
|
||||
|
||||
**图集只有 4 帧**(`TILE_FRAMES`),palette 索引 ≥4 时会降级为纯色多边形绘制。这是 `CanvasPainter.sprite()` 返回 `false` 触发的正常降级路径,不是错误。
|
||||
|
||||
---
|
||||
|
||||
## 3. 改色工作流
|
||||
|
||||
**只有这一条路**:改 `src/design-tokens.js` → 重新生成 → 检查产物 → 跑测试。
|
||||
|
||||
```bash
|
||||
# 1. 改 src/design-tokens.js
|
||||
# 2. 重新生成设计产物
|
||||
npm run design # = build-design.mjs + build-design-guide.mjs
|
||||
# 3. 检查产物与对比度报告
|
||||
npm test # 107 项,含 design.test.js / themes.test.js
|
||||
npm run build # 全量构建;对比度有失败会 exitCode=1
|
||||
```
|
||||
|
||||
`npm run design` 会重写这些文件:
|
||||
|
||||
| 产物 | 内容 |
|
||||
| --- | --- |
|
||||
| `design/tokens.css` | kebab 命名 CSS 变量 |
|
||||
| `design/tokens.json` | theme / pigments / levelThemes / surfaces / typography / motion / radii |
|
||||
| `assets/ui-surfaces.png` | **由脚本手写 PNG 编码器**烘出的 13 个 32×32 纯色块 |
|
||||
| `design/contrast-report.json` | 33 项对比度校验结果 |
|
||||
| `Design.html` | 2.6MB 单文件离线手册,内嵌图集 base64 与 SVG 复刻的棋盘示例 |
|
||||
|
||||
**对比度有三道校验**:构建脚本(失败 `exitCode=1`)、`tests/design.test.js`、`tests/themes.test.js`。
|
||||
|
||||
**注意 `npm run build` 不生成设计产物**,它只调用 `levels:versions → levels:v04 → design → build.mjs`,其中 `build.mjs` 仅把文件复制进 `dist/`。所以改色必须**单独跑 `npm run design`**。
|
||||
|
||||
---
|
||||
|
||||
## 4. 素材管线
|
||||
|
||||
### 4.1 当前使用中的素材
|
||||
|
||||
| 用途 | 文件 | 规格 |
|
||||
| --- | --- | --- |
|
||||
| 棋子图集 | `assets/tiles-matte-clean-v8.png` | 1293×1216,RGB 无 alpha |
|
||||
| 图标图集 | `assets/ui-icons-generated.png` | 1254×1254,16 个图标 |
|
||||
| 面板色块 | `assets/ui-surfaces.png` | 416×32,**生成物**,勿手改 |
|
||||
|
||||
### 4.2 裁切框是代码,不是图片
|
||||
|
||||
- 棋子:`src/sprites.js` 的 `TILE_FRAMES`(4 个 `540×465` 框)+ `src/tile-shape.js` 的 `tileSample()`(取每框**中央 20%**)与 `roundedHex()`(顶点内缩 7.5%)
|
||||
- 图标:`src/ui-skin.js` 的 `ICONS`(16 个**手写光学中心** bounds,扩成正方形 +12px 留白)
|
||||
|
||||
**图片只能在原图不透明、无杂点的区域采样。** `tiles-matte-clean-v8.png` 之所以叫 "clean",就是因为 `assets/GENERATION.md` 记录**两次边缘杂点清理尝试均失败**(其中一次产出不透明棋盘格),最终改为只采样中央干净色块。改动裁切框前先读那份记录。
|
||||
|
||||
### 4.3 生成流程与提示词
|
||||
|
||||
`assets/GENERATION.md` 保存完整生成史;提示词档案为 `assets/prompt-v4/v6/v7/v8.txt`、`assets/prompts-v3.json`。历史素材(`tiles-candy-v2/v3/v4`、`tiles-matte-v5/v6/v7`、`ui-icons.png`、`ui-panels.png`、`board-tray.png`、`background-candy-v2.png`、`logo-candy-v2.png`)保留但不用于当前界面;`ui-icons-flat.png` 是代码重绘版,**明确不再引用**。
|
||||
|
||||
**产出新素材的规则**:原始 PNG 不做脚本像素修改;替换已接受的素材要明确告知用户来源与变化,并同步更新 `Design.md` §5 的资产表。
|
||||
|
||||
---
|
||||
|
||||
## 5. 三条工作线与入手点
|
||||
|
||||
### 5.1 打磨现有界面(优先级最高的具体项见 §6)
|
||||
|
||||
改视觉前先确认改的是**语义角色**而不是某个具体位置。`Design.md` §8 的流程要求:明确角色 → 改 token → `npm run design` → 检查产物 → `npm test` / `npm run build` → 五套背景逐一检查。
|
||||
|
||||
响应式要点:竖屏 390×844 为主线,较矮屏幕需纵向滚动;点击区至少 44×44;棋盘支持 1–4 倍缩放与双指手势。
|
||||
|
||||
### 5.2 产出新素材
|
||||
|
||||
先读 `assets/GENERATION.md` 了解既有提示词的措辞风格与失败教训,再决定是否需要新素材。**优先复用现有图集**——`ui-surfaces.png` 是生成的,改 token 即可变色,不需要新图片。
|
||||
|
||||
### 5.3 为微信 / Cocos 移植准备视觉资产
|
||||
|
||||
**现状**:`wechat/HexTrail/` 是 Cocos Creator 3.8.8 **空壳工程**(`assets/` 只有 `.gitkeep`,无场景无脚本);`cocos/HexTrailsBoard.ts` 是适配示例,**未运行场景、未做 Android/iOS 构建**。
|
||||
|
||||
移植的视觉契约是:**Cocos 读取同一份 JSON/JS token 和 PNG,不得在原生侧另外猜颜色**([Design.md](../Design.md) §8)。`CandyUiSkin` 用纯色 Sprite + 圆角 Mask + 居中图标实现。
|
||||
|
||||
**已知会阻塞移植的两项**(详见 §6 D1、D2):复制清单漏文件会导致 import 失败;原生端硬编码的动效时长与网页现行模型不一致。
|
||||
|
||||
---
|
||||
|
||||
## 6. 已知设计债(按入手价值排序)
|
||||
|
||||
> 以下均为**实测复核过**的结论,不是推测。修复它们不需要改动玩法或关卡数据。
|
||||
|
||||
### D1 · 移植复制清单漏 `src/exit-animation.js`(会直接报错)
|
||||
|
||||
`docs/cocos-port.md` 的复制清单列了 `collision-animation.js`,但 `src/renderer.js:1` 直接 `import { exitTiming, smoothMotion, travelProgress } from './exit-animation.js'`。**照清单复制 → import 失败。**
|
||||
|
||||
### D2 · 原生端硬编码动效时长,与网页不一致
|
||||
|
||||
| 项 | 网页(`MOTION`) | Cocos(`HexTrailsBoard.ts`) |
|
||||
| --- | --- | --- |
|
||||
| 离场 | `120ms/单位 + ramp≤80 + 180ms 收束` | `Math.min(1.7, 0.55 + steps*0.085)`(:117) |
|
||||
| 碰撞 | `800ms` | `1.25`(:120) |
|
||||
| 旋转 | `240ms` | `0.42`(:138) |
|
||||
|
||||
`HexTrailsBoard.ts` **完全没有 import `MOTION`**。另外它的 `redraw()` 只传 `{path, hint, animation, boardAngle}`,缺 `theme / reduced / queued / shake / selected` —— 原生端因此**没有主题配色、没有 `prefers-reduced-motion` 分支、没有连点紫环反馈**。
|
||||
|
||||
### D3 · `MOTION` 有 7 个死 token
|
||||
|
||||
`exitMinTravelMs`、`exitMaxTravelMs`、`exitLongBaseMs`、`exitLongCellMs`、`exitLongMaxMs`、`exitLongStartCells`、`exitLongFullCells` —— 在 `design-tokens.js` 之外**引用数均为 0**,但仍在导出给原生端。
|
||||
|
||||
**根因**:提交 `e92cccb` 把 `exitTiming` 从"clamp 140–800ms + 长路混合曲线"换成了纯路径长度模型,没有清理 token、没有同步文档与适配器。
|
||||
|
||||
### D4 · `Design.md` 两处数字错误
|
||||
|
||||
- **§7 离场(`Design.md:166`)**:写的是**已废弃的模型**("每单位 60ms、滑行段限 140–800ms、5 格及以上 550ms+85ms/格、最长 1700ms")。实际是 **120ms/单位、无任何 clamp**。`tests/themes.test.js` 的断言(120ms、"without a duration cap")是对的,文档是错的。
|
||||
- **§8 对比度(`Design.md:175`)**:写"轨道/底板约 **3.55:1**",实测 `contrast(track, board) = **5.7636**`。源码里没有任何一对等于 3.55。
|
||||
**连带问题**:`Design.html` **自相矛盾** —— 生成表格(:43)写 5.76,正文(:105)与内嵌 JSON(:114)写 3.55。改 `Design.md` 后重跑 `npm run design` 即可一并消除。
|
||||
|
||||
### D5 · 棋子面 vs 棋盘:12 色中 7 色低于 3:1(**未声明的覆盖缺口**)
|
||||
|
||||
`CONTRAST_PAIRS` 的 33 项**没有校验棋子面与它实际相邻的颜色**。而 `renderer.js:44` 把所有格子统一画成 `THEME.board`(`#F2EEE5`),`drawTile()` 只填纯色、**无描边** —— 棋子的真实相邻面是**棋盘**,不是主题背景。
|
||||
|
||||
| 棋子色 | vs 棋盘 `#F2EEE5` |
|
||||
| --- | --- |
|
||||
| 日光黄 `#FDBC28` | 1.4626 |
|
||||
| 蜜桃杏 `#F5AA83` | 1.6548 |
|
||||
| 冰川青 `#58C9D5` | 1.6902 |
|
||||
| 嫩芽绿 `#91C95B` | 1.6935 |
|
||||
| 珊瑚橙 `#EF704F` | 2.5542 |
|
||||
| 晴空蓝 `#2392FD` | 2.7474 |
|
||||
| 莓果粉 `#FC3E80` | 2.9539 |
|
||||
|
||||
**诚实定性**:项目从未声明过这条要求,所以这是**未声明的缺口**而非违约。缓解因素是每枚棋子上都有 ≥3:1 的箭头(已证实),且颜色不参与玩法。**最坏后果是"棋子面与棋盘融在一起、只剩箭头悬空"。** 是否补描边、调棋盘底色、还是明确声明"不承诺此项",属设计决策,需与用户确认后再动。
|
||||
|
||||
### D6 · `style.css` 旧色板与 token 脱钩
|
||||
|
||||
`style.css` 仍是旧的薰衣草紫体系(`--purple:#8772ed`、`--line:#d4d9f0`、`--muted:#8c94b3`),**`var(--color-*)` 引用数为 0**。当前靠 `design/components.css` **后加载**(元素选择器同特异性下后者胜出)+ 7 处 `!important` 覆盖。
|
||||
|
||||
仍未被覆盖的硬编码包括 `.rotate-button.hinted{outline:4px solid #ffd667}`、dialog/metric 的旧灰紫(`#8d9abb`、`#95a1c0`)。
|
||||
|
||||
### D7 · `components.css` 星光辉光违反本项目自己的禁令
|
||||
|
||||
```css
|
||||
.result-emblem .ui-icon[data-icon="star"]{
|
||||
filter:brightness(0) saturate(100%) invert(79%) sepia(85%) saturate(1450%) ...}
|
||||
```
|
||||
|
||||
硬编码了 `#c88b2380`、`#ffd45c99`、`#ffe8a366` 并用 `brightness/invert/saturate` 滤镜链调色 —— 直接违反 `Design.md` §3.5「**禁止**用 `brightness / invert / saturate` 临时调面板色」与「`src/design-tokens.js` 是颜色数值的唯一来源」。同一规则复制在 `design/guide-template.html:19`。
|
||||
|
||||
### D8 · 两处冗余配对与小余量
|
||||
|
||||
- `CONTRAST_PAIRS` 里"轨道/棋盘"与"轨道/浅色外缘"**实为同一项**(`trackHalo === board === #F2EEE5`),是冗余校验
|
||||
- 最紧的两项:分格/棋盘 **+0.1434**、箭头/晴空蓝 **+0.1811**
|
||||
- **脆弱点**:珊瑚橙的白箭头比值 **2.9574**,只比阈值低 **0.0426** —— 阈值若降到 2.95 就会选白箭头并跌破 3:1(当前判定正确)
|
||||
|
||||
### D9 · lagoon 裸主题色板碰撞(当前发行路径不可达)
|
||||
|
||||
`LEVEL_THEMES[0]` 的 `palette` 只有 3 项 `[0,4,2]`,`pigmentIndex` 取模后 `[0,1,2,3] → [0,4,2,0]`,**colour 0 与 3 都是晴空蓝**。`tests/themes.test.js` 只断言 palette 长度 3–4,测不出来。
|
||||
|
||||
**当前不可达**:`app.js` 播放态总是先过 `themeWithColors()`(补足到 4/7/9/12)。属潜在缺陷,改动主题时注意。
|
||||
|
||||
---
|
||||
|
||||
## 7. 视觉验收
|
||||
|
||||
**自动测试不能替代视觉验收。** 现有测试是"测试全绿但覆盖不到视觉"的典型 —— §6 的 D5、D7、D8、D9 **都没有测试保护**,所以"107 项通过"不构成对它们的反驳。
|
||||
|
||||
### 可用的预览入口
|
||||
|
||||
| 入口 | 用途 |
|
||||
| --- | --- |
|
||||
| `/design-showcase.html` | 五套主题切换 + 真实棋盘 + 离场动效;`src/showcase.js` 支持主题标签与配色数切换 |
|
||||
| `/?theme=<id>` | 主游戏强制指定主题,例如 `?theme=midnight`(唯一能看午夜极光的方式) |
|
||||
| `/?colors=<4\|7\|9\|12>` | 覆盖单关配色数 |
|
||||
| `/Design.html` | 单文件离线设计手册,内嵌图集与组件示例 |
|
||||
| `/?editor=1` | 关卡工坊,含完整 12 色库 |
|
||||
|
||||
需要 `npm run dev` 起服务(默认 4173),**必须通过 HTTP 访问**(ES modules)。
|
||||
|
||||
### 验收要求
|
||||
|
||||
1. **五套背景逐一检查**场景文字与箭头
|
||||
2. 检查**离场、旋转、撤销后颜色稳定**
|
||||
3. 390×844 竖屏 + 较矮屏幕
|
||||
4. 主界面、选关、设置、通关/失败、碰撞状态
|
||||
5. 弹窗不穿透操作、图标居中、轨道接缝不断裂
|
||||
|
||||
**本项目目前没有任何视觉回归基线。** 建立截图基线是值得做的一件事,但目前没有;改动视觉时应提供实机证据(截图),而不是只报"测试通过"。
|
||||
|
||||
---
|
||||
|
||||
## 8. 参考
|
||||
|
||||
| 路径 | 内容 |
|
||||
| --- | --- |
|
||||
| `Design.md` / `Design.html` | 设计规范(前者手写,后者生成) |
|
||||
| `docs/cocos-port.md` | 移植接入步骤与验证限制 |
|
||||
| `docs/level-design-principles-v2.md` | 产品方向与关卡准则 |
|
||||
| `assets/GENERATION.md` | 素材生成史与提示词 |
|
||||
| `design/tokens.json` | 给原生端读的 token 导出 |
|
||||
| `design/contrast-report.json` | 33 项对比度实测结果 |
|
||||
|
||||
**本文的核查范围**:§2、§3、§4、§6 的全部数字来自对当前工作区的实测复核(构建、测试、内联 node 计算),不是转述。**未验证**:真人观感、实机触感、原生端渲染效果 —— 这三项都还没有可引用的证据。
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,475 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>关卡实验台:信度检验与 1000 关流程</title>
|
||||
<style>
|
||||
:root{
|
||||
--ground:#EEF1F4; --surface:#FFFFFF; --inset:#E3E8ED; --panel:#F7F9FA;
|
||||
--ink:#141E28; --ink2:#48596A; --ink3:#6B7A88;
|
||||
--rule:#D3DAE1; --rule2:#BFC9D2;
|
||||
--rail:#435F78; --rail-soft:#8FA6BA;
|
||||
--signal:#B23A26; --signal-soft:#F2DDD8;
|
||||
--warn:#8A5C0F; --warn-soft:#F4E9D4;
|
||||
--good:#236E64; --good-soft:#D9EDEA;
|
||||
--shadow:0 1px 2px rgba(20,30,40,.06),0 6px 18px rgba(20,30,40,.05);
|
||||
color-scheme:light;
|
||||
}
|
||||
@media (prefers-color-scheme:dark){:root:not([data-theme=light]){
|
||||
--ground:#0F161C; --surface:#141D25; --inset:#0A1015; --panel:#141D25;
|
||||
--ink:#E4EAEF; --ink2:#AEBDC9; --ink3:#8494A2;
|
||||
--rule:#28343F; --rule2:#35434F;
|
||||
--rail:#8CB0CC; --rail-soft:#4E6577;
|
||||
--signal:#E4836C; --signal-soft:#3A211B;
|
||||
--warn:#E0AE5E; --warn-soft:#33280F;
|
||||
--good:#4FC7B7; --good-soft:#11302C;
|
||||
--shadow:0 1px 2px rgba(0,0,0,.3),0 6px 18px rgba(0,0,0,.28);
|
||||
color-scheme:dark;
|
||||
}}
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;background:var(--ground);color:var(--ink);
|
||||
font-family:"PingFang SC","Hiragino Sans GB","Microsoft YaHei",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
|
||||
line-height:1.72;-webkit-font-smoothing:antialiased}
|
||||
.wrap{max-width:1000px;margin:0 auto;padding:0 24px 88px}
|
||||
code,.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums}
|
||||
header.head{padding:60px 0 30px;border-bottom:1px solid var(--rule);margin-bottom:40px}
|
||||
.eyebrow{font-size:11.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink3);margin-bottom:14px}
|
||||
h1{font-size:clamp(28px,4.4vw,42px);line-height:1.18;margin:0 0 16px;letter-spacing:-.02em;text-wrap:balance}
|
||||
.lede{font-size:17px;color:var(--ink2);max-width:66ch;margin:0}
|
||||
.meta{margin-top:20px;font-size:12.5px;color:var(--ink3)}
|
||||
h2{font-size:23px;margin:56px 0 8px;letter-spacing:-.01em;text-wrap:balance}
|
||||
h2 .num{color:var(--rail-soft);font-family:ui-monospace,monospace;font-size:15px;margin-right:10px}
|
||||
h3{font-size:16px;margin:32px 0 10px;color:var(--ink)}
|
||||
p{margin:0 0 14px;max-width:72ch}
|
||||
.sub{color:var(--ink2);font-size:14.5px}
|
||||
.card{background:var(--surface);border:1px solid var(--rule);border-radius:12px;padding:20px 22px;box-shadow:var(--shadow);margin:20px 0}
|
||||
.callout{border-left:3px solid var(--rail);background:var(--panel);border-radius:0 10px 10px 0;padding:16px 20px;margin:20px 0}
|
||||
.callout.bad{border-left-color:var(--signal);background:var(--signal-soft)}
|
||||
.callout.good{border-left-color:var(--good);background:var(--good-soft)}
|
||||
.callout p:last-child{margin-bottom:0}
|
||||
.callout b{font-weight:650}
|
||||
table{width:100%;border-collapse:collapse;font-size:13.5px;margin:16px 0}
|
||||
th,td{text-align:left;padding:9px 10px;border-bottom:1px solid var(--rule)}
|
||||
th{font-size:11.5px;letter-spacing:.06em;color:var(--ink3);text-transform:uppercase;font-weight:600;white-space:nowrap}
|
||||
td.n,th.n{text-align:right;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;white-space:nowrap}
|
||||
tbody tr:hover{background:var(--panel)}
|
||||
.scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
|
||||
.tag{display:inline-block;font-size:11px;padding:2px 8px;border-radius:20px;font-weight:600;white-space:nowrap}
|
||||
.tag.good{background:var(--good-soft);color:var(--good)}
|
||||
.tag.signal{background:var(--signal-soft);color:var(--signal)}
|
||||
.tag.warn{background:var(--warn-soft);color:var(--warn)}
|
||||
.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));margin:20px 0}
|
||||
.tile{background:var(--surface);border:1px solid var(--rule);border-radius:12px;padding:16px 18px}
|
||||
.tile .k{font-size:11.5px;letter-spacing:.06em;color:var(--ink3);text-transform:uppercase}
|
||||
.tile .v{font-family:ui-monospace,monospace;font-size:27px;font-weight:600;line-height:1.25;margin-top:4px;font-variant-numeric:tabular-nums}
|
||||
.tile .n{font-size:12.5px;color:var(--ink2);margin-top:2px}
|
||||
.scatters{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin:18px 0}
|
||||
.sc{background:var(--surface);border:1px solid var(--rule);border-radius:12px;padding:12px 12px 6px;text-align:center}
|
||||
.sc h4{margin:0 0 2px;font-size:13.5px;font-weight:600}
|
||||
.sc .r{font-family:ui-monospace,monospace;font-size:12.5px;color:var(--ink2)}
|
||||
.sc svg{width:100%;height:auto;display:block;margin-top:4px}
|
||||
.ax{stroke:var(--rule2);stroke-width:1}
|
||||
.diag{stroke:var(--rail-soft);stroke-width:1;stroke-dasharray:3 3}
|
||||
.axl{font-size:9px;fill:var(--ink3);font-family:ui-monospace,monospace}
|
||||
.dot circle{fill:var(--rail);fill-opacity:.72}
|
||||
.dot.solid circle{fill:var(--good);fill-opacity:.8}
|
||||
.dot.noise circle{fill:var(--signal);fill-opacity:.7}
|
||||
.dot.flat circle{fill:var(--warn);fill-opacity:.7}
|
||||
.bars{margin:14px 0}
|
||||
.bar-row{display:grid;grid-template-columns:140px 1fr 48px;align-items:center;gap:12px;padding:5px 0}
|
||||
.bar-k{font-size:13px}
|
||||
.bar-k small{color:var(--ink3);margin-left:6px;font-size:11px}
|
||||
.bar-track{background:var(--inset);border-radius:4px;height:9px;overflow:hidden}
|
||||
.bar-track i{display:block;height:100%;background:var(--signal);border-radius:4px}
|
||||
.bar-track i.zero{background:var(--good)}
|
||||
.bar-v{font-family:ui-monospace,monospace;font-size:13px;text-align:right}
|
||||
.note{border-left:2px solid var(--rule2);padding:2px 0 2px 14px;margin:10px 0;font-size:13.5px;color:var(--ink2)}
|
||||
.note b{color:var(--ink);font-weight:600}
|
||||
.steps{counter-reset:s;list-style:none;padding:0;margin:22px 0}
|
||||
.steps>li{counter-increment:s;position:relative;padding:0 0 22px 46px;border-left:1px solid var(--rule);margin-left:14px}
|
||||
.steps>li:last-child{border-left-color:transparent;padding-bottom:0}
|
||||
.steps>li::before{content:"T" counter(s);position:absolute;left:-15px;top:0;width:30px;height:30px;border-radius:50%;
|
||||
background:var(--rail);color:var(--surface);display:grid;place-items:center;font-family:ui-monospace,monospace;font-size:11px;font-weight:700}
|
||||
.steps h3{margin:2px 0 6px}
|
||||
footer{margin-top:64px;padding-top:22px;border-top:1px solid var(--rule);color:var(--ink3);font-size:12.5px}
|
||||
@media(max-width:640px){.bar-row{grid-template-columns:100px 1fr 42px}.wrap{padding:0 16px 60px}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<header class="head">
|
||||
<div class="eyebrow">HEX TRAILS · 关卡实验台</div>
|
||||
<h1>Agent 评级里,哪些数字真能拿来做关卡</h1>
|
||||
<p class="lede">同一批关卡、同一个模型、同一套盘面,跑两遍。能重现的指标才配进流程——这份报告把每个指标逐个检验了一遍,结论和直觉相反。</p>
|
||||
<p class="meta mono">生成于 2026-09-14 16:04 GMT+8 · 数据来自 bench/runs 的 229 局 · 关卡集 levels/prototypes/d5.json(18 关)</p>
|
||||
</header>
|
||||
|
||||
<h2><span class="num">01</span>参与检验的批次</h2>
|
||||
<p class="sub">每一批用 <code>agent</code> 字段标识,不靠文件名猜来源。「旧盘面」指擦碰只报第一个阻挡者的版本,「新盘面」指修复后全部列出的版本。</p>
|
||||
<p class="sub">模型名以 <b>CLI 启动时打印的解析结果</b>为准,而不是提示词里让 agent 自报的名字——有一批 18 局曾被标成 codex-spark,实际是配置在运行前被改掉、跑成了 gpt-6-astra/low,存档已按日志头更正。</p>
|
||||
<div class="scroll"><table>
|
||||
<thead><tr><th>批次</th><th class="n">关数</th><th class="n">通关</th><th class="n">空点</th><th class="n">擦碰空点</th><th class="n">盲转</th><th class="n">转错</th><th class="n">多转</th><th class="n">单局均</th><th class="n">每决策</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>grok-4.6 · 旧盘面</td><td class="n">18</td><td class="n">18/18</td><td class="n">4</td><td class="n">4</td><td class="n">21</td><td class="n">8</td><td class="n">22</td><td class="n">83 s</td><td class="n">6.8 s</td></tr>
|
||||
<tr><td>grok-4.6 · 新盘面 · 第 1 次</td><td class="n">18</td><td class="n">18/18</td><td class="n">2</td><td class="n">1</td><td class="n">21</td><td class="n">8</td><td class="n">22</td><td class="n">55 s</td><td class="n">3.9 s</td></tr>
|
||||
<tr><td>grok-4.6 · 新盘面 · 第 2 次</td><td class="n">18</td><td class="n">18/18</td><td class="n">0</td><td class="n">0</td><td class="n">25</td><td class="n">10</td><td class="n">28</td><td class="n">49 s</td><td class="n">3.9 s</td></tr>
|
||||
<tr><td>codex-spark · 旧盘面</td><td class="n">6</td><td class="n">6/6</td><td class="n">0</td><td class="n">0</td><td class="n">2</td><td class="n">2</td><td class="n">2</td><td class="n">15 s</td><td class="n">1.4 s</td></tr>
|
||||
<tr><td>gpt-6-astra · low · 新盘面</td><td class="n">18</td><td class="n">18/18</td><td class="n">1</td><td class="n">0</td><td class="n">21</td><td class="n">8</td><td class="n">22</td><td class="n">41 s</td><td class="n">7.0 s</td></tr>
|
||||
<tr><td>codex-spark · xhigh · 新盘面</td><td class="n">18</td><td class="n">17/18</td><td class="n">0</td><td class="n">0</td><td class="n">21</td><td class="n">7</td><td class="n">21</td><td class="n">21 s</td><td class="n">1.8 s</td></tr>
|
||||
<tr><td>kimi-k3 · high · 新盘面</td><td class="n">18</td><td class="n">18/18</td><td class="n">0</td><td class="n">0</td><td class="n">21</td><td class="n">8</td><td class="n">22</td><td class="n">48 s</td><td class="n">5.2 s</td></tr>
|
||||
<tr><td>grok-4.6 · 新关卡集(终局门槛后)</td><td class="n">18</td><td class="n">18/18</td><td class="n">0</td><td class="n">0</td><td class="n">5</td><td class="n">4</td><td class="n">6</td><td class="n">41 s</td><td class="n">3.8 s</td></tr>
|
||||
</tbody></table></div>
|
||||
<p class="sub">已完成的对局通关率全部是 100%(个别批次仍有对局在进行中,未计入)。<b>通关率在这批内容上毫无区分度,任何流程都不该建立在通过/失败上。</b></p>
|
||||
|
||||
|
||||
<h2><span class="num">02</span>信度检验:跑两遍还一样吗</h2>
|
||||
<p>同模型(grok-4.6 xhigh)、同 harness(pi)、同盘面(新)、同 18 关,只是又跑了一遍。两次之间唯一的变量就是运行本身,所以下面的相关系数<b>就是这个指标的复测信度</b>。</p>
|
||||
<p class="sub">判定规则:<b>关间标准差 < 0.35</b> 说明这个指标在不同关卡上几乎一样,再稳也没用(无法排序);<b>复测 r < 0.5</b> 说明换一次运行结果就变,不能作为依据。两条都过才算可用。</p>
|
||||
<div class="scroll"><table>
|
||||
<thead><tr><th>指标</th><th class="n">关间标准差</th><th class="n">复测相关 r</th><th class="n">逐关完全一致</th><th>判定</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>多转<br><small class="sub">清盘旋转数 − 求解器最少旋转数</small></td><td class="n">1.58</td><td class="n">0.87</td><td class="n">17/18</td><td><span class="tag good">可用</span></td></tr>
|
||||
<tr><td>盲转<br><small class="sub">转了一次,什么出口都没打开</small></td><td class="n">1.57</td><td class="n">0.92</td><td class="n">17/18</td><td><span class="tag good">可用 · 高</span></td></tr>
|
||||
<tr><td>转错方向<br><small class="sub">另一边本来能打开</small></td><td class="n">0.50</td><td class="n">0.82</td><td class="n">17/18</td><td><span class="tag good">可用</span></td></tr>
|
||||
<tr><td>步数</td><td class="n">2.24</td><td class="n">0.76</td><td class="n">16/18</td><td><span class="tag good">可用</span></td></tr>
|
||||
<tr><td>决策数<br><small class="sub">看了几次盘面</small></td><td class="n">1.89</td><td class="n">0.77</td><td class="n">10/18</td><td><span class="tag good">可用</span></td></tr>
|
||||
<tr><td>空点<br><small class="sub">点了没动</small></td><td class="n">0.46</td><td class="n">—</td><td class="n">17/18</td><td><span class="tag signal">噪声</span></td></tr>
|
||||
<tr><td>动作÷棋子</td><td class="n">0.15</td><td class="n">0.69</td><td class="n">16/18</td><td><span class="tag warn">无区分度</span></td></tr>
|
||||
<tr><td>评分:无解感</td><td class="n">0.87</td><td class="n">0.85</td><td class="n">14/18</td><td><span class="tag good">可用</span></td></tr>
|
||||
<tr><td>评分:难度</td><td class="n">0.59</td><td class="n">0.93</td><td class="n">17/18</td><td><span class="tag good">可用 · 高</span></td></tr>
|
||||
<tr><td>评分:旋转意义</td><td class="n">0.37</td><td class="n">0.32</td><td class="n">15/18</td><td><span class="tag signal">噪声</span></td></tr>
|
||||
<tr><td>评分:清晰度</td><td class="n">0.47</td><td class="n">0.19</td><td class="n">12/18</td><td><span class="tag signal">噪声</span></td></tr>
|
||||
<tr><td>评分:好玩</td><td class="n">0.42</td><td class="n">0.56</td><td class="n">15/18</td><td><span class="tag good">可用</span></td></tr>
|
||||
</tbody></table></div>
|
||||
<p class="sub">「关间标准差」衡量这个指标能不能把不同关卡区分开——标准差接近 0 的指标就算完全可复现也没用,因为每关都一样。<b>两个条件要同时满足</b>:既能区分关卡,又能跑两遍不变。</p>
|
||||
|
||||
<div class="scatters">
|
||||
<div class="sc"><h4>多转</h4><div class="r">r = 0.87</div><svg viewBox="0 0 168 168" role="img" aria-label="多转 两次运行散点图,相关系数 0.87">
|
||||
<line class="ax" x1="26" y1="142" x2="160" y2="142"/>
|
||||
<line class="ax" x1="26" y1="8" x2="26" y2="142"/>
|
||||
<line class="diag" x1="26" y1="142" x2="158" y2="10"/>
|
||||
<g class="dot ok"><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="39.2" cy="128.8" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="39.2" cy="128.8" r="3.6"/><circle cx="78.8" cy="10.0" r="3.6"/><circle cx="78.8" cy="89.2" r="3.6"/><circle cx="78.8" cy="89.2" r="3.6"/><circle cx="78.8" cy="89.2" r="3.6"/><circle cx="39.2" cy="128.8" r="3.6"/><circle cx="39.2" cy="128.8" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="52.4" cy="115.6" r="3.6"/></g>
|
||||
<text class="axl" x="84" y="162" text-anchor="middle">第 1 次</text>
|
||||
<text class="axl" x="10" y="84" text-anchor="middle" transform="rotate(-90 10 84)">第 2 次</text>
|
||||
</svg></div>
|
||||
<div class="sc"><h4>盲转</h4><div class="r">r = 0.92</div><svg viewBox="0 0 168 168" role="img" aria-label="盲转 两次运行散点图,相关系数 0.92">
|
||||
<line class="ax" x1="26" y1="142" x2="160" y2="142"/>
|
||||
<line class="ax" x1="26" y1="8" x2="26" y2="142"/>
|
||||
<line class="diag" x1="26" y1="142" x2="158" y2="10"/>
|
||||
<g class="dot solid"><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="42.5" cy="125.5" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="42.5" cy="125.5" r="3.6"/><circle cx="92.0" cy="10.0" r="3.6"/><circle cx="92.0" cy="76.0" r="3.6"/><circle cx="92.0" cy="76.0" r="3.6"/><circle cx="92.0" cy="76.0" r="3.6"/><circle cx="42.5" cy="125.5" r="3.6"/><circle cx="42.5" cy="125.5" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="42.5" cy="125.5" r="3.6"/></g>
|
||||
<text class="axl" x="84" y="162" text-anchor="middle">第 1 次</text>
|
||||
<text class="axl" x="10" y="84" text-anchor="middle" transform="rotate(-90 10 84)">第 2 次</text>
|
||||
</svg></div>
|
||||
<div class="sc"><h4>转错方向</h4><div class="r">r = 0.82</div><svg viewBox="0 0 168 168" role="img" aria-label="转错方向 两次运行散点图,相关系数 0.82">
|
||||
<line class="ax" x1="26" y1="142" x2="160" y2="142"/>
|
||||
<line class="ax" x1="26" y1="8" x2="26" y2="142"/>
|
||||
<line class="diag" x1="26" y1="142" x2="158" y2="10"/>
|
||||
<g class="dot ok"><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="70.0" cy="10.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/></g>
|
||||
<text class="axl" x="84" y="162" text-anchor="middle">第 1 次</text>
|
||||
<text class="axl" x="10" y="84" text-anchor="middle" transform="rotate(-90 10 84)">第 2 次</text>
|
||||
</svg></div>
|
||||
<div class="sc"><h4>步数</h4><div class="r">r = 0.76</div><svg viewBox="0 0 168 168" role="img" aria-label="步数 两次运行散点图,相关系数 0.76">
|
||||
<line class="ax" x1="26" y1="142" x2="160" y2="142"/>
|
||||
<line class="ax" x1="26" y1="8" x2="26" y2="142"/>
|
||||
<line class="diag" x1="26" y1="142" x2="158" y2="10"/>
|
||||
<g class="dot ok"><circle cx="46.8" cy="121.2" r="3.6"/><circle cx="67.7" cy="114.2" r="3.6"/><circle cx="46.8" cy="121.2" r="3.6"/><circle cx="46.8" cy="121.2" r="3.6"/><circle cx="46.8" cy="121.2" r="3.6"/><circle cx="46.8" cy="121.2" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="53.8" cy="114.2" r="3.6"/><circle cx="74.6" cy="10.0" r="3.6"/><circle cx="53.8" cy="114.2" r="3.6"/><circle cx="74.6" cy="93.4" r="3.6"/><circle cx="74.6" cy="93.4" r="3.6"/><circle cx="53.8" cy="114.2" r="3.6"/><circle cx="32.9" cy="135.1" r="3.6"/><circle cx="46.8" cy="121.2" r="3.6"/><circle cx="60.7" cy="107.3" r="3.6"/></g>
|
||||
<text class="axl" x="84" y="162" text-anchor="middle">第 1 次</text>
|
||||
<text class="axl" x="10" y="84" text-anchor="middle" transform="rotate(-90 10 84)">第 2 次</text>
|
||||
</svg></div>
|
||||
<div class="sc"><h4>决策数</h4><div class="r">r = 0.77</div><svg viewBox="0 0 168 168" role="img" aria-label="决策数 两次运行散点图,相关系数 0.77">
|
||||
<line class="ax" x1="26" y1="142" x2="160" y2="142"/>
|
||||
<line class="ax" x1="26" y1="8" x2="26" y2="142"/>
|
||||
<line class="diag" x1="26" y1="142" x2="158" y2="10"/>
|
||||
<g class="dot ok"><circle cx="35.4" cy="142.0" r="3.6"/><circle cx="63.7" cy="113.7" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="132.6" r="3.6"/><circle cx="26.0" cy="132.6" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="132.6" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="35.4" cy="123.1" r="3.6"/><circle cx="73.1" cy="10.0" r="3.6"/><circle cx="63.7" cy="104.3" r="3.6"/><circle cx="63.7" cy="104.3" r="3.6"/><circle cx="73.1" cy="94.9" r="3.6"/><circle cx="35.4" cy="132.6" r="3.6"/><circle cx="35.4" cy="132.6" r="3.6"/><circle cx="26.0" cy="123.1" r="3.6"/><circle cx="54.3" cy="113.7" r="3.6"/></g>
|
||||
<text class="axl" x="84" y="162" text-anchor="middle">第 1 次</text>
|
||||
<text class="axl" x="10" y="84" text-anchor="middle" transform="rotate(-90 10 84)">第 2 次</text>
|
||||
</svg></div>
|
||||
<div class="sc"><h4>动作÷棋子</h4><div class="r">r = 0.69</div><svg viewBox="0 0 168 168" role="img" aria-label="动作÷棋子 两次运行散点图,相关系数 0.69">
|
||||
<line class="ax" x1="26" y1="142" x2="160" y2="142"/>
|
||||
<line class="ax" x1="26" y1="8" x2="26" y2="142"/>
|
||||
<line class="diag" x1="26" y1="142" x2="158" y2="10"/>
|
||||
<g class="dot flat"><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="50.8" cy="133.8" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="34.2" cy="133.8" r="3.6"/><circle cx="34.2" cy="133.8" r="3.6"/><circle cx="34.2" cy="133.8" r="3.6"/><circle cx="34.2" cy="133.8" r="3.6"/><circle cx="59.0" cy="10.0" r="3.6"/><circle cx="78.2" cy="89.8" r="3.6"/><circle cx="59.0" cy="109.0" r="3.6"/><circle cx="59.0" cy="109.0" r="3.6"/><circle cx="34.2" cy="133.8" r="3.6"/><circle cx="45.2" cy="122.8" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="42.5" cy="125.5" r="3.6"/></g>
|
||||
<text class="axl" x="84" y="162" text-anchor="middle">第 1 次</text>
|
||||
<text class="axl" x="10" y="84" text-anchor="middle" transform="rotate(-90 10 84)">第 2 次</text>
|
||||
</svg></div>
|
||||
<div class="sc"><h4>评分:无解感</h4><div class="r">r = 0.85</div><svg viewBox="0 0 168 168" role="img" aria-label="评分:无解感 两次运行散点图,相关系数 0.85">
|
||||
<line class="ax" x1="26" y1="142" x2="160" y2="142"/>
|
||||
<line class="ax" x1="26" y1="8" x2="26" y2="142"/>
|
||||
<line class="diag" x1="26" y1="142" x2="158" y2="10"/>
|
||||
<g class="dot ok"><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="70.0" cy="142.0" r="3.6"/><circle cx="70.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="98.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="158.0" cy="54.0" r="3.6"/><circle cx="114.0" cy="54.0" r="3.6"/><circle cx="114.0" cy="54.0" r="3.6"/><circle cx="114.0" cy="54.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="70.0" cy="98.0" r="3.6"/></g>
|
||||
<text class="axl" x="84" y="162" text-anchor="middle">第 1 次</text>
|
||||
<text class="axl" x="10" y="84" text-anchor="middle" transform="rotate(-90 10 84)">第 2 次</text>
|
||||
</svg></div>
|
||||
<div class="sc"><h4>评分:难度</h4><div class="r">r = 0.93</div><svg viewBox="0 0 168 168" role="img" aria-label="评分:难度 两次运行散点图,相关系数 0.93">
|
||||
<line class="ax" x1="26" y1="142" x2="160" y2="142"/>
|
||||
<line class="ax" x1="26" y1="8" x2="26" y2="142"/>
|
||||
<line class="diag" x1="26" y1="142" x2="158" y2="10"/>
|
||||
<g class="dot solid"><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="92.0" cy="76.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="158.0" cy="10.0" r="3.6"/><circle cx="92.0" cy="76.0" r="3.6"/><circle cx="92.0" cy="76.0" r="3.6"/><circle cx="92.0" cy="76.0" r="3.6"/><circle cx="92.0" cy="76.0" r="3.6"/><circle cx="26.0" cy="76.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/><circle cx="26.0" cy="142.0" r="3.6"/></g>
|
||||
<text class="axl" x="84" y="162" text-anchor="middle">第 1 次</text>
|
||||
<text class="axl" x="10" y="84" text-anchor="middle" transform="rotate(-90 10 84)">第 2 次</text>
|
||||
</svg></div>
|
||||
</div>
|
||||
<p class="sub">虚线是「两次完全相同」。点贴着虚线 = 可复现;点散开 = 这个数字换一次运行就变。</p>
|
||||
|
||||
|
||||
|
||||
<h3>对照:换了盘面格式的那一对</h3>
|
||||
<p class="sub">上一节控制了所有变量。作为对照,这里是<b>旧盘面 vs 新盘面</b>的同 18 关配对——它多了一个变量(盘面变了),所以相关系数是信度的<b>下限</b>而非真值。两张表一起看,能分清「指标本身不稳」和「盘面变化导致的差异」。</p>
|
||||
<div class="scroll"><table>
|
||||
<thead><tr><th>指标</th><th class="n">控制变量后 r</th><th class="n">换盘面后 r</th><th>差异说明</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>多转</td><td class="n">0.87</td><td class="n">1.00</td><td class="sub">两者接近,盘面变化影响很小</td></tr>
|
||||
<tr><td>盲转</td><td class="n">0.92</td><td class="n">1.00</td><td class="sub">两者接近,盘面变化影响很小</td></tr>
|
||||
<tr><td>转错方向</td><td class="n">0.82</td><td class="n">1.00</td><td class="sub">控制变量后反而更低——值得留意</td></tr>
|
||||
<tr><td>步数</td><td class="n">0.76</td><td class="n">0.95</td><td class="sub">控制变量后反而更低——值得留意</td></tr>
|
||||
<tr><td>决策数</td><td class="n">0.77</td><td class="n">0.87</td><td class="sub">两者接近,盘面变化影响很小</td></tr>
|
||||
<tr><td>空点</td><td class="n">—</td><td class="n">-0.10</td><td class="sub">—</td></tr>
|
||||
<tr><td>动作÷棋子</td><td class="n">0.69</td><td class="n">0.92</td><td class="sub">控制变量后反而更低——值得留意</td></tr>
|
||||
<tr><td>评分:无解感</td><td class="n">0.85</td><td class="n">0.80</td><td class="sub">两者接近,盘面变化影响很小</td></tr>
|
||||
<tr><td>评分:难度</td><td class="n">0.93</td><td class="n">0.63</td><td class="sub">控制变量后明显更高——之前被盘面变化压低了</td></tr>
|
||||
<tr><td>评分:旋转意义</td><td class="n">0.32</td><td class="n">0.06</td><td class="sub">控制变量后明显更高——之前被盘面变化压低了</td></tr>
|
||||
<tr><td>评分:清晰度</td><td class="n">0.19</td><td class="n">0.09</td><td class="sub">两者接近,盘面变化影响很小</td></tr>
|
||||
<tr><td>评分:好玩</td><td class="n">0.56</td><td class="n">0.21</td><td class="sub">控制变量后明显更高——之前被盘面变化压低了</td></tr>
|
||||
</tbody></table></div>
|
||||
|
||||
|
||||
<h2><span class="num">03</span>跨模型交叉验证:这些数字属于关卡,不属于玩家</h2>
|
||||
|
||||
<p>下表是同一套盘面下所有批次的 <code>多转 / 盲转 / 转错方向</code>。不同厂商的模型、不同 harness、各自独立跑——如果这些数字真的由关卡决定,它们就该一样。</p>
|
||||
<div class="grid">
|
||||
<div class="tile"><div class="k">逐关完全一致</div><div class="v">16 / 18</div><div class="n">三项数字一个不差</div></div>
|
||||
<div class="tile"><div class="k">参与批次</div><div class="v">5</div><div class="n">grok新① · grok新② · kimi · astra · spark新</div></div>
|
||||
</div>
|
||||
<div class="scroll"><table>
|
||||
<thead><tr><th>关</th><th>家族</th><th class="n">grok新①</th><th class="n">grok新②</th><th class="n">kimi</th><th class="n">astra</th><th class="n">spark新</th><th>一致</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>L3</td><td>switchback</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L5</td><td>switchback</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L6</td><td>weave</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L10</td><td>petals</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L11</td><td>petals</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L15</td><td>crossing</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L17</td><td>orbits</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L19</td><td>petals</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L20</td><td>petals</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L21</td><td>switchback</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L22</td><td>orbits</td><td class="n">4/4/1</td><td class="n">10/8/3</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td><span class="tag signal">✘</span></td></tr>
|
||||
<tr><td>L23</td><td>orbits</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L24</td><td>spiral</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L25</td><td>spiral</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">4/4/1</td><td class="n">3/4/0</td><td><span class="tag signal">✘</span></td></tr>
|
||||
<tr><td>L26</td><td>switchback</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L27</td><td>weave</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td class="n">1/1/1</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L28</td><td>weave</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td class="n">0/0/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
<tr><td>L29</td><td>weave</td><td class="n">2/1/0</td><td class="n">2/1/0</td><td class="n">2/1/0</td><td class="n">2/1/0</td><td class="n">2/1/0</td><td><span class="tag good">✔</span></td></tr>
|
||||
</tbody></table></div>
|
||||
<div class="callout good">
|
||||
<p><b>这是全份报告里最硬的一条结论。</b>16/18 关上,独立运行的不同模型给出了完全相同的旋转三元组。这意味着<b>规则机器人 12 秒扫出来的这三个数,等价于大模型跑几小时的结果</b>——这个维度完全不需要 agent。</p>
|
||||
</div>
|
||||
|
||||
<h3>不一致的关:不是难,是不稳定</h3>
|
||||
<p class="sub">下面这些关在不同运行之间给出了不同的数字。排除模型差异后,剩下的解释是<b>同一关的体验取决于起手方向</b>——两个玩家玩同一关,一个觉得还行,一个觉得这关有毛病。这比"稳定地难"更值得处理。</p>
|
||||
<div class="note"><b>L22 orbits</b>:4/4/1 / 10/8/3 / 4/4/1 / 4/4/1 / 4/4/1</div><div class="note"><b>L25 spiral</b>:4/4/1 / 4/4/1 / 4/4/1 / 4/4/1 / 3/4/0</div>
|
||||
|
||||
<h2><span class="num">04</span>家族结构:机械指标指向同一个地方</h2>
|
||||
<p>把「多转」按路线家族平均。这是关卡结构问题,不是玩家问题——两批 grok、以及 spark,在这一点上给出一致的结果。</p>
|
||||
|
||||
<div class="card"><h3 style="margin-top:0">grok-4.6 · 旧盘面 · 各家族平均多转</h3><div class="bars">
|
||||
<div class="bar-row"><span class="bar-k">spiral<small>2 关</small></span>
|
||||
<span class="bar-track"><i style="width:100.0%" class=""></i></span>
|
||||
<b class="bar-v">4.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">orbits<small>3 关</small></span>
|
||||
<span class="bar-track"><i style="width:66.7%" class=""></i></span>
|
||||
<b class="bar-v">2.7</b></div>
|
||||
<div class="bar-row"><span class="bar-k">switchback<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:18.8%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">weave<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:18.8%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">petals<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">crossing<small>1 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div></div></div>
|
||||
|
||||
<div class="card"><h3 style="margin-top:0">grok-4.6 · 新盘面 · 第 1 次 · 各家族平均多转</h3><div class="bars">
|
||||
<div class="bar-row"><span class="bar-k">spiral<small>2 关</small></span>
|
||||
<span class="bar-track"><i style="width:100.0%" class=""></i></span>
|
||||
<b class="bar-v">4.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">orbits<small>3 关</small></span>
|
||||
<span class="bar-track"><i style="width:66.7%" class=""></i></span>
|
||||
<b class="bar-v">2.7</b></div>
|
||||
<div class="bar-row"><span class="bar-k">switchback<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:18.8%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">weave<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:18.8%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">petals<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">crossing<small>1 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div></div></div>
|
||||
|
||||
<div class="card"><h3 style="margin-top:0">grok-4.6 · 新盘面 · 第 2 次 · 各家族平均多转</h3><div class="bars">
|
||||
<div class="bar-row"><span class="bar-k">orbits<small>3 关</small></span>
|
||||
<span class="bar-track"><i style="width:100.0%" class=""></i></span>
|
||||
<b class="bar-v">4.7</b></div>
|
||||
<div class="bar-row"><span class="bar-k">spiral<small>2 关</small></span>
|
||||
<span class="bar-track"><i style="width:85.7%" class=""></i></span>
|
||||
<b class="bar-v">4.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">switchback<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:16.1%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">weave<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:16.1%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">petals<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">crossing<small>1 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div></div></div>
|
||||
|
||||
<div class="card"><h3 style="margin-top:0">codex-spark · 旧盘面 · 各家族平均多转</h3><div class="bars">
|
||||
<div class="bar-row"><span class="bar-k">switchback<small>3 关</small></span>
|
||||
<span class="bar-track"><i style="width:33.3%" class=""></i></span>
|
||||
<b class="bar-v">0.3</b></div>
|
||||
<div class="bar-row"><span class="bar-k">weave<small>3 关</small></span>
|
||||
<span class="bar-track"><i style="width:33.3%" class=""></i></span>
|
||||
<b class="bar-v">0.3</b></div></div></div>
|
||||
|
||||
<div class="card"><h3 style="margin-top:0">gpt-6-astra · low · 新盘面 · 各家族平均多转</h3><div class="bars">
|
||||
<div class="bar-row"><span class="bar-k">spiral<small>2 关</small></span>
|
||||
<span class="bar-track"><i style="width:100.0%" class=""></i></span>
|
||||
<b class="bar-v">4.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">orbits<small>3 关</small></span>
|
||||
<span class="bar-track"><i style="width:66.7%" class=""></i></span>
|
||||
<b class="bar-v">2.7</b></div>
|
||||
<div class="bar-row"><span class="bar-k">switchback<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:18.8%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">weave<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:18.8%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">petals<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">crossing<small>1 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div></div></div>
|
||||
|
||||
<div class="card"><h3 style="margin-top:0">codex-spark · xhigh · 新盘面 · 各家族平均多转</h3><div class="bars">
|
||||
<div class="bar-row"><span class="bar-k">spiral<small>2 关</small></span>
|
||||
<span class="bar-track"><i style="width:100.0%" class=""></i></span>
|
||||
<b class="bar-v">3.5</b></div>
|
||||
<div class="bar-row"><span class="bar-k">orbits<small>3 关</small></span>
|
||||
<span class="bar-track"><i style="width:76.2%" class=""></i></span>
|
||||
<b class="bar-v">2.7</b></div>
|
||||
<div class="bar-row"><span class="bar-k">switchback<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:21.4%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">weave<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:21.4%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">petals<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">crossing<small>1 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div></div></div>
|
||||
|
||||
<div class="card"><h3 style="margin-top:0">kimi-k3 · high · 新盘面 · 各家族平均多转</h3><div class="bars">
|
||||
<div class="bar-row"><span class="bar-k">spiral<small>2 关</small></span>
|
||||
<span class="bar-track"><i style="width:100.0%" class=""></i></span>
|
||||
<b class="bar-v">4.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">orbits<small>3 关</small></span>
|
||||
<span class="bar-track"><i style="width:66.7%" class=""></i></span>
|
||||
<b class="bar-v">2.7</b></div>
|
||||
<div class="bar-row"><span class="bar-k">switchback<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:18.8%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">weave<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:18.8%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">petals<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">crossing<small>1 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div></div></div>
|
||||
|
||||
<div class="card"><h3 style="margin-top:0">grok-4.6 · 新关卡集(终局门槛后) · 各家族平均多转</h3><div class="bars">
|
||||
<div class="bar-row"><span class="bar-k">switchback<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:75.0%" class=""></i></span>
|
||||
<b class="bar-v">0.8</b></div>
|
||||
<div class="bar-row"><span class="bar-k">petals<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:50.0%" class=""></i></span>
|
||||
<b class="bar-v">0.5</b></div>
|
||||
<div class="bar-row"><span class="bar-k">weave<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:25.0%" class=""></i></span>
|
||||
<b class="bar-v">0.3</b></div>
|
||||
<div class="bar-row"><span class="bar-k">orbits<small>4 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div>
|
||||
<div class="bar-row"><span class="bar-k">crossing<small>2 关</small></span>
|
||||
<span class="bar-track"><i style="width:0.0%" class="zero"></i></span>
|
||||
<b class="bar-v">0.0</b></div></div></div>
|
||||
<div class="callout bad">
|
||||
<p><b>orbits 和 spiral 是问题家族。</b>它们稳定地需要 7 次旋转(最少 3 次)外加 4 次盲转——等于把 6 个朝向挨个试一遍。而 petals 和 crossing 是干净的 0。锁住率解释不了这个差异(L16 也是 orbits、锁 78%,却是 3/3)。</p>
|
||||
</div>
|
||||
|
||||
<h2><span class="num">05</span>Agent 说了什么</h2>
|
||||
<p class="sub">评分是 1–5 的数字,<code>worst</code> 是它自己写的一句话。下面按反复出现的主题归类——<b>价值在重复模式,不在单条内容</b>。</p>
|
||||
|
||||
<h3>擦碰看不出来 · 30 次提及</h3>
|
||||
<div class="note"><b>L3 switchback</b>(grok旧):开局 t2/t11 路上看着没人其实会擦到,差点空点;只剩 t0 和 t3 对堵时短暂以为卡住了</div>
|
||||
<div class="note"><b>L6 weave</b>(grok旧):t5走后(第9步)t2和t3都像能出界,其实互相擦碰,只能再转</div>
|
||||
<div class="note"><b>L6 weave</b>(grok新①):朝向1时 t2 和 t3 互相擦碰、t0 被 t2 压着,短暂不确定是再转还是还有能点的</div>
|
||||
<div class="note"><b>L6 weave</b>(grok新②):第9步清完后t2和t3互相擦挡,谁先走都不行,只能转</div>
|
||||
|
||||
<h3>不知道该转哪边 · 19 次提及</h3>
|
||||
<div class="note"><b>L1 switchback</b>(grok新关):朝向3右转后没有新出口,t0和t3仍互相挡,短暂怀疑该不该改左转</div>
|
||||
<div class="note"><b>L5 switchback</b>(grok旧):第 13 步右转后朝向 3 没新出口,t0 和 t3 仍互相挡,不确定该不该继续同向转</div>
|
||||
<div class="note"><b>L5 switchback</b>(grok新①):第15步右转后朝向3没有新出口,最后两枚还互压,一度担心转错了方向</div>
|
||||
<div class="note"><b>L5 switchback</b>(spark旧):第 8-9 步清掉 t5,t4,t2 后只剩 t0/t3 互压,朝向2不再有出口,开始不确定该是继续走还是转哪边</div>
|
||||
|
||||
<h3>长路线读不动 · 32 次提及</h3>
|
||||
<div class="note"><b>L2 weave</b>(grok新关):开局 t0 绕了 21 格还压着 6 枚,一眼看不出清障顺序,只能先点边上的 t4/t6</div>
|
||||
<div class="note"><b>L3 switchback</b>(kimi):第 10 步后 t0/t2/t3/t10 四枚互相压成环,盘面上看不出解法,只能靠旋转试出新朝向</div>
|
||||
<div class="note"><b>L9 petals</b>(grok新关):开局 t0/t3 各绕 19 格互相穿过,一时看不出该先剥哪层</div>
|
||||
<div class="note"><b>L10 petals</b>(grok旧):开局 t0/t3 各 19 格 15 弯还叠着好几枚,文字路线太长,分不清该先解哪一层</div>
|
||||
|
||||
<h2><span class="num">06</span>1000 关该怎么跑</h2>
|
||||
<p>核心判断:<b>机械计数器当主力,agent 做抽检</b>。免费的规则机器人能扫全量并稳定给出盲转/多转/转错;agent 贵但能提供两样机器给不了的东西——难度的相对排序,和用自然语言点出的系统性缺陷。<b>关键是只收集经过信度检验的那几项</b>。</p>
|
||||
<ol class="steps">
|
||||
<li><h3>生成期硬门槛 · 零成本</h3><p class="sub">用已有求解器,在生成时就卡掉:最少旋转 ≥ 2、开局锁住率 ≤ 90%、首转两个方向都能推进、无死局状态。不合格的根本不进候选池。</p></li>
|
||||
<li><h3>规则机器人全量扫 · 1000 关 12 秒</h3><p class="sub">产出盲转 / 多转 / 转错方向。按 <code>盲转 ≥ 2 或 多转 ≥ 2</code> 打标。这条规则在 D5 上正好命中 orbits+spiral 那几关,和两个大模型跑两小时得到的结论一致。</p></li>
|
||||
<li><h3>Agent 只跑被标记的 + 5% 随机抽样</h3><p class="sub">不是 1000 关全跑。收集<b>三样东西</b>:<code>difficulty</code>(r=0.93,可用来给 1000 关排序)、<code>stuck</code>(r=0.85,体感无解的直接信号)、以及 <code>worst</code> 文字(重复模式能挖出系统性缺陷)。<b>丢掉 rotation / clarity / fun</b>——复测 r 只有 0.32 / 0.19 / 0.56,是模型噪声。按实测 43 s/关、4 路并行,150 关约半小时。</p></li>
|
||||
<li><h3>真人标定锚点 · 5–10 关</h3><p class="sub">Agent 的难度<b>排序</b>可信(复测 r=0.93),但绝对值可能整体偏移——它觉得「刚好」的关,真人可能觉得太简单。所以真人只需要玩少数几关当<b>锚点</b>,把 agent 的相对排序映射到真实难度刻度上,不必逐关评。这比原本设想的省很多人力。</p></li>
|
||||
</ol>
|
||||
<div class="callout good">
|
||||
<p><b>最该做的一件事:把它变成回归测试,而不是评审流程。</b>改完生成器,12 秒跑一遍规则机器人,比较盲转分布。从 22% 降到 5% 就是客观改善,升上去就是刚引入了退化。12 秒一轮可以进 CI;几小时一轮且分数不可复现的人工评审,不可能成为迭代循环。</p>
|
||||
</div>
|
||||
|
||||
<h2><span class="num">07</span>这份结论的边界</h2>
|
||||
<p class="sub">写清楚哪里不够硬,比多列几个数字重要。</p>
|
||||
<ul class="sub">
|
||||
<li>跨模型一致性只验证了 <b>6 关</b>(spark 与 grok 的交集),其中 1 关不一致。机械指标"与玩家无关"这个说法,样本还太小。</li>
|
||||
<li>复测只做了 <b>2 次</b>。2 次能算相关系数,但对评分这种低方差的离散量,2 次的估计本身就有不小的不确定性。</li>
|
||||
<li>Agent 读的是文字不是像素,<b>测不出"看不清"</b>。clarity 这一项从原理上就不该指望它。</li>
|
||||
<li>所有结论都基于 <b>D5 原型这 18 关</b>。这批关卡通关率 100%、难度评分方差极小,换一批更难的内容,结论可能不同。</li>
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p class="mono">数据:bench/runs · 生成脚本:scripts/build-bench-report.mjs · 重新生成:<code>node scripts/build-bench-report.mjs</code></p>
|
||||
<p>本页所有数字由脚本从存档直接计算,未经手工填写。相关系数为 Pearson r,标准差为总体标准差。</p>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,70 +0,0 @@
|
||||
# 主线关卡验收与节奏表
|
||||
|
||||
自动生成:`npm run levels`;固定布局参数见 `levels/campaign-seeds.json`。共 48 关,8 章,每章顺序为进入、换路、展开、小挑战、释放、长局回报。认知难度与棋盘规模分别记录。
|
||||
|
||||
全部关卡:可解且回放通关;每枚棋子在全部六朝向独立路线无闭环;参考解答无路线格外擦碰阻挡;相邻消除之间最多连续旋转一次。参考解答检查不等于穷尽玩家的任意旋转顺序,实际阻挡对象会在游戏中标记。
|
||||
|
||||
**每关至少 65% 的参考消除路径实际经过弯道,至少 3 枚弯路棋子;空格中没有走过的弯线不计入。** 全部参考解答合计 706 次消除,其中 530 次经过弯道(75.1%);纯直出关卡 0 个。这里统计的是求解器的实际离场路径,不是任意玩家操作顺序。
|
||||
|
||||
**预计时长只用于内部比较,没有真人测试数据。** 公式为 3 × 棋子数 + 0.75 × 初始独立路线总转弯 + 4 × 最少旋转。所有时间均为估计秒数,不能当作通关时限。
|
||||
|
||||
| 关 | 名称 | 节奏 | 格数 | 棋子 | 弯路离场 | 弯路占比 | 认知难度 | 开局可解 | 必要旋转 | 预计秒数 |
|
||||
|---|---|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| 1 | 跟着弯道走 | 进入 | 37 | 8 | 8 | 100.0% | 7 | 8 | 0 | 30 |
|
||||
| 2 | 转一下,路会变 | 换路 | 19 | 6 | 5 | 83.3% | 32 | 3 | 1 | 27 |
|
||||
| 3 | 交叉处不换线 | 展开 | 37 | 12 | 12 | 100.0% | 28 | 7 | 0 | 50 |
|
||||
| 4 | 先解开这道弯 | 小挑战 | 19 | 6 | 4 | 66.7% | 37 | 3 | 1 | 28 |
|
||||
| 5 | 一弯接一弯 | 释放 | 61 | 12 | 10 | 83.3% | 21 | 7 | 0 | 44 |
|
||||
| 6 | 把弯路连起来 | 长局回报 | 61 | 16 | 15 | 93.8% | 21 | 9 | 0 | 59 |
|
||||
| 7 | 沿着轨道看出口 | 进入 | 61 | 14 | 12 | 85.7% | 19 | 9 | 0 | 51 |
|
||||
| 8 | 换条短路 | 换路 | 19 | 6 | 4 | 66.7% | 33 | 3 | 1 | 24 |
|
||||
| 9 | 接连找到出口 | 展开 | 61 | 14 | 14 | 100.0% | 25 | 7 | 0 | 53 |
|
||||
| 10 | 小小转机 | 小挑战 | 19 | 7 | 5 | 71.4% | 42 | 3 | 1 | 34 |
|
||||
| 11 | 一路放行 | 释放 | 61 | 16 | 12 | 75.0% | 20 | 11 | 0 | 62 |
|
||||
| 12 | 铺开好心情 | 长局回报 | 61 | 18 | 14 | 77.8% | 24 | 9 | 0 | 65 |
|
||||
| 13 | 找到节奏 | 进入 | 61 | 16 | 12 | 75.0% | 17 | 11 | 0 | 57 |
|
||||
| 14 | 转出一条新路 | 换路 | 19 | 6 | 4 | 66.7% | 31 | 3 | 1 | 25 |
|
||||
| 15 | 继续向外走 | 展开 | 61 | 16 | 14 | 87.5% | 27 | 6 | 0 | 59 |
|
||||
| 16 | 先解哪一枚 | 小挑战 | 19 | 7 | 6 | 85.7% | 45 | 2 | 1 | 30 |
|
||||
| 17 | 宽阔的回报 | 释放 | 61 | 18 | 12 | 66.7% | 24 | 8 | 0 | 63 |
|
||||
| 18 | 长路也轻巧 | 长局回报 | 61 | 20 | 15 | 75.0% | 22 | 10 | 0 | 71 |
|
||||
| 19 | 慢慢看,都来得及 | 进入 | 61 | 18 | 13 | 72.2% | 23 | 9 | 0 | 64 |
|
||||
| 20 | 只换一个方向 | 换路 | 19 | 6 | 5 | 83.3% | 37 | 3 | 1 | 29 |
|
||||
| 21 | 连成顺畅的路 | 展开 | 61 | 18 | 16 | 88.9% | 29 | 6 | 0 | 66 |
|
||||
| 22 | 轻巧绕一个弯 | 小挑战 | 19 | 6 | 5 | 83.3% | 43 | 2 | 1 | 30 |
|
||||
| 23 | 松一口气 | 释放 | 61 | 20 | 13 | 65.0% | 23 | 11 | 0 | 76 |
|
||||
| 24 | 从容的大舞台 | 长局回报 | 61 | 22 | 15 | 68.2% | 23 | 10 | 0 | 77 |
|
||||
| 25 | 又是新的出口 | 进入 | 61 | 18 | 12 | 66.7% | 27 | 7 | 0 | 63 |
|
||||
| 26 | 看见新的可能 | 换路 | 19 | 6 | 6 | 100.0% | 38 | 2 | 1 | 27 |
|
||||
| 27 | 顺路解开 | 展开 | 61 | 20 | 14 | 70.0% | 29 | 6 | 0 | 71 |
|
||||
| 28 | 留意这个转角 | 小挑战 | 19 | 6 | 4 | 66.7% | 45 | 2 | 1 | 28 |
|
||||
| 29 | 满盘好走 | 释放 | 61 | 20 | 13 | 65.0% | 21 | 10 | 0 | 70 |
|
||||
| 30 | 长长的成就感 | 长局回报 | 61 | 22 | 17 | 77.3% | 26 | 9 | 0 | 79 |
|
||||
| 31 | 熟练地出发 | 进入 | 61 | 20 | 13 | 65.0% | 25 | 8 | 0 | 70 |
|
||||
| 32 | 一点小变化 | 换路 | 19 | 6 | 4 | 66.7% | 38 | 3 | 1 | 30 |
|
||||
| 33 | 接住这个节奏 | 展开 | 61 | 20 | 14 | 70.0% | 28 | 8 | 0 | 75 |
|
||||
| 34 | 两条路的相遇 | 小挑战 | 19 | 6 | 6 | 100.0% | 49 | 2 | 1 | 31 |
|
||||
| 35 | 把出口打开 | 释放 | 61 | 22 | 15 | 68.2% | 24 | 9 | 0 | 77 |
|
||||
| 36 | 顺畅走到最后 | 长局回报 | 61 | 24 | 16 | 66.7% | 25 | 10 | 0 | 84 |
|
||||
| 37 | 从容观察 | 进入 | 61 | 22 | 15 | 68.2% | 25 | 9 | 0 | 77 |
|
||||
| 38 | 换个角度看 | 换路 | 19 | 6 | 4 | 66.7% | 34 | 2 | 1 | 25 |
|
||||
| 39 | 一枚接着一枚 | 展开 | 61 | 22 | 15 | 68.2% | 28 | 8 | 0 | 80 |
|
||||
| 40 | 给路线松个结 | 小挑战 | 19 | 6 | 6 | 100.0% | 46 | 2 | 1 | 32 |
|
||||
| 41 | 轻轻一扫 | 释放 | 61 | 24 | 17 | 70.8% | 29 | 10 | 0 | 92 |
|
||||
| 42 | 大盘小心思 | 长局回报 | 61 | 25 | 21 | 84.0% | 30 | 9 | 0 | 98 |
|
||||
| 43 | 自在出发 | 进入 | 61 | 20 | 15 | 75.0% | 29 | 8 | 0 | 76 |
|
||||
| 44 | 最后一个新转角 | 换路 | 19 | 6 | 4 | 66.7% | 37 | 2 | 1 | 27 |
|
||||
| 45 | 熟悉的长路 | 展开 | 61 | 22 | 16 | 72.7% | 31 | 8 | 0 | 84 |
|
||||
| 46 | 小结轻解 | 小挑战 | 19 | 6 | 5 | 83.3% | 47 | 2 | 2 | 31 |
|
||||
| 47 | 收获一片畅通 | 释放 | 61 | 24 | 16 | 66.7% | 29 | 9 | 0 | 90 |
|
||||
| 48 | 自在回响 | 长局回报 | 61 | 25 | 17 | 68.0% | 26 | 11 | 0 | 94 |
|
||||
|
||||
## 前七关的路径教学
|
||||
|
||||
1. **跟着弯道走**:箭头决定起步方向,棋子会沿弯轨自动转向。
|
||||
2. **转一下,路会变**:转动底盘会换路,棋子和箭头留在原位。
|
||||
3. **交叉处不换线**:交叉处不会换轨,沿同一条线找到出口。
|
||||
4. **先解开这道弯**:先看谁挡住了路线,再决定消除或免费转盘。
|
||||
5. **一弯接一弯**:跟过一两处弯道,接连解开棋子的出口。
|
||||
6. **把弯路连起来**:盘面变大,仍然顺着每条弯轨逐一解开。
|
||||
7. **沿着轨道看出口**:先看完整路线,再选择出口或免费转盘。
|
||||
@@ -1,51 +0,0 @@
|
||||
# 关卡版本
|
||||
|
||||
在游戏左上角打开选关窗口,通过“关卡版本”切换。首次打开默认使用 v0.5;已保存的版本选择继续保留,不强制迁移。各版本有独立的上次选关位置与通关记录。切换时重新开始目标版本上次选择的关卡,不保存进行到一半的棋盘。
|
||||
|
||||
原始版本的设计理念、案例和逐关结构清单见 [v0.1 · 最初 24 关设计理念](v0.1-design-philosophy.md)。本文记录版本管理;两者共同为后续优化提供参照。
|
||||
|
||||
| 版本 | 内容 | 关数 | 章节 | 布局来源 |
|
||||
| --- | --- | ---: | --- | --- |
|
||||
| v0.1 · 最初设计 | 最初制作的完整关卡,保留名称、顺序、轨道、棋子和原离场额度 | 24 | 3 章 × 8 关 | `ef2724b` 的 `levels/campaign.json` |
|
||||
| v0.2 · 直线较多版 | 扩展为 48 关时的设计,直线较多 | 48 | 8 章 × 6 关 | `70b021d` 的 `levels/campaign.json` |
|
||||
| v0.3 · 弯轨观察版 | 弯轨教学与观察版本 | 48 | 8 章 × 6 关 | `levels/campaign-seeds.json`;发布快照归档于 `levels/versions/v0.3.json` |
|
||||
| v0.4 · 长路与惊喜 | 长路巡游、轻巧反差、清挡与往返换路体验版 | 20 | 4 组 × 5 关 | `levels/v0.4-seeds.json`,生成 `levels/v0.4.json` |
|
||||
| v0.5 · 千段轨迹 | 六类形态 × 五种体验交替编排 | 1000 | 20 章 × 50 关 | `levels/v0.5-recipes.json`,冻结 `levels/v0.5.json` |
|
||||
|
||||
版本号指关卡布局。五版统一使用当前界面、碰撞检测、免费旋转、免费失败试路与撤销规则,包括快速连点与多枚同时离场。旧版文件的 `moveLimit` 原样保留,游戏主界面仍显示待解棋子数。JSON 内的 `version: 1` 是数据格式版本,与 v0.1 等布局版本号无关。
|
||||
|
||||
v0.1 的旧闭环与扫掠阻挡也原样保留,可以通过旋转和消除找到解答。24 关与 v0.2 的 48 关均已在当前引擎中求解并完整回放。v0.3 的“每关至少 65% 参考消除路径经过弯道”等发布门槛仅适用于该版,不套用于历史布局。
|
||||
|
||||
v0.4 按[新版关卡设计准则](level-design-principles-v2.md)单独制作,全部 20 关同时验证最少旋转参考解和完整体验解。反差关的体验解会直接旋转并启动朝内目标,可能与求解器先清除所有可出棋子的次序不同。逐关关键棋子、路径与验收范围见 [v0.4 体验报告](v0.4-experience-review.md)。
|
||||
|
||||
v0.4 选关按钮展示“长路巡游、轻巧反差、清挡放行”等体验类型;旧版继续展示原难度标签。结构分仍保留在分析中,但不将长路线直接等同于高推理难度。
|
||||
|
||||
v0.5 选关按章显示,每页 50 关,可直接输入关号;`?campaign=v0.5&level=1000` 可直达第 1000 关。难度采用独立的结构预估,不把长路转弯数加入难度分。每关验证独立最少旋转解、作者解和 20 种策略;六种核心策略与十四种随机探索共同验收,按组记录,均不是玩家概率。[制作报告](v0.5-production-report.md)和[审核页](http://localhost:4173/labs/campaign-review/index.html)记录具体范围。
|
||||
|
||||
## 归档与生成
|
||||
|
||||
- `levels/versions/v0.1.json`、`v0.2.json`、`v0.3.json` 是对应 Git 文件的原始字节,不重新序列化。
|
||||
- `levels/versions/provenance.json` 记录来源完整提交、Git blob、SHA-256、字节数、关数与回放结果。
|
||||
- `npm run levels:versions` 校验归档哈希,生成 `src/levels-archive.js`,供浏览器直接导入。
|
||||
- `src/campaign-versions.js` 注册版本、章节、关卡模块与旧存档键;`src/levels.js` 保持 v0.3 接口,供原生成器、设计指南与 Cocos 示例使用;`src/levels-v04.js` 暴露 v0.4,浏览器默认选择由版本注册表决定。
|
||||
- `npm run levels` 重新生成 v0.3,再同步历史模块。`npm run levels:v04` 从新制作卡生成 20 关、双方案回放数据和体验报告。
|
||||
- `npm run levels:v05` 从确定性制作计划生成 1000 关;`npm run levels:v05:verify` 检查源码指纹、逐关重新求解与完整回放。
|
||||
- `npm run build` 校验历史归档、生成并验证 v0.4、验证冻结 v0.5,五版均进入静态站点。各版布局来源相互独立。
|
||||
|
||||
后续发布新的布局版本时,先将当前主线与出处归档、登记哈希,再在注册表中添加新版本并更新默认版本。为新版本分配新的存档键,不复用旧版完成记录。历史归档保持不变;为历史布局改版应另发版本,不能直接覆盖。
|
||||
|
||||
## 进度隔离与迁移
|
||||
|
||||
版本选择保存在 `hex-trails-campaign-version`,各版进度保存在 `hex-trails-campaign-v0.1`、`hex-trails-campaign-v0.2`、`hex-trails-campaign-v0.3`、`hex-trails-campaign-v0.4`。旧键仅在对应新键不存在时读取,写入新键,不删除或覆盖旧数据。v0.4 使用新存档槽,不读取旧版完成记录。
|
||||
|
||||
| 目标版本 | 对应旧存档键 |
|
||||
| --- | --- |
|
||||
| v0.1 | `hex-trails-v2` |
|
||||
| v0.2 | `hex-trails-observe-v3-r1`(若存在),否则 `hex-trails-observe-v3` |
|
||||
| v0.3 | `hex-trails-observe-v3-r2` |
|
||||
| v0.4 | 无,独立新存档 |
|
||||
| v0.5 | 无,使用 `hex-trails-campaign-v0.5` 独立新存档 |
|
||||
|
||||
v0.2 与 v0.3 内部关卡 ID 相同但布局不同,完成记录只按版本隔离,不能按 ID 合并。非法版本回到默认版本,越界关卡索引回到该版第一关,完成列表过滤越界值和重复值。浏览器不允许保存时,当前页面仍可切换并保留各版进度,刷新后无法保留。
|
||||
|
||||
自动测试验证历史文件与模块一致、前三版 120 关完整回放、v0.4 双方案回放和替代顺序探索、版本数量与章节、默认选择、跨版本隔离、旧存档迁移与异常存储。Cocos 示例仍通过原接口加载 v0.3;本次未移植 v0.4 到原生工程、实现原生版本选择控件或完成原生实机验证。
|
||||
@@ -1,114 +0,0 @@
|
||||
# 环路车场:转盘发车玩法研发记录与阶段结论
|
||||
|
||||
记录日期:2026-09-10\
|
||||
当前状态:**暂缓研发,保留 Demo、实现和测试,供后续复盘。**
|
||||
|
||||
## 阶段结论
|
||||
|
||||
本轮已经验证了车辆沿复杂轨道行驶、旋转道路、自动批量放行和提前错峰调度的技术可行性。路线提示、状态说明和连续行驶表现也经过多次调整。
|
||||
|
||||
但当前玩法仍没有提供足够明显的策略乐趣。最终试玩反馈是:**“比较无聊,没有策略点。”** 玩家主要在左右转动和发车之间循环;系统处理了车辆选择、出车顺序和交通冲突,玩家缺少需要权衡后果的决定。已有的目标转动次数,尚未让这种取舍在体验中成立。
|
||||
|
||||
本轮决定先暂停这个方向。订单、旋转预算、局部道岔等改进只完成了讨论,尚未实施,也未通过试玩验证。
|
||||
|
||||
## 1. 实验起点与玩法假设
|
||||
|
||||
实验以独立的 Car Loop Lab 开展,不修改主游戏的规则和主线关卡。
|
||||
|
||||
基础结构是方格或六角内部路网,加一圈同形、固定的顺时针外环。小车沿配对轨道转弯,从棋盘边缘汇入外环,最终到达右上角车库。只转动内部道路,停放车辆的位置和朝向保持不动;方格每次转 90°,六角每次转 60°。
|
||||
|
||||
最初采用“自由点车”:玩家选择车辆发车,遇到前车或交叉冲突时停车,空间清空后继续。之后提出“转盘发车”:把逐辆点击交给系统,让玩家集中处理道路无法继续放行的节点。
|
||||
|
||||
新模式的假设是:降低逐辆操作的负担,通过左右转向和转动次数形成规划挑战。需要验证的核心问题是:**自动化之后,留下的玩家决定是否仍然有趣。**
|
||||
|
||||
## 2. 研发演进与反馈
|
||||
|
||||
以下按迭代顺序记录,不代表每个阶段都经过独立的用户研究。
|
||||
|
||||
| 阶段 | 实现和调整 | 触发反馈与认识 |
|
||||
| --- | --- | --- |
|
||||
| 基础车场 | 支持方格、六角路网,短车身和明显的车顶箭头,沿曲线转向并驶向车库 | 外环需要贴合内部棋盘轮廓:方盘配方环,六角盘配六角环 |
|
||||
| 即时多车发车 | 自由点车由起点排队改为点击立即出发,多车同时行驶,途中检测真实占位和交叉冲突 | 逐辆等待影响操作响应;发车指令应立即可见 |
|
||||
| 长路线与规模 | 增加真实多弯路线和 10/16/22 辆样本;另做 96 辆桌面关卡,六角 169 格、方格 15×15 | 验证长路径、大棋盘和大批车辆的表现;页面随后改为适配窗口、去掉滚动条和过多留白 |
|
||||
| 视觉整理 | 参考 Hex Video Lab v2;调整车辆大小和白箭头,移除车身下方多余色条,减弱道路对比和格缝,移除六角外缘伸出的引道线 | 试玩反馈棋盘显得乱、看久容易疲劳;复杂路线需要更克制的背景表现 |
|
||||
| 交通问题修复 | 修复未发车车辆“预占未来整条路线”造成的误阻挡;处理两车互卡、自由模式自动演示停滞等问题 | 看起来能走却停住,会破坏规则可信度;自由模式仍保留途中让行 |
|
||||
| 转盘发车初版 | 底部改为左转/发车/右转;系统依当前方向逐辆放行,不自动转盘;无车可走时由玩家转向后再次发车 | 希望减少逐车操作,让玩家处理每轮的转向节点;同时修正左右旋转按钮的箭头表现 |
|
||||
| 路径解释与关卡目标 | 发车时显示车身同色的实际路径;两种棋盘各制作三个 16 辆关卡,加入目标转动次数与左右方向差异 | 自动运行时玩家看不到原先靠悬停才出现的路线;关卡需要体现转向和次数的作用 |
|
||||
| 整轮放行与状态说明 | 一次启动本轮可放行车辆;显示可发车、放行中、需转盘、到站中等状态;路线改用原悬停提示的线型,移除外环尾迹 | 串行发车让人无法判断“还有车能走”还是“只是在等动画”;运行阶段需要明确 |
|
||||
| 提前错峰调度 | 从途中停车让行,改为根据完整行程安排出发时刻;独立路线并行,有冲突的车在原位倒计时后出发 | 车辆贴在一起等待令人不舒服;调度要同时覆盖交叉口、外环汇入和终点,避免把拥堵移到出口 |
|
||||
| 路线颜色收敛 | 所有转盘发车路线统一恢复为原来的绿色提示线,保留淡色光晕;出盘后收起 | 试玩更偏好原版绿色提示,不再按车身颜色绘制多色路线 |
|
||||
| 乐趣评估与暂缓 | 操作和通行已较顺畅,但玩家认为玩法无聊、没有策略点 | 本轮决定先放下,记录过程与结论;后续建议停留在讨论阶段 |
|
||||
|
||||
## 3. 暂缓时保留的版本
|
||||
|
||||
### 玩家操作
|
||||
|
||||
- 进入“转盘发车”模式后,左、右按钮仅转动内部道路,中间按钮安排当前朝向下可放行的整批车辆。
|
||||
- 发车不自动旋转。转盘后也不会自动发车,需要玩家再次点击中间按钮。
|
||||
- 有冲突的车辆在起点等待自己的通行时段,显示短倒计时;已出发的车辆沿预定轨迹连续前进。
|
||||
- 放行阶段显示待发、盘内、外环数量,尚未实际起步的车辆仍计入“待出发”。盘内放行及待发安排完成后,才允许继续转盘。
|
||||
- 统一使用绿色 `#329378` 提示路线:淡色光晕、实线与端点。车辆离开棋盘后收起提示,外环不显示尾迹。
|
||||
- 默认 2× 速度,可调 1–3×。目标转动次数用于评价,目前不是硬性失败条件;颜色不承担订单或通行规则。
|
||||
- 自由点车模式作为对照保留,仍采用即时出发和实时停车让行。96 辆超大样本属于自由模式,转盘发车模式使用专门的 16 辆样本。
|
||||
|
||||
### 可复现的转盘发车样本
|
||||
|
||||
下表来自当前 `rotationPlan()` 的求解结果。左右序列是最少转动次数的一组参考解,不表示只有这一条解。每次转动后都要发车;批次车辆数的第一项是初始朝向直接发车的数量。
|
||||
|
||||
| 棋盘 | 关卡 | 种子 | 目标转数 | 参考转向 | 各轮放行数量 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 六角 | 转向开路 | 3 | 2 | 左、左 | 2、8、6 |
|
||||
| 六角 | 折返放行 | 14 | 2 | 右、左 | 3、7、6 |
|
||||
| 六角 | 连续调度 | 8 | 4 | 左、左、左、左 | 3、1、5、2、5 |
|
||||
| 方格 | 转向开路 | 6 | 2 | 右、右 | 6、4、6 |
|
||||
| 方格 | 折返放行 | 12 | 2 | 左、右 | 7、4、5 |
|
||||
| 方格 | 连续调度 | 19 | 3 | 左、左、左 | 4、4、5、3 |
|
||||
|
||||
六个关卡在初次放行之后,先向左或向右的最少总转动次数不同;第二关的最优解需要折返。这证明了关卡存在方向差异,但目前的体验反馈表明:**计算上的差异还没有转化为足够清楚、有吸引力的玩家决策。**
|
||||
|
||||
## 4. 已验证的内容与证据范围
|
||||
|
||||
- 调度改动后的最近一次完整回归为 `npm test`:100 项通过;`npm run build` 通过。之后的绿色路线调整完成语法检查、静态构建和浏览器视觉检查。本记录本身是文档变更,没有重新运行整套测试。
|
||||
- 真实应用帧循环测试覆盖六个转盘发车关卡通关、先走另一转向后的继续通关、禁止自动转盘、转后等待发车、重置和切换模式取消待发安排。
|
||||
- 调度测试覆盖互不冲突的路线同时出发、交叉路线错峰但行程仍可重叠、帧间扫掠碰撞、上一轮车辆预订通行时段,以及弯道、汇入口、外环、车库的车距。
|
||||
- 测试中途切换 1×/3×/1.5×,并使用变化的帧间隔;所有车辆共享同一模拟时钟,避免速度变化打乱调度。
|
||||
- 浏览器实测六角“转向开路”第一轮两车并行;左转后八车一轮中,三车先发、五车待发,随后接续完成。还检查了窄窗口布局和不同车身颜色使用同一绿色路线。
|
||||
- 本轮验证针对浏览器实验实现,没有完成原生引擎移植验证。
|
||||
|
||||
上述证据支持运行正确性和表现改进,不能据此证明游戏有趣。本轮乐趣判断来自研发过程中的定性试玩反馈,尚无独立样本的通关率、重复游玩意愿等数据。
|
||||
|
||||
## 5. 为什么目前缺少策略感
|
||||
|
||||
以下是对反馈的设计解释,仍需后续实验验证。
|
||||
|
||||
1. **系统接管了大部分操作决定。** 玩家不再选择具体车辆、顺序和避让方式,剩下的动作主要是左右转动及整批发车。
|
||||
2. **试错代价较弱。** 当前目标是全部清空,多转几次依然可以继续。目标转数虽存在,但尚未形成玩家愿意追求的挑战。
|
||||
3. **决策后果难以读懂。** 整盘道路复杂,玩家不容易在转动前预测这一转将释放谁、会为下一轮留下什么方向。绿色路线解释的是正在发生的运动,对转动前的规划帮助有限。
|
||||
4. **放走车辆通常只带来单向收益。** 车辆离开会腾出空间,当前规则很少要求玩家为后续目的保留某辆车或某个通行机会。
|
||||
5. **观看占比仍高。** 多弯轨迹和大量车辆能够增加动画内容,却没有相应增加有意义的决定。
|
||||
|
||||
值得保留的经验是:清晰状态、统一提示线、真实路线和提前错峰,让玩家更容易理解并舒服地观看运行。但下一轮若恢复研究,优先需要验证决策本身,而不是继续扩大车辆数量和路线长度。
|
||||
|
||||
## 6. 已讨论、尚未实施的方向
|
||||
|
||||
| 方向 | 希望产生的决定 | 当前判断 |
|
||||
| --- | --- | --- |
|
||||
| 出车订单 | 例如先送红车再送蓝车,展示当前与下一单;玩家同时考虑当前任务和下一批所需道路方向 | 优先候选。颜色将成为规则;需要重新设计可解的关卡,尚无玩法验证 |
|
||||
| 更清楚的旋转目标 | 例如三次内得金牌,转动消耗可见标记,允许撤销;让当前收益与后续转动成本有关联 | 与订单结合更值得测试,单独强化已有转数显示可能仍不足 |
|
||||
| 一个局部道岔 | 选择接通哪一条路,并限制切换次数,形成更直观的局部取舍 | 备选方向,需要验证额外控件是否值得其复杂度 |
|
||||
|
||||
讨论中的首选小实验是“订单+旋转目标”:8~10 辆车、两种颜色,同时展示当前和下一单,沿用错峰发车,并增加撤销操作。关卡刻意设置一种情况:眼前最容易完成的选择,会让下一批多花一次转动。
|
||||
|
||||
这些属于恢复研发时的候选假设,**不是已采纳的下一阶段开发计划**。重新评估时可观察:玩家能否说明自己的选择理由,是否会主动考虑下一批,是否能理解转错的代价,以及通关后是否愿意重试更少转数的解。
|
||||
|
||||
## 7. 恢复研究时的入口
|
||||
|
||||
- [转盘发车 · 六角 Demo](http://localhost:4173/labs/car-loop/index.html?mode=batch&kind=hex)
|
||||
- [转盘发车 · 方格 Demo](http://localhost:4173/labs/car-loop/index.html?mode=batch&kind=square)
|
||||
- [Lab 使用说明](../labs/car-loop/README.md),[早期视觉适配记录](../labs/car-loop/design.md)
|
||||
- [玩法与关卡规划](../labs/car-loop/batch.js):当前朝向放行、双向旋转搜索、样本种子。
|
||||
- [完整行程调度](../labs/car-loop/schedule.js),[出盘与车库轨迹](../labs/car-loop/routes.js)。
|
||||
- [模型与求解](../labs/car-loop/model.js),[自由模式实时交通](../labs/car-loop/motion.js),[界面与渲染](../labs/car-loop/app.js)。
|
||||
- [模型、交通与调度测试](../tests/car-loop.test.js),[批次关卡测试](../tests/car-loop-batch.test.js),[真实应用帧循环测试](../tests/car-loop-app.test.js)。
|
||||
|
||||
启动:在项目根目录运行 `npm run dev`。转盘发车模式的专项验证:`node --test tests/car-loop.test.js tests/car-loop-batch.test.js tests/car-loop-app.test.js`。
|
||||
+1
-1
@@ -36,7 +36,7 @@ hex-trails/
|
||||
4. `levelIndex` 选择内置关卡,或把单关 JSON 赋给 `levelAsset`。
|
||||
5. 按钮绑定 `rotateLeft()`、`rotateRight()`、`undo()`、`restart()`、`hint()`。
|
||||
6. 监听 `trail-state`,更新步数、剩余棋子、朝向、胜负和忙碌状态。监听 `trail-hint-rotation` 高亮对应旋转按钮;`trail-blocked` 可接声音/震动。
|
||||
7. 按 `THEME.background` 设置纯色背景;当前主界面只保留居中的 Level、其下方的待解棋子数量,以及左侧选关、右侧设置。按钮与面板使用下述图片皮肤,动态文字与布局使用 Label、Button、Layout、Widget、EditBox、ScrollView 等节点搭建。原生端不需要 WebView。
|
||||
7. 按 `THEME.background` 设置纯色背景;当前主界面只保留居中的 Level、其下方的剩余步数,以及左侧选关、右侧设置。按钮与面板使用下述图片皮肤,动态文字与布局使用 Label、Button、Layout、Widget、EditBox、ScrollView 等节点搭建。原生端不需要 WebView。
|
||||
|
||||
## 坐标与动画
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,29 +0,0 @@
|
||||
# 花形轨道 · 重瓣实验
|
||||
|
||||
入口:[花有出路 · 重瓣](http://localhost:4173/labs/flower/index.html)。这是独立的图案关测试,不加入 v0.4,不读写主线进度。
|
||||
|
||||
## 图案结构
|
||||
|
||||
用半径 5 的 91 格标准六边形承载路线。每个扇区有一大一小两片嵌套花瓣,旋转重复六次,形成双层十二瓣;相邻外瓣交错穿过。花心外围还有三道环带,在六个径向交点重新配对端口,把环带接进花瓣的行驶路线。整体呈放射对称的重瓣花,兼有内外层次和环形编织。
|
||||
|
||||
图案全部由实际端口配对形成,没有背景花朵图片。每格仍完整保留三条连接;177 条连接构成深色花纹,占全部 273 条连接约 65%。其他连接用细线显示。参考解会经过全部深色连接(出发格使用其外向半段),三道环带均已接通,不留下只供装饰的闭环。“暂隐棋子,看完整花纹”便于观察完整图案;“全部轨道等粗显示”用于检查端口连接。
|
||||
|
||||
花瓣和环带具有六重旋转对称,花心连接具有三重旋转对称。旋转 60° 后图案仍保持秩序,但花心连接变化,改变棋子所通向的出口。
|
||||
|
||||
## 可玩结构
|
||||
|
||||
- 共 10 枚棋子:外围 6 枚,内层 4 枚。
|
||||
- 开局 2 枚朝外棋子先离场,空出出口。
|
||||
- 内层 4 枚依次走过 13–33 个格步骤,包含 8–21 次转弯,逐步展示编织结构。
|
||||
- 外围 4 枚朝内棋子走完整的跨花瓣长路:每条 59 个格步骤、37 次转弯。
|
||||
- 参考解最后剩两枚时需要旋转一次,换接已空出的出口。
|
||||
- 试路失败和旋转均免费,支持撤销、重来和提示,沿用现有动画与碰撞规则。
|
||||
- 复用主游戏的点击队列:行驶或转盘动画期间可快速连点,待出发棋子显示描边,并按点击顺序在最新棋盘状态下执行。重复点击不重复入队;遇阻、撤销或重来会清空后续队列。
|
||||
|
||||
参考解:`petal-0 → petal-2 → bloom-2 → bloom-3 → bloom-0 → bloom-1 → petal-1 → petal-5 → 右转 → petal-3 → petal-4`。
|
||||
|
||||
## 验证
|
||||
|
||||
关卡通过格式校验与求解;参考回放没有格外阻挡。所有棋子在六个朝向下的独立路线都可离场且全程沿深色花纹行驶。测试也覆盖花纹的真实路线使用、最后一对的旋转解锁与撤销,以及六种起始朝向、正反消除顺序的通关。
|
||||
|
||||
布局与花纹定义见 [flower-study.js](../src/flower-study.js),实验界面见 [labs/flower](../labs/flower/index.html)。图案辨识度需要继续结合实际体验评估;未做原生引擎实机验证。
|
||||
@@ -1,154 +0,0 @@
|
||||
# HEX TRAILS 玩法方向与主线制作要求
|
||||
|
||||
版本:2026-09-09。本文用于关卡制作、生成器筛选与玩法验收,不规定美术样式。
|
||||
|
||||
适用范围:本文记录后续 48 关、尤其 v0.3 的制作方向。最初 24 关的设计理念另见 [v0.1 设计理念](v0.1-design-philosophy.md);本文的弯轨比例、无闭环及六拍门槛不代表原版要求。下一轮优化将对照原版结构讨论,本轮未改关卡。
|
||||
|
||||
当前方向是让喜欢轻松观察、逐步整理并获得连续反馈的玩家,在越来越丰富的棋盘上保持推进感。玩家偏好以观察行为、试路习惯和体验反馈描述,不按性别推断。9 月 9 日版通过[种子清单](../levels/campaign-seeds.json)重新编排全部 48 关,将真正经过弯道的成功离场路径作为制作核心;逐关结构记录见 [主线验收表](campaign-review.md)及[完整分析数据](../levels/campaign-analysis.json)。验收结论以当前清单重新生成的报告与测试输出为准,不能沿用旧关卡结果;玩家体验和真实完成时长仍待真人测试。
|
||||
|
||||
## 1. 核心循环
|
||||
|
||||
**观察 → 改变 → 得到可解释的反馈 → 再观察。**
|
||||
|
||||
玩家先辨认一个可能的出口,再点击棋子或旋转棋盘改变路线。成功时,棋子离场,剩余工作量减少;被挡时,移动棋子到达可理解的接触位置,与阻挡棋子产生明确反馈并返回。旋转后应能观察到路线或可行选择的变化。
|
||||
|
||||
试路是学习规则的一部分。一次没有成功的尝试应帮助玩家理解阻挡原因,不能同时带来隐性的通关成本。主线不靠最后一枚棋子的隐藏闭环、路线之外的擦碰或连续无进展旋转制造困难。
|
||||
|
||||
玩家需要顺着实际将要走过的轨道观察出口。每一关都以弯轨消除为主,直线路径只作为少量节奏调剂,不安排纯直出关。空格上画了多少弯线不代表玩家真的需要读这些路线;没有被成功离场棋子使用的装饰性曲线不计入这一目标。
|
||||
|
||||
## 2. 免费尝试与计数语义
|
||||
|
||||
- 左转、右转免费,不扣步,也不因多转几次而失败。
|
||||
- 失败试路免费,不扣步,不移动棋子的模型位置;可另行记录尝试次数用于内部分析。
|
||||
- 每次成功移除一枚棋子计 1 次有效消除。
|
||||
- 主线初始预算设为棋子数 `N`。此预算只表示还需要完成多少次有效消除,不是限制尝试的资源。
|
||||
- 主线中,成功移除 `k` 枚后,剩余量应为 `N-k`;旋转、阻挡尝试与其他未成功的探路行为不改变它。
|
||||
- 当前朝向没有可离场棋子,不应直接判负。旋转仍是可用的探索方式。
|
||||
- 撤销应恢复真实的棋盘状态与对应计数,重开恢复原始关卡。
|
||||
|
||||
界面和关卡文案应传达剩余工作量,避免让玩家以为每次观察性尝试都会消耗通关机会。自定义关卡的数据兼容规则单独处理,不能反向成为主线的旋转限制。
|
||||
|
||||
## 3. 规模、认知难度与体验长度分开制作
|
||||
|
||||
| 维度 | 回答的问题 | 主要依据 |
|
||||
| --- | --- | --- |
|
||||
| 棋盘规模 | 可操作的空间有多大? | 底格数、棋子数、占用率与区域分布 |
|
||||
| 认知难度 | 找到下一步需要想多少? | 路线转弯、最长路线、可行选择比例、依赖关系与必要旋转判断 |
|
||||
| 工作量 | 需要完成多少次有效动作? | 待移除棋子数、解答动作数、需要经过的路线量 |
|
||||
| 体验长度估计 | 哪些候选可能更长? | 内部结构估计,后续由实测校准 |
|
||||
|
||||
认知难度不加入棋盘面积或棋子数量的直接加分项,也不加入免费尝试的步数压力。同样的规则可以放在更大棋盘上延长体验,不需要同步增加路线复杂度、堵塞比例和依赖深度。
|
||||
|
||||
早期就可使用 37 格棋盘,让玩家较早体验完整的整理过程。后期舒缓关可使用 61 格棋盘,提供更多熟悉而顺畅的消除。19 格小棋盘也可以承担较难的局部判断;它的挑战来自关系清楚但需要思考,不来自体积。
|
||||
|
||||
增加底格数而没有增加有效内容,不算延长体验;增加棋子却把所有出口堵成唯一解,也不算舒缓长局。制作时应检查是否形成足够多的连续成功机会,以及玩家能否在若干局部区域之间自然选择。
|
||||
|
||||
当前种子清单的单关棋子数最多为 25。后期长局增加的是实际需要沿弯轨观察、解开的内容,不能只沿用更多直出棋子的数量目标。比较工作量时同时查看有效消除数量、真实离场路径的转弯与连续成功机会。
|
||||
|
||||
## 4. 48 关:8 章,每章 6 拍
|
||||
|
||||
主线按章节节奏编排,不按认知难度分数从低到高排序。每章允许自然回落;后期主要增加熟悉规则下的工作量,认知挑战上限不必随章节不断升高。
|
||||
|
||||
| 章内位置 | 节奏角色 | 制作意图 |
|
||||
| --- | --- | --- |
|
||||
| 1 | 进入 | 明显可行的开局,帮助玩家恢复观察节奏;可以有较大的盘面。 |
|
||||
| 2 | 换路 | 用一次清楚的旋转或路线变化引出新进展,不堆叠多个新要求。 |
|
||||
| 3 | 展开 | 扩展已经理解的关系,增加可连续处理的棋子和局部区域。 |
|
||||
| 4 | 小挑战 | 章内认知峰值,可采用较小棋盘集中表达先后关系或一次必要旋转。 |
|
||||
| 5 | 释放 | 明显低于上一关的认知负担,让出口、连续成功和自由选择重新变多。 |
|
||||
| 6 | 长局回报 | 使用熟悉关系提供更长的整理过程;可以更大、更长,但不自动更难。 |
|
||||
|
||||
第 1 关使用 37 格、8 枚棋子。开局朝向下全部棋子可直接离场,每枚成功路径恰好经过 1 处弯道,完整解答不依赖旋转或强制先后顺序。它教的是“箭头决定起步,弯轨决定后续转向”,不承担识别闭环的任务。“全部可离场”只描述开局朝向,不要求玩家转到任意朝向后也全部可出。
|
||||
|
||||
前 7 关的学习内容写入各关的 `lesson` 字段,并与实际参考路径一起验收:
|
||||
|
||||
| 关卡 | 学习重点 |
|
||||
| --- | --- |
|
||||
| 1 | 箭头决定起步方向,沿弯轨自动转向。 |
|
||||
| 2 | 旋转底盘改变路线,棋子位置与箭头方向不动。 |
|
||||
| 3 | 交叉处不换轨,沿同一条线找到出口。 |
|
||||
| 4 | 看清阻挡关系,再决定先后消除或免费转盘。 |
|
||||
| 5 | 跟过一两处弯道,获得舒缓的连续消除。 |
|
||||
| 6 | 在更大棋盘上仍逐条解开实际弯轨路径。 |
|
||||
| 7 | 先观察完整路线,再选择出口或免费转盘。 |
|
||||
|
||||
这些学习重点补充章节六拍,不改变小挑战后释放、再以长局回报收束的节奏。
|
||||
|
||||
第 5 关的释放应落实为结构差异,例如更多初始出口、更浅的依赖、更少的必要判断,不能只换一个轻松的名字。第 6 关应延长熟悉操作的愉快过程,不用反复试方向、难以解释的阻挡或长时间等待补足时长。
|
||||
|
||||
每章不要求所有关卡都必须旋转。进入、展开、释放和长局回报允许最少旋转数为 0。判断一个关卡是否适合当前节奏,应同时查看认知指标与工作量,而不是让较大棋盘天然获得更高难度标签。
|
||||
|
||||
## 5. 发布硬门槛
|
||||
|
||||
以下条件在生成候选后执行,并保存可重复验证的结果;任一必要检查未完成时,候选不能记为已验收。
|
||||
|
||||
### 规则与可解性
|
||||
|
||||
1. 关卡通过数据校验,旋转时棋子与底格关系保持有效,六次旋转恢复原始轨道状态。
|
||||
2. 旋转和失败试路不扣主线预算;成功移除扣 1;完整回放后全部棋子离场。
|
||||
3. 求解结果必须确认可达终局。触及搜索上限只能记为“未确定”,不能用作可解性通过证据。
|
||||
|
||||
### 不出现隐藏闭环
|
||||
|
||||
对每一枚初始棋子,分别在全部 6 个棋盘朝向下忽略其他棋子追踪独立路线。每条路线都必须离场,独立闭环数必须为 0。该要求覆盖主线所有章节,避免移除障碍后才发现最后一枚棋子一直绕圈。
|
||||
|
||||
### 真正使用弯轨
|
||||
|
||||
对参考解答逐步回放,只统计成功离场时实际走过的路线。每关至少 65% 的成功离场棋子经过 1 处或更多弯道,且这类棋子至少有 3 枚;完整回放的成功移除数应等于初始棋子数。
|
||||
|
||||
统计使用 `analyze().pathUsage`,不使用整张棋盘的弯线数量,也不以初始朝向忽略占用的路线统计替代真实回放。旋转会改变轨道,成功路径必须按每次实际消除时的棋盘朝向计算。单纯增加空白格上的曲线,或让绝大多数棋子从边缘直线离场,不能满足发布要求。
|
||||
|
||||
### 阻挡可以从路线解释
|
||||
|
||||
在已验证解答回放的每个决策状态,对所有剩余棋子的路线进行检查。阻挡对象必须位于该棋子的独立路线所经过的格子中,不能出现路线格子之外的侧面擦碰阻挡。
|
||||
|
||||
这项检查不能只查看最终选中的成功移除路线,因为成功路线本来就没有阻挡,无法揭示其他可点击棋子的意外碰撞。每个 `blocked` 结果还必须指向真实存在且不是自身的棋子,并提供有效接触位置,供动画展示同一个阻挡原因。
|
||||
|
||||
### 旋转后立即出现进展
|
||||
|
||||
换路关和小挑战关的已验证解答中,相邻有效消除之间最多出现 1 次连续旋转。安排为必要步骤的这次旋转必须打开至少一个可消除选择,不能要求玩家先做一次没有进展的旋转,再猜第二次方向。
|
||||
|
||||
免费旋转不等于每个任意方向都保证成功,但正式解答和教学顺序必须有清晰因果。发布时同时检查旋转动画与模型更新一致,下一次点击使用旋转后的实际轨道。
|
||||
|
||||
### 节奏与计量
|
||||
|
||||
每关记录章节、节奏角色、底格数、棋子数、认知指标与工作量。完成 48 关的组内检查:小挑战之后确有释放,长局回报的工作量增长没有被等量的认知负担增长抵消。这里要求的是候选结构和回放验证,玩家的实际感受仍需后续测试。
|
||||
|
||||
### 来源与可重复验证
|
||||
|
||||
`levels/campaign-seeds.json` 保存全部 48 关的种子与生成参数,是主线布局的制作来源;不能只编辑生成后的 `campaign.json`。修改清单后运行 `npm run levels`,同步关卡、共享模块与报告,再运行测试。
|
||||
|
||||
`levels/campaign-analysis.json` 中每关的 `pathUsage` 记录真实参考成功路径,包括直出/弯轨棋子数、弯轨比例、单弯/多弯数量、总转弯、最长连续直出段,以及逐棋子的路径明细。前 7 关还应核对 `lesson` 是否被实际动作支持。报告记录的是参考解答,不是穷尽玩家所有任意旋转和点击顺序。
|
||||
|
||||
## 6. 内部时长假设
|
||||
|
||||
当前仅用下式比较候选的潜在体验长度:
|
||||
|
||||
```text
|
||||
估计秒数 = 3 × N + 0.75 × 总转弯数 + 4 × 最少旋转数
|
||||
```
|
||||
|
||||
`N` 是初始棋子数;总转弯数采用当前分析器对初始朝向、忽略占用时各棋子独立路线的转弯数求和;最少旋转数来自规则求解器。各系数都是内部制作假设,尚未经过真人用时标定。
|
||||
|
||||
上述总转弯口径与 `pathUsage.totalBends` 的实际参考成功路径口径不同,不得混用。后者用于验证弯轨体验与阅读负担,前者仍是现行估时公式的输入;即使弯轨比例达到发布要求,也不能据此宣称真人体验时长已增加。
|
||||
|
||||
该结果不是玩家平均通关时长、完成承诺或难度分数。它没有完整模拟玩家的扫描速度、主动停顿、错误尝试、动画等待、提示使用与设备差异。大棋盘的估计数值更高,只能说明当前结构模型认为工作量更大,不能据此宣称玩家一定会玩得更久或更开心。
|
||||
|
||||
候选尚未确认可解、出现独立闭环或搜索未确定时,不应将估时作为可发布关卡的数据。公式调整时保留版本,避免把不同计算口径下的数字当作体验提升证据。
|
||||
|
||||
## 7. 后续玩家测试
|
||||
|
||||
先验证轻松观察与持续推进的体验,再决定是否需要调整公式或节奏。当前没有可引用的玩家统计结果。
|
||||
|
||||
| 观察项 | 记录与解释方式 |
|
||||
| --- | --- |
|
||||
| 主动停顿 | 区分玩家正在看路线的停顿、动画占用时间与离开游戏的空闲;不能把全部停顿都解释成困难。 |
|
||||
| 成功消除间隔 | 观察连续成功是否顺畅,以及卡顿是否集中在少数阶段;结合动画时间判断。 |
|
||||
| 旋转到下一次成功的间隔 | 记录是否能理解旋转带来的新机会,是否出现反复空转和方向试探。 |
|
||||
| 失败试路与原因 | 区分明确的路线占用、无法解释的接触和误触;尝试次数多不自动意味着体验差。 |
|
||||
| 最后一枚棋子阶段 | 观察是否出现突然的理解断点、长停顿或依赖提示结束。 |
|
||||
| 提示、撤销与重开 | 结合发生阶段和玩家描述解释原因,避免仅用总次数判定关卡质量。 |
|
||||
| 挑战后的感受 | 比较第 4、5、6 关的主动停顿、连续成功和主观轻松程度,确认释放与回报确实发生。 |
|
||||
| 活跃完成时长 | 从首次有效交互到通关分段记录,并排除明确离开游戏的时间;与工作量、提示使用一起分析。 |
|
||||
|
||||
测试反馈应以可观察行为与玩家自己的描述为依据。需要延长后期单关时,优先增加熟悉且可顺畅处理的内容;只有在理解与反馈都清楚时,才增加少量新的判断要求。
|
||||
@@ -1,244 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta http-equiv="refresh" content="60">
|
||||
<title>50 关任务看板</title>
|
||||
<style>
|
||||
:root{
|
||||
--ground:#EEF1F4; --surface:#FFFFFF; --inset:#E3E8ED; --panel:#F7F9FA;
|
||||
--ink:#141E28; --ink2:#48596A; --ink3:#6B7A88;
|
||||
--rule:#D3DAE1; --rule2:#BFC9D2;
|
||||
--rail:#435F78; --rail-soft:#8FA6BA;
|
||||
--bad:#B23A26; --bad-soft:#F2DDD8;
|
||||
--warn:#8A5C0F; --warn-soft:#F4E9D4;
|
||||
--good:#236E64; --good-soft:#D9EDEA;
|
||||
--live:#1F6FB2; --live-soft:#DCE9F4;
|
||||
--shadow:0 1px 2px rgba(20,30,40,.06),0 6px 18px rgba(20,30,40,.05);
|
||||
color-scheme:light;
|
||||
}
|
||||
@media (prefers-color-scheme:dark){:root:not([data-theme=light]){
|
||||
--ground:#0F161C; --surface:#141D25; --inset:#0A1015; --panel:#141D25;
|
||||
--ink:#E4EAEF; --ink2:#AEBDC9; --ink3:#8494A2;
|
||||
--rule:#28343F; --rule2:#35434F;
|
||||
--rail:#8CB0CC; --rail-soft:#4E6577;
|
||||
--bad:#E4836C; --bad-soft:#3A211B;
|
||||
--warn:#E0AE5E; --warn-soft:#33280F;
|
||||
--good:#4FC7B7; --good-soft:#11302C;
|
||||
--live:#6BB3EE; --live-soft:#12283A;
|
||||
--shadow:0 1px 2px rgba(0,0,0,.3),0 6px 18px rgba(0,0,0,.28);
|
||||
color-scheme:dark;
|
||||
}}
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;background:var(--ground);color:var(--ink);
|
||||
font-family:"PingFang SC","Hiragino Sans GB","Microsoft YaHei",ui-sans-serif,system-ui,-apple-system,sans-serif;
|
||||
line-height:1.7;-webkit-font-smoothing:antialiased}
|
||||
.wrap{max-width:1080px;margin:0 auto;padding:0 24px 80px}
|
||||
code,.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums}
|
||||
header.head{padding:48px 0 26px;border-bottom:1px solid var(--rule);margin-bottom:30px}
|
||||
.eyebrow{font-size:11.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink3);margin-bottom:12px}
|
||||
h1{font-size:clamp(26px,4vw,38px);line-height:1.2;margin:0 0 14px;letter-spacing:-.02em;text-wrap:balance}
|
||||
.meta{font-size:12.5px;color:var(--ink3)}
|
||||
.progress{margin:22px 0 0}
|
||||
.progress .bar{height:10px;background:var(--inset);border-radius:6px;overflow:hidden}
|
||||
.progress .bar i{display:block;height:100%;background:var(--good);border-radius:6px;transition:width .4s}
|
||||
.progress .lbl{display:flex;justify-content:space-between;font-size:12.5px;color:var(--ink2);margin-top:7px}
|
||||
h2{font-size:21px;margin:44px 0 6px;letter-spacing:-.01em}
|
||||
h2 .num{color:var(--rail-soft);font-family:ui-monospace,monospace;font-size:14px;margin-right:9px}
|
||||
p{margin:0 0 12px;max-width:74ch}
|
||||
.sub{color:var(--ink2);font-size:14px}
|
||||
.card{background:var(--surface);border:1px solid var(--rule);border-radius:12px;padding:18px 20px;box-shadow:var(--shadow);margin:16px 0}
|
||||
.callout{border-left:3px solid var(--rail);background:var(--panel);border-radius:0 10px 10px 0;padding:14px 18px;margin:16px 0}
|
||||
.callout p:last-child{margin-bottom:0}
|
||||
.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(176px,1fr));margin:16px 0}
|
||||
.tile{background:var(--surface);border:1px solid var(--rule);border-radius:12px;padding:14px 16px}
|
||||
.tile .k{font-size:11px;letter-spacing:.06em;color:var(--ink3);text-transform:uppercase}
|
||||
.tile .v{font-family:ui-monospace,monospace;font-size:25px;font-weight:600;line-height:1.25;margin-top:3px}
|
||||
.tile .n{font-size:12px;color:var(--ink2);margin-top:2px}
|
||||
.tile.ok .v{color:var(--good)} .tile.miss .v{color:var(--bad)} .tile.warn .v{color:var(--warn)}
|
||||
table{width:100%;border-collapse:collapse;font-size:13.5px;margin:14px 0}
|
||||
th,td{text-align:left;padding:8px 10px;border-bottom:1px solid var(--rule)}
|
||||
th{font-size:11px;letter-spacing:.06em;color:var(--ink3);text-transform:uppercase;font-weight:600;white-space:nowrap}
|
||||
td.n,th.n{text-align:right;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;white-space:nowrap}
|
||||
.scroll{overflow-x:auto}
|
||||
.tag{display:inline-block;font-size:11px;padding:2px 9px;border-radius:20px;font-weight:600;white-space:nowrap}
|
||||
.tag.good{background:var(--good-soft);color:var(--good)}
|
||||
.tag.bad{background:var(--bad-soft);color:var(--bad)}
|
||||
.tag.live{background:var(--live-soft);color:var(--live)}
|
||||
.tag.idle{background:var(--inset);color:var(--ink3)}
|
||||
.phase{margin:24px 0}
|
||||
.phase h3{font-size:15.5px;margin:0 0 4px;display:flex;align-items:center;gap:10px}
|
||||
.phase h3 .pid{font-family:ui-monospace,monospace;font-size:11.5px;color:var(--surface);background:var(--rail);border-radius:5px;padding:2px 7px}
|
||||
.tasks{list-style:none;margin:10px 0 0;padding:0;border-left:2px solid var(--rule);margin-left:6px}
|
||||
.tasks li{position:relative;padding:9px 0 9px 22px}
|
||||
.tasks li::before{content:'';position:absolute;left:-6px;top:17px;width:10px;height:10px;border-radius:50%;
|
||||
background:var(--ground);border:2px solid var(--rule2)}
|
||||
.tasks li.done::before{background:var(--good);border-color:var(--good)}
|
||||
.tasks li.doing::before{background:var(--live);border-color:var(--live);box-shadow:0 0 0 4px var(--live-soft)}
|
||||
.tasks li.blocked::before{background:var(--bad);border-color:var(--bad)}
|
||||
.tasks .t{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
|
||||
.tasks .tid{font-family:ui-monospace,monospace;font-size:11.5px;color:var(--ink3)}
|
||||
.tasks .tt{font-size:14.5px;font-weight:500}
|
||||
.tasks li.done .tt{color:var(--ink2)}
|
||||
.tasks .note{font-size:12.5px;color:var(--ink3);margin-top:1px}
|
||||
.rules li{margin-bottom:8px}
|
||||
.rules b{font-weight:650}
|
||||
.rules .how{font-size:12px;color:var(--ink3);margin-left:6px}
|
||||
.log{list-style:none;padding:0;margin:12px 0}
|
||||
.log li{padding:8px 0 8px 16px;border-left:2px solid var(--rule);font-size:13.5px;color:var(--ink2)}
|
||||
.log li b{color:var(--ink);font-weight:600;font-family:ui-monospace,monospace;font-size:12px;margin-right:8px}
|
||||
footer{margin-top:56px;padding-top:20px;border-top:1px solid var(--rule);color:var(--ink3);font-size:12px}
|
||||
@media(max-width:640px){.wrap{padding:0 16px 60px}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<header class="head">
|
||||
<div class="eyebrow">HEX TRAILS · 关卡调优</div>
|
||||
<h1>调出 50 关难度合适、好玩的关卡,交付人工审核</h1>
|
||||
<p class="meta mono">第 3 轮 · 更新于 09-14 16:45 · 本页每 60 秒自动刷新</p>
|
||||
<div class="progress">
|
||||
<div class="bar"><i style="width:90%"></i></div>
|
||||
<div class="lbl"><span>19 / 21 项完成</span><span class="mono">90%</span></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<h2><span class="num">A</span>现在的状态</h2>
|
||||
<div class="grid">
|
||||
<div class="tile ok"><div class="k">候选关卡</div><div class="v">50 <span style="font-size:14px;color:var(--ink3)">/ 50</span></div><div class="n">当前关卡集</div></div>
|
||||
<div class="tile ok"><div class="k">盲转 / 关</div><div class="v">0.00</div><div class="n">目标 0</div></div>
|
||||
<div class="tile ok"><div class="k">转错方向 / 关</div><div class="v">0.00</div><div class="n">目标 0</div></div>
|
||||
<div class="tile ok"><div class="k">猴子 动作÷棋子</div><div class="v">6.43</div><div class="n">目标 ≥3.0(不无脑)</div></div>
|
||||
</div>
|
||||
|
||||
<div class="scroll"><table>
|
||||
<thead><tr><th>最少旋转数</th><th class="n">候选关数</th><th>说明</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>1 转</td><td class="n">5</td><td class="sub">浅</td></tr>
|
||||
<tr><td>2 转</td><td class="n">5</td><td class="sub">浅</td></tr>
|
||||
<tr><td>3 转</td><td class="n">24</td><td class="sub">浅</td></tr>
|
||||
<tr><td>4 转</td><td class="n">12</td><td class="sub">中</td></tr>
|
||||
<tr><td>5 转</td><td class="n">4</td><td class="sub">中</td></tr>
|
||||
|
||||
</tbody></table></div>
|
||||
<p class="sub">路线家族分布:v05 ×10 · spiral ×2 · switchback ×12 · weave ×18 · orbits ×8 终局可走朝向分布:{"3":44,"4":5,"5":1}</p>
|
||||
|
||||
<h2><span class="num">B</span>什么叫「难度合适且好玩」</h2>
|
||||
<div class="callout"><p class="sub">旋转是免费的、是这个游戏的特色,玩家应该频繁做——所以不该限制旋转次数。该限制的是每一次旋转值不值:转了有没有棋子出来、能不能看出来该转哪、以及转完之后有没有「原来这么简单」的反差。评分里只有 difficulty(复测 r=0.93)和 stuck(r=0.85)可信,rotation / clarity / fun 是噪声(0.32 / 0.19 / 0.56),所以「好玩」全部换成机械代理。 另外,演出本身就是奖励——棋子沿弯路走出去的那几秒是减压点,所以开局必须有得看,而不是只有两枚贴边棋子和 0.3 秒。</p></div>
|
||||
<ul class="rules sub">
|
||||
<li><b>旋转要深</b>:难度来自「需要转很多次」,不是「转错受罚」。旋转数随关号上升,不设上限<span class="how">(求解器最少旋转数)</span></li>
|
||||
<li><b>每转都有回报</b>:每一次旋转至少放出 2 枚棋子;无效转动 = 0<span class="how">(deepLevelStats.releasePerTurn / 规则机器人)</span></li>
|
||||
<li><b>演出是回报</b>:开局就要有得看:可点 ≥3 枚、其中最好的一条离场演出 ≥0.9s;全关长巡游(≥0.9s)≥3 次<span class="how">(showStats,用真实动画计时)</span></li>
|
||||
<li><b>反差感</b>:平均反差 ≥12:棋子在某个朝向看着像噩梦(长路线多弯),转过去就是几步走出(代价 = 格数 + 2×弯数)<span class="how">(六朝向逐棋子代价差)</span></li>
|
||||
<li><b>不无脑</b>:猴子 动作÷棋子 ≥3.0(v0.5 全库 1.67 = 乱点就能过)<span class="how">(生成时算)</span></li>
|
||||
<li><b>不挫败</b>:stuck ≤2.0;终局任一朝向卡住时,左右转都能开<span class="how">(grok 抽样 + 求解器)</span></li>
|
||||
<li><b>不重复</b>:盘面签名互不相同,路线家族分布不偏科<span class="how">(deepLevelKey)</span></li>
|
||||
</ul>
|
||||
<div class="scroll"><table>
|
||||
<thead><tr><th>关号区间</th><th>旋转数</th><th>目标 difficulty 评分</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>L1–L12</td><td>2–3 转</td><td class="mono">1.5 – 2.0</td></tr>
|
||||
<tr><td>L13–L32</td><td>3–5 转</td><td class="mono">2.0 – 2.6</td></tr>
|
||||
<tr><td>L33–L50</td><td>5–8 转</td><td class="mono">2.6 – 3.0</td></tr>
|
||||
</tbody></table></div>
|
||||
|
||||
<h2><span class="num">C</span>任务</h2>
|
||||
|
||||
<div class="phase">
|
||||
<h3><span class="pid">P0</span>判据:先说清楚什么叫「好」</h3>
|
||||
<ul class="tasks">
|
||||
<li class="done"><div class="t"><span class="tid">T0.1</span><span class="tt">难度曲线与旋转配额定义</span><span class="tag good">完成</span></div><div class="note">50 关分三档,0 转关卡死 10% 上限(用户硬要求)</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T0.2</span><span class="tt">机械验收门槛</span><span class="tag good">完成</span></div><div class="note">盲转=0、转错=0、终局可走朝向≥2 —— 前两项已由改锁结构达成</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T0.3</span><span class="tt">「好玩」的机械代理指标</span><span class="tag good">完成</span></div><div class="note">猴子 APT ≥3.0。fun 评分复测 r=0.56 不可用,改用「乱点过不了」当代理</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="phase">
|
||||
<h3><span class="pid">P1</span>产能:解除旋转上限,把反差感做进筛选</h3>
|
||||
<ul class="tasks">
|
||||
<li class="done"><div class="t"><span class="tid">T1.1</span><span class="tt">growDeepLevel 扩展到 6 个朝向</span><span class="tag good">完成</span></div><div class="note">现在只在朝向 0/1/2 插棋子,所以最少旋转恒等于 3 —— 这是「太简单」的根因</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T1.2</span><span class="tt">解除 rotations===3 的硬限制,允许 4/5/6+</span><span class="tag good">完成</span></div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T1.3</span><span class="tt">反差感指标进 deepLevelStats 并作门槛</span><span class="tag good">完成</span></div><div class="note">contrastStats 已进 deepLevelStats 并作门槛;实测 weave 22–33、switchback 29、spiral 18–24、orbits 12–17,petals 仅 2.0–5.7、crossing 3.8–5.5</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T1.4</span><span class="tt">每转释放 ≥2 枚的门槛</span><span class="tag good">完成</span></div><div class="note">改为按朝向配额插棋(每个朝向 ≥2 枚在等),取代原来的随机比例——随机比例会留下空转的朝向</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T1.5</span><span class="tt">扩产到 ≥120 候选并去重、家族均衡</span><span class="tag good">完成</span></div><div class="note">两批共 720 个种子 → 1113 个候选 → 过闸门 369 关(原 228)。家族 weave 262 / switchback 58 / orbits 39 / spiral 10</div></li>
|
||||
<li class="blocked"><div class="t"><span class="tid">T1.6</span><span class="tt">终局三枚互锁(hero+gate+tail)</span><span class="tag bad">受阻</span></div><div class="note">量化了:扫 1113 个候选,过闸门后深度≥4 的只有 23 个(2%)。第二次扩池把种子数翻倍,深关卡只从 16 涨到 23 —— 难度上限是构造的供给瓶颈,不是筛选问题。后档平均 4.0 转就是这个供给能支撑的上限</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T1.7</span><span class="tt">开局展示位(快速爽到)</span><span class="tag good">完成</span></div><div class="note">实测整个构造的开局中位只有 2 枚可点、最佳演出 0.57s——锁链开局全锁死。在构造里预留 2 个开局位(立即可点且路线长到值得看),实测开局可点 2→3 枚、最佳演出 0.72s→1.12s</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T1.8</span><span class="tt">离场演出封顶</span><span class="tag good">完成</span></div><div class="note">计时原本线性无上限,最长一次 17.4s,正式关 18.8% 超过 2s。拐点 2.4s 以下完全不变,以上加速逼近 3.2s 上限。labs/exit-timing 可同步对比</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="phase">
|
||||
<h3><span class="pid">P2</span>标定:把机械指标映射到真实难度</h3>
|
||||
<ul class="tasks">
|
||||
<li class="done"><div class="t"><span class="tid">T2.1</span><span class="tt">grok 抽样跑候选池,收集 difficulty / stuck</span><span class="tag good">完成</span></div><div class="note">R1:grok-4.6 xhigh 全量跑 50 关,收齐 difficulty / stuck / 机械指标与自由文本抱怨</div></li>
|
||||
<li class="blocked"><div class="t"><span class="tid">T2.2</span><span class="tt">拟合 difficulty ~ 机械特征</span><span class="tag bad">受阻</span></div><div class="note">做不成,且不是样本量问题:27 关里 26 关 difficulty 都打 2 分,响应几乎无方差,回归的是常数。根因在 bench 本身——文字盘面把每颗棋子的路线、挡路者、紧贴者直接列成清单,agent 不必用眼睛顺线走,而那正是这游戏的难点。agent 原话:「挡路名单已经写全,不用顺着格子数」。为解释它另建的 legibility 指标与评分相关 -0.02,同样无效,已记录为负结果不采用</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T2.3</span><span class="tt">用模型给全部候选打分并按曲线选 50 关</span><span class="tag good">完成</span></div><div class="note">select-50 按机械特征打分并均匀铺开,家族上限 36%。权重是设计假设而非拟合结果(见 T2.2),由人工审核裁定</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="phase">
|
||||
<h3><span class="pid">P3</span>迭代:跑几轮把曲线调平</h3>
|
||||
<ul class="tasks">
|
||||
<li class="done"><div class="t"><span class="tid">T3.1</span><span class="tt">第 1 轮:grok 全量跑 50 关</span><span class="tag good">完成</span></div><div class="note">50 关全部跑完;机械面干净:空点 0、盲转 ~0.3/关、全部通关。总体读数:整批偏易一档(2 分 vs 刚好的 3 分)</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T3.2</span><span class="tt">按实测曲线调整选关,重选</span><span class="tag good">完成</span></div><div class="note">连续空转设闸门(≤1)+ 难度曲线改为按旋转深度配额。同一规则机器人对照:盲转 0.24→0.12,最长连续盲转 4→1,决策数不变</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T3.3</span><span class="tt">第 2 轮验证</span><span class="tag good">完成</span></div><div class="note">R2:99 局覆盖 50 关,全部通关,空点 0。难度按档 2.00 / 2.05 / 2.40,无解感 1.21 / 1.15 / 1.74 —— 评分第一次出现梯度</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T3.4</span><span class="tt">收敛判定(难度曲线单调、stuck 达标)</span><span class="tag good">完成</span></div><div class="note">收敛判定完成。机械面全部达标:空点 0、不可解态 0、连续空转≤1、终局朝向≥3、三轮全部通关。难度面 2.00/2.05/2.39 单调,后档仍低于「刚刚好」的 3 分,上限由深关卡供给决定(T1.6)。第三轮试图用反差再推一把,被数据否掉并回退</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="phase">
|
||||
<h3><span class="pid">P4</span>交付</h3>
|
||||
<ul class="tasks">
|
||||
<li class="done"><div class="t"><span class="tid">T4.1</span><span class="tt">50 关关卡集</span><span class="tag good">完成</span></div><div class="note">交付的是第二版(R2 跑的那一版),从其 run 反建,50 关旋转深度 {1:5,2:5,3:24,4:12,5:4},家族 weave18/switchback12/v05 10/orbits8/spiral2。198 项测试全绿,规则机器人复核 50/50 通关、空点 0、最长连续盲转 1</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T4.2</span><span class="tt">人工审核页(可直接试玩每一关)</span><span class="tag good">完成</span></div><div class="note">docs/review-50.html:50 张开局盘面缩略图 + 机械指标 + agent 实测 + 试玩直达;并标注「哪些数字能信」,把感知类问题(路线长度、紧贴)显式交给人眼</div></li>
|
||||
<li class="done"><div class="t"><span class="tid">T4.3</span><span class="tt">后续关卡制作流程的优化总结</span><span class="tag good">完成</span></div><div class="note">docs/level-process.html:两轮对照、复测可信度表(本批现算)、五条规则各带证据、被否掉的做法清单</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<h2><span class="num">E</span>已有的 agent 实测</h2>
|
||||
<div class="scroll"><table>
|
||||
<thead><tr><th>批次</th><th class="n">关数</th><th class="n">difficulty</th><th class="n">stuck</th><th class="n">盲转/关</th><th class="n">多转/关</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>R3 · grok xhigh</td><td class="n">100</td><td class="n">2.10</td><td class="n">1.35</td><td class="n">0.14</td><td class="n">0.26</td></tr>
|
||||
<tr><td>R2 · grok xhigh</td><td class="n">100</td><td class="n">2.16</td><td class="n">1.37</td><td class="n">0.12</td><td class="n">0.24</td></tr>
|
||||
<tr><td>R1 · grok xhigh</td><td class="n">50</td><td class="n">2.10</td><td class="n">1.44</td><td class="n">0.24</td><td class="n">0.38</td></tr>
|
||||
<tr><td>Codex CLI · gpt-6-astra low</td><td class="n">18</td><td class="n">2.44</td><td class="n">1.44</td><td class="n">1.17</td><td class="n">1.22</td></tr>
|
||||
<tr><td>Codex CLI · spark xhigh</td><td class="n">18</td><td class="n">3.11</td><td class="n">2.28</td><td class="n">1.17</td><td class="n">1.17</td></tr>
|
||||
<tr><td>Grok Build CLI · xhigh</td><td class="n">18</td><td class="n">2.39</td><td class="n">1.83</td><td class="n">1.17</td><td class="n">1.22</td></tr>
|
||||
<tr><td>pi · Grok 4.6 xhigh</td><td class="n">18</td><td class="n">2.39</td><td class="n">1.89</td><td class="n">1.17</td><td class="n">1.22</td></tr>
|
||||
<tr><td>pi · Grok 4.6 xhigh · 复测</td><td class="n">18</td><td class="n">2.44</td><td class="n">1.78</td><td class="n">1.39</td><td class="n">1.56</td></tr>
|
||||
<tr><td>pi · Grok 4.6 xhigh · 新门槛</td><td class="n">18</td><td class="n">2.11</td><td class="n">1.39</td><td class="n">0.28</td><td class="n">0.33</td></tr>
|
||||
<tr><td>Kimi CLI · k3 high</td><td class="n">18</td><td class="n">2.94</td><td class="n">1.83</td><td class="n">1.17</td><td class="n">1.22</td></tr>
|
||||
<tr><td>Codex · high reasoning</td><td class="n">10</td><td class="n">3.00</td><td class="n">1.90</td><td class="n">0.40</td><td class="n">0.50</td></tr>
|
||||
<tr><td>Codex CLI · xhigh</td><td class="n">6</td><td class="n">3.00</td><td class="n">2.17</td><td class="n">0.33</td><td class="n">0.33</td></tr>
|
||||
</tbody></table></div>
|
||||
<p class="sub">difficulty 3 = 刚刚好;stuck 越低越好。这两项是评分里唯二复测可信的(r = 0.93 / 0.85)。</p>
|
||||
|
||||
<h2><span class="num">F</span>日志</h2>
|
||||
<ul class="log">
|
||||
<li><b>第三轮回退</b>按反差选关后,后档评分 2.39±0.10 → 2.19±0.08(约两个标准误),平均分≥2.5 的关从 11 掉到 6。反差确实和「被评得更难」相关,但按它选关造不出更难的关——相关不等于可操纵。已回退到第二版</li>
|
||||
<li><b>一个差点报错的对照</b>levels/campaign-50-r2.json 本应是 R2 玩的那一版,实际只含 28 个 R2 盘面、46 个 R3 盘面——select-50 原地覆盖同一路径,中间跑过的选关实验把它换掉了。改为从 run 反建(run 自带完整盘面与序号),并删掉该快照</li>
|
||||
<li><b>R3 结果</b>第三轮只改一个变量:桶内按反差取关。后档反差 27.9→28.5、旋转深度不变,后档评分 2.39→2.17。以 r=0.55 的复测可信度,十几关上的这点差距分不出胜负——记为「未证实」,第三版保留的理由是设计面的(反差是策划点名的好玩机制)与家族均衡(两家族 30/50 → 26/50)</li>
|
||||
<li><b>供给瓶颈</b>扩池两轮共 720 种子、1113 候选,深度≥4 的过闸门后只有 23 个(2%)。种子翻倍只让深关卡从 16 涨到 23,说明 growDeepLevel 难以造出需要四转以上的关卡——这是后档难度的硬上限</li>
|
||||
<li><b>R2 结果</b>难度评分按档 2.00/2.05/2.40(R1 是三档全平),无解感 1.21/1.15/1.74。意外把每关跑了两次,得到 45 对复测:84% 重放了完全相同的动作序列,机械指标 r=1.00,难度评分 r=0.55——且评分分歧的那几对全是同轨迹。结论:agent 近乎确定性,同一关不必跑两遍</li>
|
||||
<li><b>R2 依据</b>后段 14 条抱怨里两类:路线太长(感知,已对照 v0.5 基线否掉)与「转了没反应」(机械,可设闸门)。只改后者:endgameMinOpen 2→3、doubleDead 无闸门→≤2。两条合计只留 16% 候选,所以先扩池</li>
|
||||
<li><b>未擅自改动</b>agent 33 条抱怨里两大主题是路线太长(68 格 27 弯)与紧贴易看漏。但已上线的 v0.5 在这两项上更严重(最长 88 格 vs 84 格),属于游戏本来的性格;且文字盘面会同时夸大和缩小感知问题。因此只在审核页标出,不擅自设闸门</li>
|
||||
<li><b>R1 结论</b>难度评分在这批关卡上无区分度(26/27 都是 2 分),原因是文字 bench 把判断白送给了 agent。结论:agent 轮次用于抓缺陷(死局、盲转、空点、演出),难度排序只能靠机械假设 + 人工审核。这条改变了后续流程的设计</li>
|
||||
<li><b>演出</b>离场动画封顶定稿(拐点 2.4s / 上限 3.2s),最长 17.4s→3.5s;拐点以下手感不变。同时发现开局演出是结构性缺陷并在构造里修掉</li>
|
||||
<li><b>P1 进展</b>旋转深度打开:生成分布从「全部恒为3」变成 {3,4,5,6,7,8,9}。两次结构性猜测失败并已撤回(插入端多朝向出口过滤实测零效果)。深关卡的瓶颈定位为终局三枚互锁,改用扩大扫描量应对</li>
|
||||
<li><b>方向修正</b>旋转配额的思路被推翻:旋转免费且是核心特色,不该限次数,该限的是每次旋转的回报与可读性。实测发现 17 关最少旋转全部恒为 3(生成器写死),且 petals/crossing 两个家族几乎没有反差感(平均 2.0–5.7 对比 weave 的 22–33)</li>
|
||||
<li><b>起点</b>已完成前置工作:擦碰漏报修复(113/581 例)、终局单出口门槛、锁结构改为双向可开 —— 规则机器人盲转/转错/多转已全部归零</li>
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p class="mono">看板状态:bench/board.json · 生成:node scripts/build-board.mjs · 页面数字(候选数、盲转、猴子 APT、agent 实测)由脚本从关卡集与 bench/runs 直接测得,不是手写</p>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,97 +0,0 @@
|
||||
# 论文精读:把设计意图与空间一起生成
|
||||
|
||||
知识编号:P01 · 更新:2026-09-12 · 标签:`mixed-initiative` `mission-space` `生成文法` `局部重生成` `路线骨架`
|
||||
|
||||
**可复用结论:先描述玩家将经历的关系,再把关系与空间约束共同落实成可玩的布局;把中间结果留给设计者检查和修改。** 对 HEX TRAILS,“清掉入口 → 放出内向棋子 → 绕花瓣长路离场”应该是生成输入,而不只是生成完成后的评价标签。
|
||||
|
||||
## 文献与阅读范围
|
||||
|
||||
Daniël Karavolos, Anders Bouwer, Rafael Bidarra. *Mixed-Initiative Design of Game Levels: Integrating Mission and Space into Level Generation*. Foundations of Digital Games, 2015。
|
||||
|
||||
- [原文 PDF](https://livegamedesign.github.io/assets/FDG2015_Karavolos.pdf)
|
||||
- [大学文献记录](https://research.hva.nl/en/publications/mixed-initiative-design-of-game-levels-integrating-mission-and-sp/)
|
||||
- 本次核读:PDF 全部 8 页;正文第 1–6 节、图 1–3、表 1、致谢与参考文献。第 3、5 页图示另经渲染查看。以下页码指 PDF 文件页序。
|
||||
- 论文类型:两项系统案例与方法讨论。**不是玩家效果实验,也没有提供千关难度曲线或商业留存验证。**
|
||||
|
||||
## 论文实际讲了什么
|
||||
|
||||
### 1. Mission 与 space 是两个相关的设计对象
|
||||
|
||||
Mission 指玩家任务及其关系,例如先取得钥匙才能打开门;space 指这些任务发生的位置、房间和路径。论文讨论如何通过模型转换连接二者,而不是先造一张通用地图再塞任务。这里的 mission 不要求存在剧情文本。研究着眼于开发期间的人机协作:设计者可以直接改图或草图,也可以重跑某个生成步骤。(§1–2,p.1–3)
|
||||
|
||||
Ludoscope 将生成流程拆成模块,每个模块有自己的符号和转换规则。执行可由概率决定,也可遵循指定顺序的 recipe,或交由设计者编辑。符号的成员属性携带配对关系、当前可用能力等上下文;规则后的脚本可触发后续规则。论文的价值在于可控制的设计流程,并非提出一个包办各种游戏的自动生成器。(§2.3、§6,p.3、6)
|
||||
|
||||
### 2. Dwarf Quest:先任务图,再空间布局
|
||||
|
||||
设计者绘制抽象行动图,系统依次展开谜题、拾取和战斗,再让设计者微调详细图,最后由布局求解器映射为房间。这个顺序有依赖依据:谜题节点本身可能包含拾取和战斗。钥匙与锁用 ID 关联;战斗及取得敌人掉落钥匙需要落在同一房间。布局器还会加入连接路径和填充房间,以满足二维网格、房间出口数等游戏约束。(§3–3.1,p.3–4)
|
||||
|
||||
**图 1 的信息**:左侧是可分步执行的设计流程,右侧依次展示抽象图、展开图及最终地图。地图中有来自任务图的房间,也有布局器补的填充房间。这提醒我们:几何上新增的内容,不一定新增了玩法关系;需另行检查它承担的体验。
|
||||
|
||||
### 3. TickTick++:空间草图与任务顺序共同约束生成
|
||||
|
||||
设计者同时给出起终点、能力道具及连接路径的草图,以及取得能力的顺序。系统据此扩展轮廓,并标注各路径位置已经具有哪些能力。路径扩展可能产生歧义,流程专门留出人工修正轮廓的步骤。锁的放置按能力获取顺序的逆序进行,因为最后获得的能力对应可放置区域最少。之后才用模板展开细节,并转换到游戏使用的实际尺度。(§4–4.1,p.4–5)
|
||||
|
||||
**图 2–3 的信息**:图 2 有两路输入,在空间轮廓生成和锁放置阶段汇合;人工介入不只发生在开头,轮廓修正和末端微调也是流程的一部分。图 3 证明流程产物可以进入实际游戏画面,不能由此推断玩家更喜欢这些关卡。
|
||||
|
||||
### 4. 两个案例支持不同生成方向
|
||||
|
||||
表 1 对比的是“任务先于空间”和“任务与空间并行约束”。因此,不能把论文概括成唯一的“先依赖图、后画形状”流水线。对强形状需求,可以先给空间草图,同时约束任务关系。相同任务图生成多个空间,以及同一空间承载不同任务,都是作者讨论的复用方向。(§5–6、表 1,p.5–7)
|
||||
|
||||
## 证据与适用边界
|
||||
|
||||
| 原文支持的说法 | 不应扩大的说法 |
|
||||
| --- | --- |
|
||||
| 两个案例实现了分模块、人机交替的生成流程 | 已证明比手工设计更省多少工时、提升多少满意度 |
|
||||
| 重跑下游模块可以保持上游输入 | 已实现任意局部锁定、精确保留本轮生成结果 |
|
||||
| 修改参数可以改变案例中的战斗配置、谜题分支等 | 参数等价于真实玩家难度,或可直接映射本项目五档难度 |
|
||||
| 中间图/轮廓有助于设计者控制任务与空间 | 所有自动展开都会保持可解、不会产生歧义 |
|
||||
| 作者讨论同一任务生成多个空间 | 这些空间在玩家眼中必然是不同体验 |
|
||||
|
||||
作者明确指出:模板仍需要大量人工工作;规则改变可能使模板失效;复杂模块的错误可能源于文法、流程或游戏代码,排查困难。重跑模块虽不改上游,仍可能丢失该模块上一轮输出中设计者喜欢的部分;选择性保留被提出为待解决方向。论文也明确说案例没有与玩家互动,实时适应玩家、难度序列可视化属于后续工作。(§5–6,p.6–7)
|
||||
|
||||
## 对 HEX TRAILS 的迁移方案
|
||||
|
||||
以下均为本项目设计建议,**不是论文已验证结果**。
|
||||
|
||||
### 制作卡 P01-A:将“主爽点”变成输入约束
|
||||
|
||||
一次生成至少给出三项:目标体验、必须发生的关系、允许变化的空间。
|
||||
|
||||
```text
|
||||
体验:内向棋子经过轻巧操作后沿花瓣长路离场
|
||||
关系:入口 A 移走后,旋转一格使 B 接通出口
|
||||
空间:B 的实际路线经过指定花瓣,交叉保持轨道配对
|
||||
固定:B 的初始位置/箭头,关键花瓣段,关键动作上限
|
||||
可变:其他棋子位置、非关键轨道、次要离场顺序
|
||||
证据:真实规则回放中,B 在允许动作内成功走过指定路线
|
||||
```
|
||||
|
||||
具体动作数是一张制作卡的意图,不应升级成所有关卡的统一规则。若关键路径在生成中被破坏,应返回具体冲突,避免用装饰花瓣补足标签。
|
||||
|
||||
### 制作卡 P01-B:为花瓣提供双向生成入口
|
||||
|
||||
普通清挡关可从关系骨架开始;花瓣、螺旋、环绕等关卡可先固定实际可行驶的路线片段,再寻找兼容的棋子、阻挡与旋转阶段。两种入口汇合在“带条件的路线与释放关系”中间表示上。
|
||||
|
||||
本游戏底盘旋转会改变路线,所以一张静态“谁挡谁”的图不够。至少记录关系成立时的底盘朝向、剩余棋子以及实际行进路线。不同状态可以有不同关系;不要将某一参考解的关系当作全局真理。
|
||||
|
||||
### 制作卡 P01-C:明确哪些东西可以重做
|
||||
|
||||
后续编辑器应允许设计者固定关键棋子、路段、阶段和已验收的释放效果,再局部生成其他内容。每次修改输出“保留项、变化项、失效的验证”。这比反复换随机种子更符合协作目标。
|
||||
|
||||
注意:**精细锁定是我们计划补足的能力,不是论文中已经完整实现的功能。** “重跑下游”与“保住下游上次喜欢的局部”是不同问题。
|
||||
|
||||
### 制作卡 P01-D:按体验角色构造模块
|
||||
|
||||
优先形成“入口让路”“一转放行”“跨区巡游”“阶段清理”“漂亮收尾”等可组合模块。每个模块有输入状态、输出机会、空间约束及可回放见证。模块不是只画几条线的图案模板。
|
||||
|
||||
逆序放锁可以启发“先保障空间最受限的关键路线,再填外围内容”,但其适用条件需要验证。平台游戏的能力获取和本游戏旋转换路并不相同,不能直接复制其锁匙算法。
|
||||
|
||||
## 后续使用时的检查清单
|
||||
|
||||
1. 当前设计输入是在表达玩家经历,还是只有大小、密度、弯数?
|
||||
2. 形状与关键释放关系冲突时,有没有明确的中间表示供修改?
|
||||
3. 重生成是否保留了设计者明确固定的内容?
|
||||
4. 关键效果是否在真实规则和实际点击流程中回放成立?
|
||||
5. 同一任务骨架的新空间是否改变了路线、观察或释放过程?仅颜色变化不算新的体验证据。
|
||||
|
||||
关联:[PCG-QD 精读](02-pcgqd.md)解决候选库多样性;[难度与序列补充研究](03-progression-and-difficulty.md)讨论如何从关卡库安排推进过程;[总报告](../level-design-research-report.md)将三者结合。
|
||||
@@ -1,179 +0,0 @@
|
||||
# 论文精读:Procedural Content Generation through Quality Diversity
|
||||
|
||||
知识条目:KB-P02 · 核读日期:2026-09-12 · 适用对象:HEX TRAILS 关卡生成、候选库、筛选与评审工具。
|
||||
|
||||
**最有用的结论:生成器应保留“不同体验类型中各自优秀的关卡”,而不是用一个总分把全部候选排队。** 论文为这种候选库提供方法框架;把它应用到长路巡游、轻巧反差和花瓣路线,是本项目的设计推论。
|
||||
|
||||
## 1. 文献身份与阅读范围
|
||||
|
||||
Daniele Gravina, Ahmed Khalifa, Antonios Liapis, Julian Togelius, Georgios N. Yannakakis. *Procedural Content Generation through Quality Diversity*. 2019 IEEE Conference on Games (CoG). DOI:`10.1109/CIG.2019.8848053`。arXiv 初次提交日期为 2019-07-09。[元数据](https://arxiv.org/abs/1907.04053)
|
||||
|
||||
本次逐页阅读了[作者提供的 8 页 PDF](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf),并与[作者全文 HTML](https://antoniosliapis.com/articles/pcgqd.php)交叉核对;渲染检查了包含图 1–5、表 I 的 PDF 第 4–6 页。以下页码指该 PDF 的物理页序,从首页算第 1 页,不能直接套用到重新排版的版本。
|
||||
|
||||
它是一篇**方法综述与研究方向论文**:归纳已有 QD 算法及游戏应用,论述优势、解释性与开放问题。它没有报告一项新的 1000 关量产实验,没有研究箭头消除游戏的难度曲线,也没有给出长期留存或玩家满意度的因果证据。文中的个案数值是作者转述所引研究,不能归为这篇综述自己的统一对照实验。
|
||||
|
||||
本条目采用三个标签:**[论文]** 表示原文论述或转述;**[解读]** 表示对方法适用边界的分析;**[项目建议]** 表示需要在 HEX TRAILS 中实现、验证的方案。
|
||||
|
||||
## 2. 可复用摘要
|
||||
|
||||
**[论文]** QD(Quality Diversity)同时处理“内容是否达到质量要求”和“内容在行为上有哪些不同”。它可以通过行为特征划分空间、在相似候选间保留更优者,也可以通过行为距离鼓励新颖性。可解性等硬约束与局部质量竞争是两种质量控制方式。MAP-Elites 是其中一种算法,PCG-QD 是更宽的程序化内容生成方法类别。[§II,PDF 第 1–3 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=2)
|
||||
|
||||
**[论文]** 作者认为,一次搜索保留许多不同的合格内容,有利于批量产出、人机协作、观察生成器能够覆盖哪些类型,以及帮助设计师理解结果。效果依赖行为特征、质量指标、约束和评价器的定义;高维空间、分箱粒度、特征依赖及仿真成本都是问题。[§III、§V,PDF 第 3–4、7 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=3)
|
||||
|
||||
**[项目建议]** 对 1000 关最有价值的用法,是建立可以按体验挑选的候选档案。先确保规则与解法成立,再分别保存“直接长路”“清挡放行”“一次旋转反差”“有形状的长路”等优秀样关。关卡次序、难度波动和真人体验校准应由额外流程完成,不能把档案格子的排列直接当成玩家关卡顺序。
|
||||
|
||||
## 3. 全文阅读定位
|
||||
|
||||
| 位置 | 原文内容 | 本条目取用的知识 |
|
||||
| --- | --- | --- |
|
||||
| 第 1 页,摘要、§I、§II 开头 | 质量与多样性的动机;QD 与只寻找最优解的区别 | 数量和参数差异不能直接代表可感知变化 |
|
||||
| 第 2 页,§II-A/B/C | 行为距离、行为分区、局部竞争、约束;ME、ME-NOV、MESB、CNS | 分开定义“好不好”与“是哪一类” |
|
||||
| 第 3 页,§II-C 后半、§III-A/B/C | CSS、CME、NS-LC、SS-LC;批量效率、评价函数、表达范围 | 算法选型;避免把 fitness-free 解读成不需要质量判断 |
|
||||
| 第 4 页,§III-C/D/E、§IV-A/B;图 1、2 | 可视化覆盖、人机协作、解释性;图像与弹幕案例 | 档案空洞诊断;不同表现不必争同一个最高分 |
|
||||
| 第 5 页,表 I、图 3、4、§IV-B 至 F | 各应用的质量/多样性定义;Mario、卡组、地图建议 | 特征应与实际玩法对应;仿真指标有条件性 |
|
||||
| 第 6 页,图 5、§IV-F 至 J、脚注 1 | 武器、飞船、方块建筑、地牢、案例讨论 | 算法 surprise 与玩家惊喜的区别;可解释性尚非充分验证结论 |
|
||||
| 第 7 页,§V、§VI、参考文献开头 | 高维、粒度、代理模型、不同风格的测试代理;结论 | 多策略验证、控制评价成本、限制指标维数 |
|
||||
| 第 8 页,参考文献 | 所引方法与应用的原始文献 | 后续追读入口;本次未冒充已全文阅读这些被引论文 |
|
||||
|
||||
## 4. 五个必须分清的概念
|
||||
|
||||
### 4.1 质量与行为特征
|
||||
|
||||
**[论文]** 质量回答某个候选是否符合要求、或在同类候选里是否更好;行为特征描述它属于哪种表现。两枚得分相同的候选仍可能值得同时保存,因为它们的行为不同。原文特征并不限于真实玩家行为:也包括空间结构、图像类别、卡牌费用分布等可计算描述。[§II,PDF 第 1–3 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=2)
|
||||
|
||||
**[项目建议]** “实际最长成功路径”“放行方式”“路线形态”“旋转阶段”适合描述体验类别;“能完整清盘”“交叉与碰撞符合正式规则”“承诺的主爽点确实在回放出现”适合成为验收条件。难度可以先作为记录和编排标签,不必直接进入统一质量分。
|
||||
|
||||
例如,舒缓长路与多阶段清挡分别比较本类质量。若统一奖励“旋转越多、依赖越深、路径越长”,搜索可能让本来应该轻巧的关卡也变得繁重。
|
||||
|
||||
### 4.2 内容编码差异与体验差异
|
||||
|
||||
**[论文]** QD 的多样性机制强调行为空间,不等于仅检查基因编码是否不同。案例也显示,特征选取会直接决定系统眼中的“不同”:Sentient Sketchbook 用不同格子数量;Mario 场景用代理回放实际触发的机制。[§II-A、§IV-C/E,PDF 第 2、5 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=5)
|
||||
|
||||
**[项目建议]** 换颜色、改种子、移动一段未使用装饰线,都可能改变文件,却不改变玩家体验。候选去重应同时检查结构同构、放行关系与实际回放表现。把棋盘、棋子和箭头整体一起作对称变换,可能只是同一体验的变体;只旋转底盘会改变本游戏的出路,不能按同一种等价变换误删。
|
||||
|
||||
### 4.3 可行与有趣
|
||||
|
||||
**[论文]** 可行性通常由硬约束决定,例如地图是否可通行、脚本是否合法、代理能否完成。部分方法再在可行候选之间比较质量。[§II-B、§IV-J,PDF 第 2、6 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=6)
|
||||
|
||||
**[解读]** 一个代理找到解,只证明在其规则模型与动作定义下存在已找到的完成过程。它没有证明玩家能理解线索,也没有证明行进值得看完。搜索超时不能直接当作无解;把超时当无解会连带扭曲档案覆盖率。
|
||||
|
||||
### 4.4 算法新颖性、算法 surprise 与玩家惊喜
|
||||
|
||||
**[论文]** Novelty 依据与已存在行为的距离;surprise 可以依据当前结果偏离过去种群趋势预测的程度。武器案例用过去两代死亡位置热图作预测,奖励偏离预测的位置分布。[§II-C、§IV-F,PDF 第 3、6 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=6)
|
||||
|
||||
**[解读]** 这里的 surprise 没有测量玩家第一眼的判断。因此,不能声称采用 CSS 就会自动生成“看似棘手,一转就通”的关卡。
|
||||
|
||||
**[项目建议]** 轻巧反差至少需要两条独立证据:结构上确有很短的放行操作;玩家观看开局后确实预期它更难。前者可以由模型验证,后者需要试玩提问或行为观察。两者不要合成一个未经标定的“惊喜分”。
|
||||
|
||||
### 4.5 表达范围与关卡难度曲线
|
||||
|
||||
**[论文]** 表达范围描述生成器能产出哪些样式,特征图可以暴露集中区域、空洞及指标偏置。[§III-C,PDF 第 3–4 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=4)
|
||||
|
||||
**[项目建议]** 档案回答“我们有多少种可用体验”,主线编排回答“玩家接下来应遇到哪种体验”。前者覆盖均匀,不代表后者应平均投放,也不代表玩家的学习负担应逐关线性上升。
|
||||
|
||||
## 5. 算法应怎样理解与选择
|
||||
|
||||
下表是对 §II-C 的简化归纳,详细定义见 [PDF 第 2–3 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=2)。右栏全部属于项目建议,并非论文针对本游戏的结论。
|
||||
|
||||
| 方法 | 论文中的核心机制 | HEX TRAILS 的考虑 |
|
||||
| --- | --- | --- |
|
||||
| MAP-Elites(ME) | 特征分箱,每箱保留质量最好的个体;从档案选择父代继续变化 | 适合做第一版可浏览候选档案;先定义少量有设计意义的坐标 |
|
||||
| ME-NOV | 用新颖性影响父代选择,让搜索偏向较少探索的行为 | 当候选持续挤在相近区域时,再评估是否需要 |
|
||||
| MESB | 按已生成个体的特征分布重新调整箱边界 | 有助处理分布不均;边界变化会影响跨批次统计,应保存版本 |
|
||||
| CNS | 分成可行与不可行种群;可行者追求新颖,不可行者接近可行或同样追求新颖 | 有价值的半成品不能直接入主线,可以放在独立修复池 |
|
||||
| CSS | 可行/不可行分流,可行种群追求偏离预测的行为 | 暂不以此实现人的轻巧反差;两种 surprise 的定义不同 |
|
||||
| CME | 每个特征箱内分别保存可行与不可行种群,兼顾局部质量与修复 | 若花瓣路线稍改即破坏配对或可解性,可考虑保留接近合格的变体 |
|
||||
| NS-LC | 同时奖励行为新颖性和胜过附近候选的质量 | 需要可信的行为距离;不同路线类别不宜随意赋数计算欧氏距离 |
|
||||
| SS-LC | 用偏离预测与局部竞争结合,可再混合 novelty | 没有证据表明它应成为本项目首选,先用可解释基线 |
|
||||
|
||||
**[论文]** 标准 ME 的基本过程是:初始化候选 → 评价质量与特征 → 找到所属箱 → 空箱直接保存,已有候选则只保留更优者 → 从档案抽取父代并变异或交叉 → 继续评价与替换。[§II-C1,PDF 第 2 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=2)
|
||||
|
||||
**[项目建议]** 初版可以先把现有候选按特征分类、筛选、可视化。这能验证特征是否有用,但若没有从档案选父代并持续搜索,应称为“借鉴 QD 的分类候选库”,不要声称已经实现完整 MAP-Elites。
|
||||
|
||||
## 6. 图表、个案和数值到底证明了什么
|
||||
|
||||
| 证据位置 | 实际内容 | 可以借鉴 | 不能推出 |
|
||||
| --- | --- | --- | --- |
|
||||
| 图 1,第 4 页;§IV-C,第 5 页 | 图中展示六个二元特征的 Mario 机制热图;案例正文称完整实验使用八个机制、256 个箱,平均约 100 个箱生成了关卡 | 检查特征依赖与不可达组合;热图用于诊断生成器 | 不能将图中 64 种组合当作正文完整的 256 格档案;不能把约 100 格解释为 100 名玩家或 100 个优质整关 |
|
||||
| 图 2,第 4 页;§IV-B,第 4–5 页 | Talakat 弹幕脚本,采用代理熵、代理风险和子弹分布作特征,以 A* 检查可玩性 | 同一游戏内可以保留运动表现不同的内容 | 三张图不证明玩家满意度或主线节奏;“密集”不自动等于“更难” |
|
||||
| 图 3,第 5 页;§IV-C | Mario 片段按代理回放触发机制分类,局部质量偏向简单且可完成 | 可以按实际放行/行进事件描述关卡,而非只数静态元素 | 没有证明一个参考代理代表所有玩家;片段生成不同于完整战役编排 |
|
||||
| 图 4,第 5 页;§IV-E | Sentient Sketchbook 左侧设计画布、右侧候选建议;从用户草图开始生成 | 让设计师能在明确的初稿基础上挑选变化 | 单张界面图不构成设计效率提升的统一用户实验 |
|
||||
| 图 5,第 6 页;§IV-F | 两种自动生成武器;surprise 使用模拟死亡位置偏离预测 | 评价行为而非仅外观,保持可用约束 | 不能把该 surprise 直接译成玩家的“啊哈体验” |
|
||||
| 表 I,第 5 页 | 横向列出不同应用的算法、发散机制、质量机制、特征定义 | 同一框架下,各品类需要不同的质量和特征 | 没有跨应用可比的“统一质量分”或算法总排名 |
|
||||
|
||||
以上均来自[论文 PDF 第 4–6 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=4)。三个容易误用的数字也需单独记录:
|
||||
|
||||
- 图像/物体案例的 **1000** 是分类网络的类别数,和本项目的 1000 关目标无关(§IV-A,第 4 页)。
|
||||
- Hearthstone 案例用 **200 局游戏**中的生命差来评价卡组,并用费用曲线的均值与方差描述多样性。这是该案例的评估设计,不是本项目每关必须模拟 200 次的标准(§IV-D,第 5 页)。
|
||||
- 脚注比较 Sentient Sketchbook 中“6 个线程各产 1 个建议”和 CNS“1 个线程产 6 个建议”。它说明候选批量复用的机会,不是本论文给出的通用 6 倍运行时间加速结论(第 6 页,脚注 1)。
|
||||
|
||||
## 7. 适用边界与需要主动防范的误读
|
||||
|
||||
**[论文]** 高维行为空间难覆盖;箱太细会稀疏,箱太粗会隐藏差别;作者讨论了潜在空间、Voronoi 分区和仿真代理模型等方向。多风格测试代理被提出用于检查内容是否按预期被体验。[§V,第 7 页](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf#page=7)
|
||||
|
||||
**[解读]** 下列限制尤其影响我们的决策:
|
||||
|
||||
1. **指标依然决定盲点。** 名为 *Fitness-Free Search* 的小节并未取消质量定义;许多算法仍使用约束和局部质量比较。减少对一个全局目标的依赖,不等于算法会自行判断好玩。
|
||||
2. **空箱不全是坏事。** 它可能来自规则不允许的组合、特征互相依赖、分箱不合理,也可能只是搜索不足。应分别标明“确认不可行”“尚未找到”“已有合格候选”。
|
||||
3. **批量效率是方法动机,不能套成固定性能承诺。** 本文没有以同一任务、同一计算预算把全部方法重跑并给出统一胜负;每个关卡的仿真仍可能昂贵。
|
||||
4. **可解释性是部分能力与研究方向。** 作者在 §IV-J 明确指出,所综述案例中还没有项目把解释性作为明确目标来研究;特征图本身不是“设计师理解已被证明提升”。
|
||||
5. **2019 年的横向论述不是今天所有算法的能力上限。** 文中对机器学习生成、构造法或声明式方法多样性控制的概括应放回当年的语境;本条目不据此宣称其他生成方法都无法做到多样化。
|
||||
6. **发表范围没有覆盖移动消除游戏的长期曲线。** 免费试错、连续点击、动作动画、碎片时间、广告节奏、1000 关留存均不是本文验证对象,不能用学术引用替代这些体验研究。
|
||||
|
||||
## 8. 转换为 HEX TRAILS 的制作规则
|
||||
|
||||
以下均为 **[项目建议]**,与[新版关卡设计准则](../level-design-principles-v2.md)衔接。论文提供方法启发,不提供这些配置的验证结果。
|
||||
|
||||
### 8.1 三层评价,避免长路等同于难度
|
||||
|
||||
| 层次 | 初版记录 | 如何使用 |
|
||||
| --- | --- | --- |
|
||||
| 正确性 | 数据合法、正式规则下的清盘解、碰撞与轨道一致性、求解是否触顶 | 不合格候选不进入玩家关卡;未确定单独存放 |
|
||||
| 体验类型 | 实际成功路线长度/弯数/空间形态,主放行方式,主奖励出现阶段 | 进入相应候选档案;用来保持变化 |
|
||||
| 本类质量 | 主爽点兑现、因果可读、运动可跟随、重复操作负担、真人反馈 | 在同类候选中比较,保留回放和评审理由 |
|
||||
|
||||
“长路、低前置负担”是一种值得保存的类型;不能因为操作简单就在统一困难度排名中被淘汰。花瓣轮廓只证明形状存在,仍要检查玩家实际放出的棋子有没有走过构成花瓣的路径。
|
||||
|
||||
### 8.2 先做少量可解释档案,再扩维
|
||||
|
||||
可以先按主放行方式分库,例如直接通行、清挡通行、旋转换路、分阶段组合;每个库先用两个坐标浏览,例如“实际主路径长度带 × 前置动作负担”。路线形态、反差意图、盘面密度等先做筛选标签。具体分界应来自已审核样关分布,当前不固定未经校准的阈值。
|
||||
|
||||
若把所有标签做笛卡尔积,会产生大量没有设计意义或规则上不可达的格子。也不要为了填满图表而制造不符合核心体验的关卡。
|
||||
|
||||
### 8.3 同一几何可以成为不同关卡,但要有不同的体验证据
|
||||
|
||||
花瓣骨架可承载直接巡游、外围清挡后放出主瓣、一转接通内向长路等不同意图。保留变化时应写明:关键棋子、放行条件、成功路径、奖励顺序分别改变了什么。只换配色或旋转截图,不足以证明新增一关的价值。
|
||||
|
||||
反过来,两种外形不同的棋盘也可能具有几乎相同的“全部能点就点、转一次、全部清空”节奏。结构档案和回放摘要应能发现这种重复。
|
||||
|
||||
### 8.4 评价回放要覆盖多种合理操作
|
||||
|
||||
至少区分顺手点击畅通棋子、主动追求长路、优先清挡、尝试旋转等策略。对每种策略分别记录:是否清盘、主长路是否出现、关键反差是否被直接绕过、奖励在何时兑现。策略和样本数量需随验证成本确定,不能从本文借一个固定次数当作充分性保证。
|
||||
|
||||
若正式运行时支持快速点击、输入队列或并行动画,仿真与体验评审要体现相同的规则。输入屏蔽或动画调度造成的耗时,不能直接算成关卡的推理难度。
|
||||
|
||||
### 8.5 候选库与主线编排分别验收
|
||||
|
||||
候选库验收“不同类型中有没有足够好的选择”;主线验收“连续游玩时有没有学习、变化与舒缓”。先维持可用类型库,再从中编排短序列试玩。先前 1000 关方案中的难度数量、长路比例和章节长度仍是待验证假设,不能因为引入 QD 而升级为研究结论。
|
||||
|
||||
## 9. 后续可以直接引用的设计卡
|
||||
|
||||
| 知识卡 ID | 可直接使用的规则 | 验证问题 |
|
||||
| --- | --- | --- |
|
||||
| QD-01 | 正确性、体验类别、本类质量分别记录 | 高难标签是否正在替代“好玩”的判断? |
|
||||
| QD-02 | 按实际回放区分关卡,不能只比较种子与截图 | 两关带来的放行与巡游过程到底哪里不同? |
|
||||
| QD-03 | 在每个体验类型内部保留优秀候选 | 舒缓长路是否被困难度总分挤掉了? |
|
||||
| QD-04 | 反差要有结构证据和玩家预期证据 | 我们测到的是算法偏差,还是人的惊喜? |
|
||||
| QD-05 | 档案空洞先诊断,不急于补齐 | 是搜索不足、指标冲突,还是本来不值得生成? |
|
||||
| QD-06 | 主奖励用多种合理点击顺序验证 | 只有参考解能看到花瓣巡游吗? |
|
||||
| QD-07 | 记录候选来源、变体关系、淘汰原因与指标版本 | 修改评分后,能否解释哪些候选为何消失? |
|
||||
| QD-08 | 内容多样性与连续关卡节奏分别设计 | 单关都合格,连玩十关是否仍然重复? |
|
||||
|
||||
建议首先做一个小规模对照:使用相同候选生成预算,比较“现有单分筛选”和“按体验分类、类内挑选”。由盲评检查核心爽点兑现、可感知差别及可读性,并记录合格数量与人工筛选时间。此实验属于项目验证方案,尚未执行;它比先把完整进化算法搬进工程更能检验 QD 思路是否解决了眼前问题。
|
||||
|
||||
## 10. 来源与待追读范围
|
||||
|
||||
- **全文来源**:[作者 PDF](https://antoniosliapis.com/papers/procedural_content_generation_via_quality_diversity.pdf)、[作者 HTML](https://antoniosliapis.com/articles/pcgqd.php)。两者是同一篇论文的不同载体,不算两项独立研究。
|
||||
- **文献身份核对**:[arXiv 元数据](https://arxiv.org/abs/1907.04053)、[作者文献条目](https://antoniosliapis.com/publications.php?bib=gravina2019pcgqd#gravina2019pcgqd)。
|
||||
- **后续追读候选,未在本次冒充全文读过**:参考文献 [12] MAP-Elites 原始方法、[19] *Intentional Computational Level Design*、[39] *Empowering Quality Diversity in Dungeon Design with Interactive Constrained MAP-Elites*、[49] *Procedural Personas as Critics for Dungeon Generation*。引用其具体实验结论前,应另立条目核读原文。
|
||||
- **检索审计**:[本条目来源记录](../../exa-results/level-design-2026-09-12/paper-qd-sources.json)。本流使用 Exa 搜索 1 次、请求 5 个候选结果;实际全文核读的是 1 篇论文,而不是 5 篇论文。
|
||||
@@ -1,80 +0,0 @@
|
||||
# 补充研究:关卡顺序、玩家熟练度与难度估计
|
||||
|
||||
知识编号:P03–P04 · 更新:2026-09-12 · 标签:`关卡编排` `技能组合` `难度模型` `冷启动` `玩家分群`
|
||||
|
||||
两篇指定论文主要解决“怎样生成”和“怎样保持候选多样性”。本次通过 Exa 另找到两项直接讨论关卡编排、真人难度数据的研究,用来补足千关方案中的排序与验证环节。
|
||||
|
||||
## P03:从解法特征组织关卡序列
|
||||
|
||||
Eric Butler, Erik Andersen, Adam M. Smith, Sumit Gulwani, Zoran Popović. *Automatic Game Progression Design through Analysis of Solution Features*. CHI 2015. DOI: 10.1145/2702123.2702330。
|
||||
|
||||
[作者提供的论文](https://www.ericbutler.net/assets/papers/chi2015_progression.pdf)。本次阅读正文的方法、生成、编排、实验、讨论与结论;下载 10 页 PDF 核对章节页位。此项为补充研究,不与两篇指定论文的逐图精读范围混称。
|
||||
|
||||
### 方法要点
|
||||
|
||||
作者不只记录关卡有哪些机制,还记录机制如何组合。对有程序化解题过程的问题,可用行动序列的 n-gram;对 Refraction 这种有多种摆法的空间谜题,用解法图中的小子图 graphlet 表示“转向器接分流器”等关系。还需要额外的数学关系图,以区分空间连接相同、分数要求不同的题。(PDF p.4–5)
|
||||
|
||||
编排时从多样的关卡库中选下一关,综合玩家接触/完成过的特征、设计者赋予各特征的权重以及当前目标负担。先修关系只形成偏序,不能靠一次拓扑排序就解决节奏:还需控制新概念、熟悉概念组合和练习的出现速度。作者可以重新给关卡打特征标签、重排,而不用重新生成所有布局。(p.5–7)
|
||||
|
||||
**重要前提**:该实验的生成器约束所有可能解具有相同的解法图,所以可用一条参考解提取共有特征。本游戏有旋转和不同释放顺序,尚无这个保证。我们只能明确区分“必经特征”“多策略常见特征”和“作者解独有特征”。(p.5)
|
||||
|
||||
### 实验到底证明了多少
|
||||
|
||||
线上实验共 2,377 名玩家,自动组 1,221 人,人工原版组 1,156 人。中位游玩时间分别为 184 秒、199 秒,所用检验未发现显著差异;完成谜题数中位数为 8 与 10,存在小幅显著差异,但两组题目不同,作者不认为它是理想的投入度比较指标。(p.7–8)
|
||||
|
||||
这支持“该框架经过调整后产生了可比较的短期游玩表现”,**不能写成自动设计已经等效于人工设计,或已证明长期留存、千关完成率更好**。作者明确指出缺少随机顺序对照,甚至不能据此确定编排本身对投入度贡献了多少。(p.8)
|
||||
|
||||
图 4 及讨论揭示了一个与千关特别相关的失败:概念耗尽后,自动系统连续选择非常相近的题,人工序列则更常出现较大的概念跳跃。作者提出减慢新概念消耗、惩罚连续相近题等改进方向,未把它们报告成已验证的最优策略。(p.8–9)
|
||||
|
||||
还需计算制作成本:作者指出,针对具体游戏实现这套系统往往比手工编排更费工;如果目标只是做出一款关卡顺序合理的游戏,是否受益仍不确定。自动化的价值应连同反复调优、重排与后续扩展来评估,不能仅凭“自动”就宣称省工。(p.9)
|
||||
|
||||
### 对本项目的可用建议
|
||||
|
||||
- 用“清挡 → 放行”“清挡 → 转盘 → 巡游”“转过去清理 → 转回来放行”等短组合描述认知内容;单纯记录本关出现过“旋转”不足以区分体验。
|
||||
- 将关卡库与关号解耦,允许同一批关卡重排并比较效果。
|
||||
- 编排器同时限制相邻相似度和新概念跳幅;只追求平滑,会滑向重复。
|
||||
- 保留长路直接放行的舒缓关。本项目的目的包括观看与释放享受,不能照搬 Refraction 每关尽量引入未掌握挑战的约束。
|
||||
|
||||
## P04:用真人与模拟数据校准难度
|
||||
|
||||
Jeppe Theiss Kristensen, Paolo Burelli. *Difficulty Modelling in Mobile Puzzle Games: An Empirical Study on Different Methods to Combine Player Analytics and Simulated Data*. arXiv:2401.17436,2024。
|
||||
|
||||
[作者公开全文](https://arxiv.org/html/2401.17436)。本次重点核读 §3–9(案例、方法、数据、两组实验、讨论和结论);没有复现实验,也未逐篇追读其引用文献。
|
||||
|
||||
### 实际研究范围
|
||||
|
||||
案例为 Tactile Games 的 Lily’s Garden,研究前 500 关。数据采集区间为 2021-06-01 至 2021-12-01,只包含期间开始游戏且玩过至少 200 关的玩家;因此不能用这份样本直接解释首日流失者。(§3、§5.1)
|
||||
|
||||
研究把难度操作化为完成关卡所需的尝试次数,比较随机森林、神经网络、因子分解机,输入包括历史结果、玩家特征、关卡静态特征及代理实际游玩的动态特征。还区分已有关卡数据和新关卡没有真人记录的冷启动场景。(§4–7)
|
||||
|
||||
在此样本中,约前 100 关包含较多教学与容易关,之后平均尝试次数在约 3.2 附近波动,个别难关仍有明显高峰。**这是这个游戏、这批样本的观察值,不是所有解谜游戏应采用的目标。**(§3、图 2)
|
||||
|
||||
### 对生产有用的结果与限制
|
||||
|
||||
1. 新关卡的群体平均预测中,神经网络和随机森林使用代理、玩家与关卡特征组合表现较好;因子分解机加入全部特征则可能因过拟合变差。§6 的个体预测与 §7 的群体平均预测必须分别解读,不能用一句“某算法最好”覆盖所有场景。(§6–8)
|
||||
2. 代理通常比真人强,可能分不开真人眼中的容易与中等关卡。直接把代理当作真人补数据的尝试也没有得到理想结果。(§8.2、§9)
|
||||
3. 对新关卡,预测往往把简单关估高、难关估低,向均值收缩。单个精确预测值容易制造不必要的确定感。(§7)
|
||||
4. 作者仍认为设计者需要亲自玩,才能判断是否有趣、解法是否清楚;建议未来研究按时间窗口验证模型,以更接近真实上线后的预测。(§8.2)
|
||||
|
||||
### 对本项目的可用建议
|
||||
|
||||
本游戏试路和旋转免费,失误不等于重开。直接套用“平均重试 3.2 次”既不匹配规则,也不匹配体验目标。应先记录下列独立指标,再与玩家对难度、疲劳和愉悦的评价对应。
|
||||
|
||||
| 指标 | 解决的问题 | 不能直接推出什么 |
|
||||
| --- | --- | --- |
|
||||
| 首次有效动作前的主动观察时间 | 开局是否找得到入口 | 长时间一定是困难;玩家可能在欣赏图案 |
|
||||
| 无效试路、无收益旋转及连续发生的位置 | 哪处理解或反馈有问题 | 每次尝试都是挫败;试探也可能有趣 |
|
||||
| 关键动作后的新可放行棋子 | 操作的因果回报是否清楚 | 解锁数量越多,质量越高 |
|
||||
| 主动观看时长与输入受阻时长分开 | 长路奖励是否被实现成等待 | 所有动画时间应缩短 |
|
||||
| 自然点击策略下关键路线的曝光 | 核心内容是否经常发生 | 抽样出现率等于全体真人概率 |
|
||||
| 当前关完成后是否愿意继续 | 该段是否产生继续玩的动机 | 单关留存差异全由该关造成 |
|
||||
|
||||
先用人工基准关和简单的可解释分档,再用同熟练度玩家的实际数据校准。不需要一开始训练复杂神经网络。若以后做预测,按关卡版本、模板家族和时间留出测试集,避免同模板近似题泄漏到训练与测试两侧。
|
||||
|
||||
## 两项补充研究对千关方案的共同修正
|
||||
|
||||
“关号越后,结构分越大”不够;“结构分后半程保持不变”也不保证体感稳定。需要同时知道玩家学会了什么、最近见过什么、这关实际兑现什么奖励。
|
||||
|
||||
建议把下一关选择写成可解释的设计流程:先满足已教规则与目标体验,再筛掉连续重复、视觉过载和过量操作,最后从符合当前熟练度的候选中选取。先实现可审阅的离线编排;在线个性化作为有数据后再评估的选项。
|
||||
|
||||
这与[PCG-QD](02-pcgqd.md)的关系是:多样关卡库提供选择范围;编排器决定玩家走哪条内容序列;试玩校准判断这条序列是否真的合适。
|
||||
@@ -1,155 +0,0 @@
|
||||
# 国际相近游戏:关卡机制、内容组织与证据边界
|
||||
|
||||
研究日期:2026-09-12。适用项目:HEX TRAILS。本文是后续制作知识库的一部分,不是对竞品生成器的逆向结论。
|
||||
|
||||
**目前最有用的发现是:同属“点击箭头清空”的游戏,可以把挑战放在完全不同的位置——寻找出路、识别遮挡、颜色分区、时间压力或关后评价。为了做出 1000 关,首先要稳定我们自己的体验,再扩展内容组合;不能把竞品的关数、棋子数或付费卡点直接当作难度曲线。** 这是一条基于以下资料提出的项目建议,不是竞品开发者共同发表的结论。
|
||||
|
||||
本流使用 Exa 进行 13 次搜索,请求 65 个结果位,返回 49 个精确 URL;不同地区的同一商店页包含在这 49 个 URL 中。实际抓取并核读 14 个不同页面的相关正文,直接查看 1 段视频的 16 个时间点,以及 2 张官方宣传截图。没有安装或完整通关这些游戏,也没有读取其关卡数据或源码。来源与检索记录分别见 [international-sources.json](../../exa-results/level-design-2026-09-12/international-sources.json) 和 [international-search-log.json](../../exa-results/level-design-2026-09-12/international-search-log.json)。
|
||||
|
||||
## 1. 证据怎么使用
|
||||
|
||||
| 标签 | 可以支持的结论 | 不能自动支持的结论 |
|
||||
| --- | --- | --- |
|
||||
| 官方文案 | 商店主体、宣传的基本规则、列出的功能 | 实际每关规则、关卡总量核验、人工与程序化占比、真实难度变化 |
|
||||
| 本次视觉观察 | 指定截图或视频时间点里确实可见的状态 | 没有显示的操作、并行输入逻辑、完整规则、整条主线规律 |
|
||||
| 作者体验 | 行业作者报告自己玩到的机制与感受 | 本次亲测、当前全部版本一致、开发团队的意图或内部算法 |
|
||||
| 用户个例 | 某位用户报告的感受或问题,可形成验证假设 | 所有玩家的意见、统计频率、留存或收入因果 |
|
||||
| 项目推论 | 结合证据和本项目目标提出的设计与实验 | 已经验证有效的竞品经验、已证实的 1000 关方案 |
|
||||
|
||||
Exa 抽取的商店页可能来自不同时间的缓存。本文不使用“2 天前更新”之类相对日期推断当前版本,也不把搜索结果中的出版时间当成游戏上线日期。
|
||||
|
||||
## 2. 先解决 Arrow Jam 的同名问题
|
||||
|
||||
只给出“Arrow Jam”不足以唯一定位产品。下面几个产品不能互相借用机制、关数或玩家反馈。
|
||||
|
||||
| 产品身份 | 已核对的主体及唯一标识 | 本次有依据的区别 |
|
||||
| --- | --- | --- |
|
||||
| Arrow Jam! - Tap Puzzle | Grand Games A.Ş.;iOS `6762192889` | 官方明确有限时间、先释放一枚给其他箭头让路,列出 linked arrows、corners、pipes;本次录像也显示倒计时。[商店](https://apps.apple.com/us/app/arrow-jam-tap-puzzle/id6762192889) |
|
||||
| Arrow Jam | PoseidonJoy/POSEIDON TECHNOLOGY LIMITED;Android `com.sp.arrow.jam` | 文案强调指定路径、碰撞、狭窄布局,宣称数百个手作关卡。未实机核验。[商店](https://play.google.com/store/apps/details?id=com.sp.arrow.jam&hl=en) |
|
||||
| Arrow Jam! - Puzzle Game | CyberGame Limited;iOS `6764256696` | 宣称 12 种形状、数百关、无计时,提到圆、心、星形。与 Grand 的有计时版本不同。[商店](https://apps.apple.com/us/app/arrow-jam-puzzle-game/id6764256696) |
|
||||
| Arrows Jam: Tap Escape Puzzle | Ga Mee Global Limited;Android `com.gameeapp.android.app.arrows` | 宣称 1000+ 关、无倒计时。数字是商店声明,尚未核数。[商店](https://play.google.com/store/apps/details?id=com.gameeapp.android.app.arrows&hl=en) |
|
||||
| Arrow Jam Go! Tap Escape | TidalAurum, LLC;iOS `6757224414` | 官网说 7000+,商店正文仍说数百个布局;统计范围与时间不明,不能选择较大数字当成已验证事实。[官网](https://arrowjamgo.com/)、[商店](https://apps.apple.com/us/app/arrow-jam-go-tap-escape/id6757224414) |
|
||||
|
||||
本报告把 **Grand Games 版本**作为有录像可交叉核对的 Arrow Jam 样本,并把其余版本保留为身份索引;这不表示已经确认用户此前说的就是 Grand 版本。后续若提供原始商店链接,可直接收束到对应版本。
|
||||
|
||||
另一个容易混淆的名称是 Unpuzzle。这里研究的是 **KekGames 在 Kongregate 发布的原版**,不是搜索中出现的 Hypercell、包名 `com.taptapgames.unpuzzle` 的同名手游。[原版发布页](https://www.kongregate.com/en/games/kekgames/unpuzzle)
|
||||
|
||||
## 3. 六个样本,分别提供什么设计信息
|
||||
|
||||
| 样本 | 有来源的基本结构 | 与 HEX TRAILS 最相关的内容 | 本次证据强度 |
|
||||
| --- | --- | --- | --- |
|
||||
| Arrow Jam! - Tap Puzzle/Grand | 限时点击释放、阻挡关系,官方列出多种障碍 | 出路发现与连续释放;关内分段与明确挑战标签 | 官方文案+视频抽帧 |
|
||||
| Arrows – Puzzle Escape/Lessmore | 无计时、避免碰撞、提示;大量关卡是官方声明 | 密集折线组成轮廓;可把视觉内容与操作压力分开 | 官方文案+一张宣传截图 |
|
||||
| Arrow Out/Lion Studios Plus | 方向解谜、形状关、缩放和多种道具是官方描述 | 行业体验文章报告颜色分组、星级、章节门槛 | 官方文案+二手体验,部分规则描述不一致 |
|
||||
| Tap Away/Popcore | 单方向离场的 3D 方块,旋转整体从其他角度观察 | 形状本身就是关卡内容,移除过程逐步改变整块结构 | 官方文案+一张宣传截图 |
|
||||
| Traffic Escape!/FOMO | 根据车顶箭头判断路径,按次序移动车辆避开其他车辆 | 让路因果的生活化表达;新增压力机制可能改变舒缓定位 | 官方文案+具体用户个例 |
|
||||
| Unpuzzle/KekGames | 拖走相互拼接的方块,逐块清空 | 允许多种解序的拆解;新规则应保持标识清楚 | 创作者发布页+发行平台说明+用户个例 |
|
||||
|
||||
逐项证据见下文。这个表没有给各游戏打“好玩程度”或“1000 关质量”分数,因为本次证据不足以作这种排名。
|
||||
|
||||
### 3.1 Arrow Jam! - Tap Puzzle:计时与复杂结构是两种不同压力
|
||||
|
||||
Grand 的官方玩法说明把目标写得很清楚:找出路径畅通的箭头,释放它来打开其他箭头的路径,在时间结束前清空。官方同时列出相连箭头、转角、管道等障碍;这些名字不等于本次已验证其完整规则。[App Store,INT-02](https://apps.apple.com/us/app/arrow-jam-tap-puzzle/id6762192889)
|
||||
|
||||
本次在浏览器打开 IOSTouchplayHD 于 2026-06-02 发布的 iOS 录像,开屏可见 Grand 标识,视频描述中的商店链接也指向相同 App ID。以下是抽帧观察记录;不是从字幕生成的实机结论,也不是完整通关记录。[原录像,INT-03](https://www.youtube.com/watch?v=6tObwJPw-JA)
|
||||
|
||||
| 时间点 | 画面中实际可见 | 可以提炼的设计问题 |
|
||||
| --- | --- | --- |
|
||||
| 00:20、00:23、00:26 | “Levels 1–4”标签;从极少箭头到若干彩色折线;顶部约 3 分钟计时器;部分箭头已经离开棋盘范围 | 起步是否先提供很短的成功循环,再增加要观察的线条? |
|
||||
| 00:30、00:33、00:36 | 同一标签下的彩色弯折布局逐步清空,随后出现完成反馈 | 画面复杂度与需要多少关键判断应分别记录。 |
|
||||
| 00:39 | 约 3:00 起始计时;一条外围长折线包住内侧蓝色箭头群 | 外围与内侧可形成清楚的空间层级,但仅凭此帧不能确定释放依赖。 |
|
||||
| 01:00 | 明确“Level 6”;灰色箭头与左侧彩色直箭头;倒计时 2:55 | 教学后的视觉变化可能来自标识或局部规则,需要完整记录交互才能判断。 |
|
||||
| 03:00 | 主线节点 12、13、14,以及更上方的 Hard 标记 | 挑战有显式包装;此画面不支持固定每几关一个难关。 |
|
||||
| 04:00 | 上下两簇箭头,中间幕布显示数字 7 | 关内可以分阶段揭示内容;幕布触发条件本次未完整追踪。 |
|
||||
| 07:00 | 长红色外围折线、内侧绿色箭头群;计时 2:58 | 同一“围绕—内侧”的布局母题可以改变内部结构。两帧相似不等于数据重复。 |
|
||||
| 10:00 | Super Hard 标签、2:46 计时、上下分布的黄色和绿色箭头 | 计时与布局共同出现;标签不是客观难度测量。 |
|
||||
|
||||
这些画面足以证明该样本的计时器、局部空间层级和挑战标签确实存在。**它们不能证明点击缓存、真实并行运动、动态碰撞、安全点击率或第 1000 关结构。** 即使录像看起来清得很快,也无法从少量静帧确定第二次点击何时被引擎接受。
|
||||
|
||||
商店里一位用户说后期图案重复;这是值得做结构去重检查的信号,但没有关号和统计样本,不可写成“Grand 后期大量重复”的事实。[同页用户评价,INT-02](https://apps.apple.com/us/app/arrow-jam-tap-puzzle/id6762192889)
|
||||
|
||||
**迁移建议:** 我们可借鉴清楚的外围/内侧阶段和成功反馈,但 HEX TRAILS 的长路行进本身是回报。若照搬倒计时,玩家可能被迫忽略原本想看的巡游。保留无时间压力主线,单独测试需要快操作的玩法是否成立,更符合[本项目设计准则](../level-design-principles-v2.md)。
|
||||
|
||||
### 3.2 Arrows – Puzzle Escape:形状与密度可以成为独立内容轴
|
||||
|
||||
Lessmore 的官方商店说明为无计时、避免碰撞、可用提示,并宣称数千个手作关卡;制作方官网也列出这一产品。这里的“数千”“手作”“逐渐复杂”均为制作方自述,没有公开工具、制作工时或完整关卡统计。[Google Play,INT-04](https://play.google.com/store/apps/details?id=com.ecffri.arrows&hl=en)、[Lessmore 官网,INT-05](https://lessmore.games/)
|
||||
|
||||
本次直接查看该 Google Play 页面第一张宣传截图:深色折线箭头密集拼出有侧面轮廓与底座的整体图案,上方有三颗心。它说明形状可以由实际棋子构成,轮廓识别与逐步清空可以同时出现。**这只是宣传选样,没有关号,不代表形状关在主线中的比例。** [截图来源页,INT-04](https://play.google.com/store/apps/details?id=com.ecffri.arrows&hl=en)
|
||||
|
||||
**迁移建议:**
|
||||
|
||||
- 给“整体轮廓”和“真实成功行进路线”各自设检查项。我们的花瓣必须由配对轨道、实际行进和整盘构图共同支持,不能只靠空轨装饰。
|
||||
- 把长线条的静态外形、消除动画持续时间、棋子头部实际经过的曲线路程分开。竞品箭头线条很长,不足以证明它提供了 HEX TRAILS 想要的“起步后沿底盘多次转向”。
|
||||
- 先生成“低推理负担+强形状”“中等推理+弱形状”等不同组合,避免把所有花形关放入最高难度档。
|
||||
- 黑白线条减少颜色噪声,但也可能增加密集跟线负担;这种效果需要在我们的六角交织轨道上测试,不能仅从截图判定优劣。
|
||||
|
||||
### 3.3 Arrow Out:降低读图负担与提高通关门槛可以同时发生
|
||||
|
||||
Arrow Out 商店销售商为 Lion Studios Plus LLC,版权行写 Mindstorm Studios 2025。中文文案列出缩放、提示、魔法棒、橡皮擦,并宣称形状关与数千关;其“旋转箭头、移动方块”的表述不能直接视为本次已确认的实机规则。[App Store,INT-06](https://apps.apple.com/us/app/arrow-out/id6754243057?l=zh-Hans-CN)
|
||||
|
||||
白鲸出海 2026-05-22 的体验文章报告了另一组具体观察:线条按箭头方向退出、三次错误失败;用颜色分区降低跟线负担;同时控制箭头数与颜色数;通关星级关联误判次数,章节解锁需要星星。文章还报告第 20 关与第 40 关分别开启特定活动。这里保留为 **作者当时版本的体验报告**,不把这些关号当作当前所有版本的固定规则。[虎嗅转载,INT-07](https://www.huxiu.com/article/4860736.html)
|
||||
|
||||
同一文章把收入变化归因于这套改造,并引用第三方商业数据。本报告没有独立核实其收入,也不采用这种因果结论。尤其不能据此证明“多制造失误才能留住玩家”。
|
||||
|
||||
**迁移建议:** 颜色或线宽可以辅助读图,但先保证不改变我们的规则含义;星级、体力、广告和章节门槛属于另一层进度与商业系统。做 1000 关的第一版质量评估,应测布局本身的观察难度、反差和释放感,不能用重试次数或星级缺口替代。
|
||||
|
||||
**待核实矛盾:** 官方中文文案的“旋转箭头”与文章描述的直线退出是否对应不同功能、版本或翻译,目前无法确定。报告不自行补成一个混合玩法。
|
||||
|
||||
### 3.4 Tap Away:旋转观察、形状清空与旋转换路要区分
|
||||
|
||||
Popcore 的官方说明明确:点方块使其沿单一方向飞走,滑动屏幕旋转整体,从不同角度判断;随着推进,结构与方块形状变化,并有主题、皮肤。第一张宣传截图直接可见立方体堆叠、方向箭头与点击手势。[Google Play,INT-08](https://play.google.com/store/apps/details?id=com.jctswbglsm.SwipeAway&hl=en)
|
||||
|
||||
**迁移建议:** 方块或棋子可以拼成完整的物体,清空时整物逐步分解,这种“整体状态变化”值得借鉴。但 Tap Away 文案中的旋转用于从不同角度观察整个结构;HEX TRAILS 是棋子不动、底盘轨道改变。两种旋转对依赖关系的作用不同,不应共用一个难度计数。
|
||||
|
||||
一个可用的制作卡字段是:“这一操作增加了可见信息,还是实际改变了通行条件?”它能帮助我们识别无效旋转,以及真正的一转放行反差。
|
||||
|
||||
### 3.5 Traffic Escape!:清挡因果直观,新增压力未必增强原有享受
|
||||
|
||||
FOMO 官方说明要求通过车顶箭头查看路径,决定移动车辆次序,避免其他车辆,并宣称后续拥堵更大、更密集。这能支持清挡与出路判断的机制描述,不能支持真实关卡数或车道生成算法。[Google Play,INT-09](https://play.google.com/store/apps/details?id=com.bonnie.trafficescape&hl=en)
|
||||
|
||||
同页 2025 年 3–4 月的三条评论反对新增爆炸卡车或交换车辆:有用户说原本享受从容观察,现在不得不赶时间;其中两人自报已到 6588、17000 关。这些关号未经核验,但可形成一个明确研究问题:**把舒缓拆解增加为计时应急,是否改变了原先吸引这批玩家的体验?** 不能把三条负面评论推广为全部玩家反馈,也不据此认定这些功能总体失败。[同页评论,INT-09](https://play.google.com/store/apps/details?id=com.bonnie.trafficescape&hl=en)
|
||||
|
||||
**迁移建议:** 内容量增长优先改变路线形态、关键让路关系和阶段安排。引入新压力机制前,应能解释它怎样增强长路、反差或整盘释放,而不是仅仅增加失败机会。
|
||||
|
||||
### 3.6 Unpuzzle:多种解序与“轻松但满足”值得作为参照
|
||||
|
||||
KekGames 的原始发布页把目标写为逐块清空,操作为拖动方块拆离;Poki 的发行说明进一步写明有其他方块挡路时不能拖走,并允许多种解法。[Kongregate,INT-10](https://www.kongregate.com/en/games/kekgames/unpuzzle)、[Poki,INT-11](https://poki.com/en/g/unpuzzle)
|
||||
|
||||
原发布页有玩家说“容易但满足”,也有人指出旋转标记与方向标记叠加时不易辨认。这两类评论只能提示体验和可读性问题,不能替代测评样本。[评论所在发布页,INT-10](https://www.kongregate.com/en/games/kekgames/unpuzzle)
|
||||
|
||||
搜索还找到多个站转载“一百五十关、十项附加机制、无失误惩罚”等一人称文案;本次未在原官方商店重新核到,故不将转载次数计为多个独立证据,也不用它证明全体关卡性质。[存档转载线索,INT-18](https://apkpure.com/unpuzzle/com.kekgames.unpuzzle)
|
||||
|
||||
**迁移建议:** HEX TRAILS 成功移除只应减少障碍,玩家可以有多种合理解序。评审重点应是不同自然解序仍能触达巡游和反差,而不是强求唯一解。附加标记或新规则一旦提高识别负担,应能带来对应的体验收益。
|
||||
|
||||
## 4. 可以进入制作知识库的五张设计卡
|
||||
|
||||
以下全部是本项目建议,不能标成竞品已验证方法。
|
||||
|
||||
| 知识卡 | 使用时机 | 需要记录与验证 |
|
||||
| --- | --- | --- |
|
||||
| K1:长路不是难度代理 | 为花瓣、回环、长绕行打分时 | 实际路程、弯数、空间跨度;前置关键动作;玩家是否愿意跟完。不能用长路直接提高推理档。 |
|
||||
| K2:释放关系与几何形状分开制作 | 从几个母题扩为大量关卡时 | 先写“谁放谁”,再写路线与轮廓。相同形状至少允许不同释放关系;相同依赖也可承担不同视觉内容。 |
|
||||
| K3:操作流畅度是关卡可用性的前提 | 验证快点、连续清空和长路动画时 | 点击是否接收、何时启动、阻挡何时重算、是否丢输入;用实际连续操作测试,不能以视频看起来顺畅代替。 |
|
||||
| K4:难关后的舒缓应降低判断量 | 安排波浪式节奏时 | 保留丰富路径与形状,减少前置依赖和必须旋转;不要一律缩为几条短直线。 |
|
||||
| K5:新增内容先增强原有回报 | 考虑计时、幕布、炸弹、星级门槛时 | 写明服务哪项核心体验;若主要增加等待、赶时间或付费需求,单独评估,不纳入布局质量分。 |
|
||||
|
||||
## 5. 对“高质量 1000 关”的直接影响
|
||||
|
||||
不能据现有资料声称某竞品采取固定锯齿难度、每隔多少关给花形、前 500 关手工后 500 关程序生成。更稳妥的方案是把它们转成可测试的设计维度:
|
||||
|
||||
1. **结构内容轴:** 释放依赖、关键门槛数、旋转对通行条件的实际作用、阶段数量。
|
||||
2. **观看内容轴:** 真实行进路程、连续弯绕、整体花形或其他轮廓、清空后的视觉变化。
|
||||
3. **负担轴:** 跟线、跨区寻找阻挡、颜色与标记识别、重复点击、被系统迫使等待。
|
||||
4. **节奏轴:** 首次回报何时出现,中段是否有新机会,最后几枚是否顺畅兑现。
|
||||
5. **多样性轴:** 邻关在以上维度上有何不同;换色、镜像、旋转视觉包装不能自动当成新的体验。
|
||||
|
||||
这些轴可与论文中的任务/空间分离、质量多样性档案对接。竞品提供的是可观察的表达方式与反例;论文提供组织生成和筛选的框架;最终难度边界与编排频率仍由我们的样关、规则回放和真人体验来校准。
|
||||
|
||||
## 6. 排除的伪确定性,以及下一轮怎样补证
|
||||
|
||||
本轮明确排除两类看似直接却证据不足的材料:
|
||||
|
||||
- 一篇承接开发业务的文章给出“前 500 关手工、后面程序化”“每天 15–25 关”等数字,并推测 Lessmore 使用生成工具。文中没有制作方依据,不能当作 Lessmore 的实际生产法;示例代码要求唯一解,也不自然适合我们的多解序拆解规则。[被排除的商业建议,INT-16](https://raijinnstudio.com/blog/minimalist-arrow-puzzle-game-design-guide)
|
||||
- 一个“第 1000 关攻略”搜索结果只列出先清外围、再清中心等通用步骤,缺少可复核的逐棋子次序。本次未验证其嵌入视频,不用它评定第 1000 关,更不把 1000 个网页条目等同于 1000 关研究。[未验证攻略,INT-17](https://arrowspuzzleguide.com/levels/1000)
|
||||
|
||||
后续如需竞品的精确难度曲线,应固定 App ID、版本、平台、存档起点和模式,连续记录早期关卡,再按已知关号抽取中后段;每关保留完整初盘与回放、真实输入、失误、提示使用和动画时长。对于本次仅见宣传截图的形状关,要找到带关号的实际回放。即便得到这些数据,也只能描述该版本的样本曲线;生成算法、动态分配与 AB 实验仍需公开开发者材料或获得授权的数据来确认。
|
||||
@@ -1,98 +0,0 @@
|
||||
# 中文箭头游戏调研:从《一箭又一箭》提取量产与节奏经验
|
||||
|
||||
调研日期:2026-09-12。适用项目:HEX TRAILS。检索工具:Exa。本文是有来源的设计研究;本轮没有安装、实玩这些移动游戏,也没有逐帧核验实机视频。
|
||||
|
||||
最有价值的发现,是《一箭又一箭》开发者已经公开讨论了我们面临的同一个问题:大量关卡怎样持续供给、怎样随玩家熟练程度重新编排。其做法可以支持“生成、评级、排序、反馈分别迭代”的生产方向,但没有公开可直接复用的难度公式,也没有证明固定的 1000 关配比。
|
||||
|
||||
## 1. 先确认研究的是哪个游戏
|
||||
|
||||
| 产品/版本 | 身份依据 | 可确认与不可合并之处 |
|
||||
| --- | --- | --- |
|
||||
| **一箭又一箭,微信小游戏** | [腾讯应用宝官方条目](https://sj.qq.com/appdetail/wx69949b45b793b612),小程序标识 `wx69949b45b793b612`,页面列开发者海南掌趣网络科技有限公司。[2026 年开发者大会实录](https://www.youxituoluo.com/534534.html)由广州畅想互动何毅坤讲述研发历程。 | 官方平台条目与研发分享者的主体名称不同,分别记录,不能擅自解释其代理、控股或发行关系。 |
|
||||
| **一箭又一箭,Google Play App** | [Google Play 官方条目](https://play.google.com/store/apps/details?hl=zh_HK&id=com.cxgame.yjyyjgoo),包名 `com.cxgame.yjyyjgoo`,开发者 CXHD Network Technology Co. Ltd.,关于开发者列广州畅想互动网络科技有限公司。 | 可确认同名产品由该研发主体发布。不能据此认定其关卡、道具、广告、计时与微信版完全同步。 |
|
||||
| **箭了又箭/超级消消,微信、抖音小游戏候选** | [行业报道](https://news.qq.com/rain/a/20260107A06XJ600)将产品归于广州池骋网络;[池骋官网](http://www.cc9527.com/)可确认公司身份,但本轮所读官网没有该产品的详细玩法条目。 | 有媒体关联,尚缺可核验的对应小程序 ID、研发说明与连续实机记录。本篇仅作为市场对照,不能当成《一箭又一箭》的别名。 |
|
||||
| **箭了个箭 - 箭头向前冲,iOS App** | [App Store 官方条目](https://apps.apple.com/cn/app/id6755886795),ID `6755886795`,提供者文龙 刘。检索缓存中亦出现副标题“你聪明你来”。 | 以商店 ID 识别同一条目。其文案描述目标箭头出逃、邻箭头变向等规则,尚未实机核验;不能借相似名称给用户所指游戏补规则。 |
|
||||
|
||||
本轮发现了足以造成错误结论的同名和缓存问题:
|
||||
|
||||
- 搜索将 `wxc485463086fbd9d0` 标为“箭了又箭新”,但[实际抓取页面](https://sj.qq.com/appdetail/wxc485463086fbd9d0)标题已是“挪动物”,故排除为《箭了又箭》的当前身份凭据。
|
||||
- [TapTap 的“箭了又箭”条目](https://www.taptap.cn/app/798583)和 [App Store ID 6756483139](https://apps.apple.com/cn/app/%E7%AE%AD%E4%BA%86%E5%8F%88%E7%AE%AD-%E8%B6%85%E7%BA%A7%E6%B6%88%E6%B6%88%E7%8E%8B/id6756483139)介绍的是冲刺、躲避障碍;后者提供者为盟 吉。没有证据可将它们并入池骋的箭头消除小游戏,故不用于分析其关卡逻辑。
|
||||
- 复刻教程的网格尺寸、DAG 生成器、毫秒耗时,仅属于作者的复刻实现,不是原游戏的内部实现。下载站或聚合站的泛化玩法说明也不进入核心证据。
|
||||
|
||||
## 2. 《一箭又一箭》:开发者实际披露了什么
|
||||
|
||||
核心来源是 2026 年 5 月 27 日微信小游戏开发者大会上的何毅坤分享,全文核读了[游戏陀螺实录](https://www.youxituoluo.com/534534.html)、[参会者 ZRONG 实录](https://blog.zengrong.net/post/one-arrow-after-another-combo-innovation/)及[游戏日报实录](https://news.yxrb.net/2026/0528/7007.html)。三篇均来自**同一场演讲**,只算一个开发者经验来源;没有取得原始实验数据或独立复现。下列“开发者披露”均是演讲转录中的自述。
|
||||
|
||||
### 2.1 规模问题确实包含“内容消耗速度”
|
||||
|
||||
开发者称平均用户每日通过约 30–40 关,核心用户可能达到 200–300 关。这是该团队报告的产品数据,未附统计窗口、样本定义或分布,不能套用为 HEX TRAILS 的日均目标。[来源](https://www.youxituoluo.com/534534.html)
|
||||
|
||||
**对我们的推论:**1000 关库存能维持多久,要同时看单关体验和用户的内容消耗。按上述自述数字进行简单情景计算,1000 关对应约 25–33 个活跃日,或约 3–5 个高强度活跃日;这不是本项目的留存预测,却提示“达到 1000”与“持续有内容”需要两套验收。
|
||||
|
||||
### 2.2 难度排序需要随熟练程度改变
|
||||
|
||||
开发者称早期采用简单、中等、困难循环;老玩家后来反馈越来越简单,团队认为主要原因是熟练程度提高。随后在后段提高困难关出现频率,并在多次 A/B 试验中把难度分级从 3 档扩展到 5 档。[来源](https://blog.zengrong.net/post/one-arrow-after-another-combo-innovation/)
|
||||
|
||||
**对我们的推论:**相同结构的关卡,对第 20 关玩家和第 700 关玩家未必具有相同体感。我们的分级应同时记录结构负担和玩家阶段;舒缓关也应保留新的路线或漂亮的兑现方式,以免只剩熟练操作。这里没有披露“每几关一个难关”、难度阈值、评分系数或通关率目标,因此先前方案中的具体配额仍只是待测假设。
|
||||
|
||||
### 2.3 AI 参与了一整套制作工具与调优工作
|
||||
|
||||
演讲将评分算法、生成算法、编辑器、关卡排序及难度节奏调整都列为 AI 参与完成的工作;并说重排涉及大量关卡。没有公开代码、模型、提示词、数据格式、自动化边界,无法判断是运行时模型直接出图、AI 编写程序,还是二者结合。[来源](https://news.yxrb.net/2026/0528/7007.html)
|
||||
|
||||
**对我们的推论:**最可迁移的是工具链分工:生成器产候选,验证器保证规则,评级系统表征负担,编排器选择顺序,策划根据反馈改目标。不能把“使用 AI”当成关卡质量凭证,也不能把本项目拟议的质量多样性搜索说成该产品实际用了 MAP-Elites。
|
||||
|
||||
### 2.4 特殊机制以低频出现维护新鲜感
|
||||
|
||||
开发者说明彩色箭头额外消除、吃豆人灵感、巨大箭头、冲刺连击等变化,并称新机制平均每天只让用户遇到 1–2 次,以特殊或奖励关形式出现;巨大箭头的目标之一是带来明显的视觉变化,而不显著增加难度。[来源](https://www.youxituoluo.com/534534.html)
|
||||
|
||||
**对我们的推论:**“新鲜”可以来自视觉尺度、放行方式和回报变化,不必不断增加规则。但必须区分我们的两种内容:长路与轻巧反差是日常核心体验,应经常兑现;花瓣、编织、螺旋属于原有规则下的空间语言,也可以成为常见路线家族。真正改变规则的新机关,才更适合先按特殊关低频试验。不能机械地把长路关也降为每天一两次。
|
||||
|
||||
### 2.5 连击是正反馈目标,是否并行动画仍未知
|
||||
|
||||
演讲明确说连击机制来自用户希望消除更爽快的反馈,并描述利用上下线槽形成进度反馈。它没有说明同时在途棋子的数量、动画是否串行、是否缓存点击、碰撞状态何时提交。[来源](https://blog.zengrong.net/post/one-arrow-after-another-combo-innovation/)
|
||||
|
||||
**对我们的推论:**关卡制作和交互验证必须联合进行:同一盘在“一次看完一枚”的玩法下和快速连续点出的玩法下,奖励密度不同。我们应记录有效快速点击接收率、最大在途数、每段可连续释放的数量、长路是否被其他运动遮蔽。不能从竞品提到连击直接推出其实现了真正并行,更不能因此取消本项目用户要求的快速点击。
|
||||
|
||||
### 2.6 计时调节与关卡结构是两类变量
|
||||
|
||||
开发者自述通过动态时间限制适配不同熟练度,追求临近截止时通过的体验,并称测试改善了留存和商业表现。转录版本对商业指标出现 ARPU 与 IPU 的差异;本轮没有核实演讲幻灯片与原始口径,因此不报告提升百分比,也不把具体商业指标作为可靠结论。[游戏陀螺](https://www.youxituoluo.com/534534.html)、[ZRONG](https://blog.zengrong.net/post/one-arrow-after-another-combo-innovation/)
|
||||
|
||||
**对我们的推论:**同一空间谜题可以因时限变成不同的压力体验,所以难度数据必须区分结构、识别负担和外部压力。本项目现行方向强调完整观看长路、免费试路,暂无理由直接引入倒计时。先验证本项目的巡游与反差是否成立;若以后研究计时模式,应作为另一个明确的体验目标。
|
||||
|
||||
### 2.7 反馈解释“为什么”,不能只看流失数
|
||||
|
||||
演讲把内置问卷、游戏社群意见列为迭代输入,用来解释用户为什么无聊、为什么不继续,而不是只根据异常指标增加内容。[来源](https://news.yxrb.net/2026/0528/7007.html)
|
||||
|
||||
**对我们的推论:**试玩记录应把“没看到长路”“长路好看但接连点击不响应”“依赖看不懂”“已经熟练所以无聊”分开。这些原因对应路线、输入、可读性、排序四种不同修正,不能都归为难度偏高或偏低。
|
||||
|
||||
## 3. 中文同类的差异与可迁移范围
|
||||
|
||||
| 对照对象 | 来源能支持的设计信息 | 对 HEX TRAILS 的价值与边界 |
|
||||
| --- | --- | --- |
|
||||
| 一箭又一箭,Google Play 版 | 官方文案描述前方畅通时点击放出,另有黑洞、大箭头、水管传送转向等机关;强调消除音效和流畅动画。[商店](https://play.google.com/store/apps/details?hl=zh_HK&id=com.cxgame.yjyyjgoo) | 支持研究“沿路运动本身如何成为奖励”和“机关如何改变放行方式”。具体运动轨迹、连锁细节、三星规则尚未亲测;不能推定它和 HEX TRAILS 的固定轨道配对、底盘旋转相同。 |
|
||||
| 箭了又箭/超级消消,小游戏候选 | 行业报道描述长短线条互相阻挡、依次拆出、碰撞回弹、失误次数与时限;提及形状、色彩、动物外观变体。[报道](https://news.qq.com/rain/a/20260107A06XJ600) | 值得对照的维度是从拥挤到清空、阻挡因果、视觉辨识与外部压力。该报道没有足够的关卡样本,不能据此重建前 1000 关曲线或推出图案关频率。 |
|
||||
| 箭了个箭,iOS ID 6755886795 | 商店文案宣称朝向移动后会改变相邻箭头朝向,并有目标出口、障碍与传送门;更新说明把动画、跟手和消除反馈列为改进点。[商店](https://apps.apple.com/cn/app/id6755886795) | 若实机证实邻箭头变向,则属于“操作改变未来状态”的不同规则族,不宜照搬单调清挡的依赖模型。现阶段仅列为待测反例;“千关挑战”仍是商店宣称,不是 1000 关质量审计。 |
|
||||
|
||||
**一个需要纠正的行业术语:**报道把碰撞回弹、不易因误操作永久卡死称为“唯一解”。这并不严谨。有解、成功消除不会新增阻挡、只有一个合法完整消除序列,是三个不同命题。若 A、B 互不阻挡,先 A 后 B 与先 B 后 A 就已构成不同消除顺序。知识库统一使用“可解性”“成功移除的单调性”“解序列数量”,不沿用该报道的“唯一解”说法。[被核对的报道](https://news.qq.com/rain/a/20260107A06XJ600)
|
||||
|
||||
## 4. 长路、反差、花瓣路线应该怎样吸收这些经验
|
||||
|
||||
以下是本项目的设计推导,不是竞品公开配方。
|
||||
|
||||
| 本项目目标 | 建议进入制作卡的变量 | 候选验证方式 |
|
||||
| --- | --- | --- |
|
||||
| 长路巡游 | 实际成功路径长度、转弯与空间展开;首次放出位置;一路行进是否值得跟随 | 同时播放独立观赏与快速连点两种回放,检查关键长路能否被看见。不能用棋盘线条总长度替代。 |
|
||||
| 轻巧反差 | 第一眼预期、目标箭头朝向、放行前置动作数、回报等待距离 | 使用朝内起步但能离场、清一枚放长路、转一次接出口等样关,询问预期与实际落差。巨大箭头的视觉反差只是相邻经验,不证明旋转反差已经有效。 |
|
||||
| 花瓣及图形路线 | 外轮廓可辨认性、实际使用的花瓣路径、与上一关的结构差异 | 区分“整体轮廓像花”和“棋子真的走出花瓣轨迹”;给相同轮廓配置不同清挡或旋转节奏,剔除只换皮的近重复。 |
|
||||
| 关内释放节奏 | 开局可动数、一次动作新增可动数、连续可释放数量、最后几枚的表演内容 | 制作“宽开局—短清挡—长路兑现”等明确结构,再看真实选择是否仍能碰到设计的回报。 |
|
||||
| 1000 关难度曲线 | 玩家熟练阶段、结构负担、识别负担、操作和动画时长、内容新颖性 | 比较固定三拍循环与按熟练阶段调整的序列;观察继续游玩、疲劳、误点解释和回报识别,不只优化总通关数。 |
|
||||
|
||||
推荐先做成 **三组可比样关**:同结构换空间形态、同形态换依赖结构、同奖励换放行门槛。每组控制其他变量,分别研究玩家究竟是在享受路线、享受解锁,还是因拥挤和输入受阻而耗时。这个实验设计比直接借用竞品宣传的“越往后越难”更能指导本项目量产。
|
||||
|
||||
## 5. 本轮证据边界与下一次最值钱的补充
|
||||
|
||||
本流共运行 9 次 Exa 搜索,请求 50 个候选结果,返回 35 个不同的原始 URL;实际完成 11 个页面的正文阅读,另有 1 个 URL 抓取超时后以同一 App 的完整商店 URL 读到正文。候选数不等于阅读数,三个演讲转录也不等于三个独立产品实验。完整[检索日志](../../exa-results/level-design-2026-09-12/chinese-search-log.json)及[来源台账](../../exa-results/level-design-2026-09-12/chinese-sources.json)保留了排除项。
|
||||
|
||||
本轮未实玩移动版本,未亲眼核验完整实机视频或演讲配图;网页尝试受到连接和子任务浏览器能力限制。因此没有给出关号、运动时长、并行上限、花形出现频率等观察数据。正文中仅将商店文案视作产品方宣称,将演讲视作开发者经验,将行业报道视作二手信息。
|
||||
|
||||
后续现场样本应优先补齐:确认用户实际玩到的小程序身份与版本;各取早期、熟练后和特殊关的连续游玩记录;对同盘执行慢点、快速连点、解锁中连点,记录是否丢输入及奖励曝光;核验形状关到底改变了布局轮廓、实际路线还是规则。对样本之外的第 1000 关仍保持未知,直到得到对应数据。
|
||||
@@ -1,71 +0,0 @@
|
||||
# HEX TRAILS 关卡设计知识库
|
||||
|
||||
建立日期:2026-09-12。用途:为后续样关、生成器、关卡筛选、难度编排及试玩提供可追溯的设计依据。阅读入口:[关卡设计调研报告](../level-design-research-report.md)。
|
||||
|
||||
本库已完成两篇指定论文的全文精读,并通过 Exa 补充相关研究、产品官方资料、开发者分享和一份竞品录像的定点观察。论文、公开宣传、实际观察与项目方案分别标注,不能相互替代。
|
||||
|
||||
## 按设计问题查找
|
||||
|
||||
| 现在要解决的问题 | 首选条目 | 可直接取用的内容 |
|
||||
| --- | --- | --- |
|
||||
| 怎样把“清挡后放出长路”变成生成输入? | [P01:Mission 与 space](01-mission-space.md) | 任务关系、空间草图、中间表示、人工介入点 |
|
||||
| 怎样保住漂亮花瓣,局部修改棋子与难度? | [P01:制作卡 B/C](01-mission-space.md) | 两路输入、固定项与可变项、局部修改后的重验证 |
|
||||
| 怎样避免 1000 关只是同一种题换种子? | [P02:PCG-QD](02-pcgqd.md) | 行为特征、类内质量、多样候选档案、近重复检查 |
|
||||
| 为什么不能拿长路长度直接当难度? | [P02](02-pcgqd.md)、[P04](03-progression-and-difficulty.md) | 质量/类型/难度分离,结构数据与真人表现校准 |
|
||||
| 怎样安排新概念、旧概念组合和复习? | [P03:解法特征与编排](03-progression-and-difficulty.md) | 技能组合、局部差异、关卡库与顺序解耦 |
|
||||
| 老玩家觉得越来越简单,该改什么? | [中文竞品研究](05-chinese-comparators.md) | 《一箭又一箭》开发者的分档、重排与反馈经验 |
|
||||
| Arrow Jam 到底是哪一种规则? | [海外竞品研究](04-international-comparators.md) | 发行商/商店 ID 消歧,计时与非计时版本分开 |
|
||||
| 图案、奖励和机关应如何安排频率? | [中文竞品研究](05-chinese-comparators.md)、[总报告](../level-design-research-report.md) | 核心体验、空间语言、特殊规则三者分开安排 |
|
||||
| 快速连点会不会改变“好关卡”的判断? | [中文竞品研究](05-chinese-comparators.md)、[总报告](../level-design-research-report.md) | 输入响应、实际回放、奖励可见性、规则版本 |
|
||||
|
||||
## 证据标签与使用规则
|
||||
|
||||
| 标签 | 可用于什么 | 使用时保留的边界 |
|
||||
| --- | --- | --- |
|
||||
| 论文方法 | 生成器架构、评价与实验设计 | 方法提出、案例演示、对照实验分别写;保留前提 |
|
||||
| 论文实验 | 支持在对应任务、样本、指标下的结论 | 不跨品类套用数值,不把无显著差异写成等效 |
|
||||
| 开发者自述 | 了解原团队的设计意图与工作流程 | 转录可能有误;无原始数据时不作独立效果保证 |
|
||||
| 官方产品说明 | 确认产品身份与其宣称的规则/内容 | “千关”“手工”“逐渐变难”不等于已审计质量 |
|
||||
| 录像观察 | 描述该版本、时间点可见的行为与布局 | 未看到的不补写;单次录像不能恢复整条曲线 |
|
||||
| 二手分析 | 提供待核查线索和有来源的作者体验 | 不冒充开发者算法或本轮亲测 |
|
||||
| 项目建议 | 转换成样关意图、工具要求、实验问题 | 标明待验证;不因引用论文就升级为既定准则 |
|
||||
|
||||
同一论文的 PDF 与 HTML、同一演讲的三篇转载、同一 App 的多地区商店链接,不算独立证据。研究中的 novelty/surprise 与玩家的“新鲜/惊喜”不是天然等价指标。
|
||||
|
||||
## 后续制作时的最小知识使用流程
|
||||
|
||||
1. 先读[现行关卡设计准则](../level-design-principles-v2.md),明确该关承诺的主体验。
|
||||
2. 从本库选一至两张相关设计卡,写出对本关的具体约束,避免堆砌所有指标。
|
||||
3. 制作并在正式规则下回放;记录成功路径、放行关系、替代顺序与输入调度。
|
||||
4. 给候选标体验类别、结构负担、评审状态和来源,不直接用单总分决定取舍。
|
||||
5. 用连续试玩决定关号与相邻关,保留版本;必要时重排而不重做布局。
|
||||
|
||||
## 建议的关卡知识记录模板
|
||||
|
||||
```yaml
|
||||
levelId: 稳定关卡标识,不等于当前关号
|
||||
rulesVersion: 规则与输入调度版本
|
||||
designIntent: 玩家应该获得的具体体验
|
||||
sourceCards: [P01-B, QD-06]
|
||||
primaryPiece: 关键棋子标识
|
||||
fixedConstraints: 需要保留的路线/位置/放行条件
|
||||
releasePattern: 直接放行/清挡/旋转/组合阶段
|
||||
shapeFamily: 花瓣/环绕/螺旋/其他
|
||||
observedTrace: 实际成功回放与逐棋子路径数据位置
|
||||
alternativePolicies: 测过哪些合理点击和旋转策略
|
||||
rewardExposure: 哪些策略中实际出现主奖励;附样本量
|
||||
difficultyEvidence: 结构估计/设计者比较/玩家样本,分别填写
|
||||
duplicateFamily: 同骨架与近似体验家族
|
||||
reviewStatus: 待定/待修改/已验收/淘汰
|
||||
reviewReason: 具体原因,不能只有分数
|
||||
campaignPlacementVersion: 编排序列版本
|
||||
```
|
||||
|
||||
这只是制作记录建议,尚未接入游戏数据格式。引用知识卡表示采用了一个设计思路,不能替代本关验证。
|
||||
|
||||
## 来源与维护
|
||||
|
||||
- [检索与来源台账入口](../../exa-results/level-design-2026-09-12/README.md):保留 URL、身份、阅读范围、证据类型与排除理由。
|
||||
- [1000 关初步方案](../1000-level-production-plan.md):配额、分档及章节数仍为试验假设;本次研究没有确认其精确数值。
|
||||
- 后续新增条目需记录日期、来源、阅读范围、支持的具体命题、限制及对本项目的推导。
|
||||
- 玩家验证推翻建议时,保留旧建议和修正原因;不要反过来修改文献结论以迎合实现。
|
||||
@@ -1,191 +0,0 @@
|
||||
# HEX TRAILS 新版关卡设计准则
|
||||
|
||||
准则版本:v2 · 2026-09-10\
|
||||
状态:新一轮关卡制作与评审基准;已据此制作 [v0.4 的 20 关体验版](v0.4-experience-review.md)及 [v0.5 千关首版](v0.5-production-report.md)。验收范围与例外以各版实际报告为准,真人长线体验仍待试玩。\
|
||||
适用范围:主线关卡设计、样关制作、候选筛选、节奏编排与试玩评审。
|
||||
|
||||
本文基于本轮玩法讨论,以 v0.1 的长绕行、旋转换路和逐层让路结构为参照。准则版本不等于游戏中的布局版本;v0.4 是新增的独立体验版本,原有三版关卡与存档保持原状。
|
||||
|
||||
后续设计意图以本文为准;[现行玩法方向](gameplay-direction.md)和[技术说明](level-design.md)中的 v0.3 制作门槛用于解释现有实现,不能直接套用为新版目标。新准则涉及的筛选变更,须在制作样关时同步落实到生成器、测试与报告,不能仅凭本文宣称现有关卡已经符合。
|
||||
|
||||
## 1. 核心体验
|
||||
|
||||
**让玩家亲手放出棋子,看着它沿弯弯绕绕的长路径顺畅离场;也让看起来很难出去的棋子,通过一个简单动作就轻松消除。**
|
||||
|
||||
玩法同时提供过程享受和操作成就:棋子一路巡游本身值得观看;清挡或转盘之后把它放出来,又让玩家感到自己的操作很有收获。
|
||||
|
||||
箭头与路径的分工是玩法特色:**箭头决定起步方向,路径决定后续转向和最终出口。** 朝内不等于出不去,靠近边缘不等于必然好走。底盘旋转时,棋子的位置与箭头保持不动,轨道变化产生新的出路。
|
||||
|
||||
关卡设计先确定玩家将享受到什么,再安排达成它所需的观察和操作。难度、规模、弯轨比例与操作量是制作工具,不是核心体验的替代品。
|
||||
|
||||
## 2. 四项核心爽点
|
||||
|
||||
### 2.1 长路巡游:一次点击,享受一整段弯绕离场
|
||||
|
||||
玩家启动棋子,目光跟着它连续转弯、穿过交织轨道、绕到另一侧,最后开出棋盘。运动过程本身就是奖励,即使路线一眼可解,也成立。
|
||||
|
||||
制作要求:
|
||||
|
||||
- 设计实际成功离场时会走过的长绕行路线,关注连续转向、空间展开和完整的运动过程。
|
||||
- 可以让长路开局就畅通,也可以通过清挡或旋转释放。长路不必先经过困难,才有观看价值。
|
||||
- 路线长度、转弯数量和空间形态共同组织观感;大量互不相关的单弯消除不能替代一条完整的长绕行。
|
||||
- 动画应连贯、可跟随,让转弯和穿行充分呈现。完整行进是内容,不能预先视为应压缩的等待。
|
||||
- 速度与节奏通过实际播放调整;不以慢放、重复兜圈或额外停顿人为补足长路体验。
|
||||
|
||||
评审问题:**点下这枚棋子后,是否有一段让人愿意跟着看完的行进过程?**
|
||||
|
||||
### 2.2 轻巧解难的反差:看起来棘手,解决起来很轻巧
|
||||
|
||||
先让棋子的朝向和位置形成“它怎么出去”的直觉,再让一个简单、可理解的动作打开出路。
|
||||
|
||||
典型结构:一枚箭头朝内的棋子看起来不容易离场;旋转一次底盘后,箭头和棋子都没动,底下却接上向外的路线;随后点击,棋子顺畅离场。这里“一次旋转放行”指旋转建立离场条件,仍由玩家点击启动,不新增自动消除规则。
|
||||
|
||||
制作要求:
|
||||
|
||||
- 表面困难感来自箭头、位置、轨道和阻挡的组合;不靠藏线、模糊交叉或未教规则误导玩家。
|
||||
- 解法保持轻巧,典型为一次旋转,或先移走一枚明显的挡路棋子,再点击目标。
|
||||
- 出路打开后及时兑现,不再叠加多层阻挡,破坏“原来这么简单”的回报。
|
||||
- 放行后的路线可长可短:短路突出轻巧,长绕行叠加巡游享受。
|
||||
- 反差也可以由路径本身产生:朝内起步,沿轨道转向后直接离场,不要求每次都附带旋转。
|
||||
|
||||
评审问题:**玩家第一眼预计它有多难?实际需要多简单的动作?前后差异能否清楚感受到?**
|
||||
|
||||
### 2.3 清挡与换路的发现:我的操作把后面的路放出来了
|
||||
|
||||
棋子既是待释放对象,也可能为其他棋子占着空间。移走它,或改变底盘朝向,会打开新的路线。
|
||||
|
||||
制作要求:
|
||||
|
||||
- 让关键操作与新机会形成可辨认的因果,例如移走 A 后 B 通行,或转盘后内侧棋子接上出口。
|
||||
- 允许短直出棋子承担让路、开局入口和即时反馈的作用,不按自身转弯少判定其价值低。
|
||||
- 旋转应贯穿主线,并与占用变化结合;可使用“清一批再转”“转过去清挡再转回来”等结构。
|
||||
- 避免所有旋转关都重复“清完能点的,随便转一下再清完”的同一种节奏。
|
||||
- 成功移除只减少障碍,不破坏其他路线。解谜内容应来自发现关系和换路机会,不依赖合法消除后不可逆的死局。
|
||||
|
||||
评审问题:**哪一步改变了谁的出路?玩家能否看见、预判或在操作后理解这一变化?**
|
||||
|
||||
### 2.4 整盘逐步释放:越解越通,最终清空
|
||||
|
||||
单枚巡游提供局部奖励,整盘从交织受阻到逐渐放行提供持续满足。
|
||||
|
||||
制作要求:
|
||||
|
||||
- 给出可进入的开局,再通过清理和换路展开局面。
|
||||
- 组织局部阶段,例如外围让路、中央放行、旋转换路、长轨收尾;并非每关必须包含全部阶段。
|
||||
- 把长路和轻巧反差分布在过程中,不让前面大量操作都只是等待最后的奖励。
|
||||
- 收尾可以轻松而漂亮。最后几枚既可以承担长路巡游,也可以接连顺畅离场。
|
||||
- 增加棋子时,明确增加了什么体验;不能只延长重复点击。
|
||||
|
||||
评审问题:**从开局到结束,玩家是否不断获得新机会,并感到棋盘确实被自己逐步解开?**
|
||||
|
||||
## 3. 爽点之间的关系
|
||||
|
||||
| 组合 | 关卡表达 |
|
||||
| --- | --- |
|
||||
| 纯长路巡游 | 出口已经畅通,直接启动一段漂亮的长绕行,适合展示与舒缓。 |
|
||||
| 轻巧反差 | 朝内棋子转一下就能出去,实际解法很简单。 |
|
||||
| 清挡后巡游 | 短出口先让路,后面的长轨棋子获得释放。 |
|
||||
| 旋转、反差与巡游 | 看似难出的棋子,一转接通长路线,随后完整绕行离场。 |
|
||||
| 多阶段整盘释放 | 清挡、换路、长路巡游交替出现,最后清空。 |
|
||||
|
||||
每关应明确主爽点和关键棋子,不要求每关塞满全部四项。长路巡游与轻巧反差应成为主线反复出现的内容,不能只放在少数展示关;具体频率通过样关和试玩校准,暂不规定未经验证的每 10/20 关配额。
|
||||
|
||||
允许零旋转关直接提供长路巡游或路径反差,无需逐关豁免。与此同时,旋转必须保持主线核心操作的地位,不能长期退化成小棋盘中的偶尔点缀。审核时同时查看旋转频率与作用是否重复,而不是仅检查最少旋转数大于零。
|
||||
|
||||
## 4. 以 v0.1 为参照,纠正后续版本的偏移
|
||||
|
||||
三版在当前引擎下的参考解回放得到以下结构对照。这些是路径与解法数据,不是玩家满意度数据。
|
||||
|
||||
| 指标 | v0.1 | v0.2 | v0.3 |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| 必须旋转的关卡 | 24/24 | 16/48 | 16/48 |
|
||||
| 成功消除经过弯道的比例 | 56.2% | 7.0% | 75.1% |
|
||||
| 每条弯轨成功路径平均转弯 | 3.75 次 | 1.45 次 | 1.25 次 |
|
||||
| 单条成功路径最多转弯 | 16 次 | 4 次 | 4 次 |
|
||||
|
||||
v0.1 第 24 关的参考解先消除七枚直出棋子,后段包含 12、13、14、15 次转弯的成功路径。它说明短出口、逐层让路、旋转换路和长绕行可以组成完整的释放过程。相关案例与来源见 [v0.1 设计理念](v0.1-design-philosophy.md)及[归档布局](../levels/versions/v0.1.json)。
|
||||
|
||||
新版继承长绕行、解锁关系和旋转阶段,不机械复制原版的扣步压力、线性评分排序或教学缺点。尤其不能将“弯轨占比更高”视为长路体验已经恢复,也不能将原版最多 16 弯变成所有关卡必须追求的指标。
|
||||
|
||||
## 5. 难度、教学与节奏
|
||||
|
||||
### 表面困难与实际困难分开设计
|
||||
|
||||
“看起来难,轻松放出”是主动追求的内容。不要为了让布局显得有挑战,就同时加深依赖、延长试探或减少所有出口。
|
||||
|
||||
长路径增加观看内容和潜在跟线负担,但可以没有解锁门槛;短路径也可能承担复杂依赖。分别记录观看内容、推理要求和操作量,不能仅按弯数把一关定成困难。
|
||||
|
||||
### 教学要让玩家尽早尝到特色
|
||||
|
||||
前期需形成以下学习闭环,具体关号待样关编排:
|
||||
|
||||
1. 点击棋子,体验箭头起步、沿轨转向和离场。
|
||||
2. 在低阻挡条件下完整观看一段长绕行,不把长路全部推迟到高难关。
|
||||
3. 展示朝内箭头也能沿轨出盘,并用简单旋转制造一次轻巧反差。
|
||||
4. 用清楚的 A 挡 B 关系,展示短出口如何释放后续路线。
|
||||
5. 再组合清挡、交叉跟线与旋转;交叉不换轨须由实际路径清楚展示。
|
||||
|
||||
教学关一次突出一个主要理解点。玩家应亲手操作并看到回报,文字说明不能代替关卡表达。
|
||||
|
||||
### 舒缓不等于路线短,高潮不等于很难
|
||||
|
||||
- 舒缓关可减少前置阻挡,让长轨棋子更容易放出。
|
||||
- 挑战关可增加少量清晰的让路与旋转关系,完成后及时兑现巡游或反差。
|
||||
- 难关后降低判断负担,保留丰富的运动内容和成功反馈。
|
||||
- 棋盘大小与节奏角色不固定绑定;大盘可以一转放行,小盘也能呈现长绕行。
|
||||
- 六拍可作为编排参考,不固定每拍解法,也不预设首个尖峰必须位于某一关。
|
||||
|
||||
## 6. 每关制作卡
|
||||
|
||||
候选入库时填写下表;先用文字说明设计意图,再用结构数据与实际回放核对。
|
||||
|
||||
| 字段 | 必须说明的内容 |
|
||||
| --- | --- |
|
||||
| 主爽点 | 本关主要提供哪一种体验,关键棋子是谁。 |
|
||||
| 第一眼预期 | 玩家预计哪些棋子好出、哪些难出;反差关尤需说明。 |
|
||||
| 关键动作 | 直接点击、清挡、一次旋转,或一段短组合。 |
|
||||
| 实际回报 | 哪枚棋子被放行,怎样行进,在哪一步兑现。 |
|
||||
| 长路内容 | 实际成功路径的格步骤数、转弯数和空间形态;不能只统计空格装饰线。 |
|
||||
| 反差内容 | 改变前后谁的出路发生变化,实际前置动作有多少。 |
|
||||
| 阶段与收尾 | 开局入口、中段变化、最后几枚分别承担什么。 |
|
||||
| 主要负担 | 跟线、识别阻挡、预判旋转,还是重复操作;哪些可减轻。 |
|
||||
| 与相邻关的差异 | 路线形态、放行方式、依赖关系或旋转节奏有什么变化。 |
|
||||
|
||||
示例:主爽点为轻巧反差叠加长路巡游;目标是一枚朝内棋子;旋转一次后接上无阻挡的弯绕长路,点击即可完整离场;其余棋子提供容易理解的入口和收尾。此例是制作意图,必须由真实布局和回放证明,不能仅靠标签成立。
|
||||
|
||||
## 7. 验证与评审要求
|
||||
|
||||
### 规则正确
|
||||
|
||||
- 数据有效,旋转后的棋子与底格关系合法;完整参考解可回放清盘。
|
||||
- 免费旋转、免费失败试路和撤销继续有效;成功消除预算为棋子数,表示剩余工作量。
|
||||
- 求解触及搜索上限只能标为未确定,不能记为已验证可解。
|
||||
- 轨道、碰撞、动画与点击使用一致的模型;交叉处不换轨,颜色不参与规则。
|
||||
|
||||
### 体验证据
|
||||
|
||||
- 按真实成功离场时的朝向与剩余棋子回放路径。保留 `pathUsage` 及逐棋子明细,同时检查关键路径在实际画面中的表现。
|
||||
- 长路关须存在实际可释放的长绕行;多条单弯和未使用曲线不能代替。长度与弯数先记录分布和代表案例,样关验证后再制定制作带,不先用一个统一阈值裁剪全部内容。
|
||||
- 反差关须明确目标棋子、改变前后路线、前置动作和放行结果。结构能证明动作简单,是否产生惊喜还需实际观看与试玩判断。
|
||||
- 检查代表性的替代点击顺序与旋转探索,确认主爽点不会只藏在一条不自然的参考解中。报告注明覆盖范围,抽检不能宣称穷尽所有玩家操作。
|
||||
- 检查阻挡是否可解释,必要时改布局或加强接触反馈。当前有格外擦碰不等于必然合理,也不等于应直接删去所有相关空间结构。
|
||||
|
||||
### 区分旧门槛与新目标
|
||||
|
||||
v0.3 的 65% 弯轨比例、全六朝向独立无闭环及每段至多一次旋转,不直接作为新版统一设计前提。它们可能排除值得保留的长绕行与换路关系,必须结合样关逐项决定是否沿用、调整或限定适用范围。
|
||||
|
||||
闭环与多次旋转不作为默认难点;若候选使用,须说明玩家如何辨认当前走不通、如何得到换路线索,以及操作后获得什么回报。轻巧反差关应保持短操作即可兑现,不能借此引入反复空转。首轮样关优先证明核心爽点,无须主动加入这些复杂情况。
|
||||
|
||||
### 试玩关注点
|
||||
|
||||
观察玩家是否愿意跟完长路、能否理解放行变化,以及是否出现“原来这么简单”的反应。分别记录主动观察、行进动画、失败试路和离开游戏的时间,不把全部动画时长当等待,也不把全部失败点击当挫败。
|
||||
|
||||
可询问:“哪一枚最想看它走完?”“哪一枚比你想的容易出去?”“哪一步让你觉得后面都通了?”结合行为和回答调整关卡,不用参考解、难度分或时长估计代替体验结论。
|
||||
|
||||
## 8. 实施顺序
|
||||
|
||||
先制作并回放三类样关:直接可享受的长路巡游、一次旋转放行的轻巧反差、短路清挡后释放长绕行。确认单项体验成立后,再组合成有开局、中段变化和收尾的短关卡序列。
|
||||
|
||||
随后根据样关修订生成器参数与筛选条件,同步测试、路径报告和制作卡,再扩大关卡量。以当前清单生成的主线仍遵循其既有生成流程;新增手作样关应单独保存可重复的布局与验证结果,不直接修改现有派生关卡文件。
|
||||
|
||||
本轮不预设量产总关数、广告配额或精确难度峰值。下一步首先验证:**玩家能否持续享受弯绕离场,并通过轻巧操作获得超出第一眼预期的释放感。**
|
||||
@@ -1,204 +0,0 @@
|
||||
# HEX TRAILS 关卡设计调研报告
|
||||
|
||||
2026-09-12 · 范围:两篇指定论文精读、相关研究、箭头消除及相邻游戏、1000 关生产建议。
|
||||
|
||||
**研究后的建议是:建立“设计意图与路线骨架 → 可验证的关卡候选 → 多样体验库 → 按熟练度编排 → 试玩修正”的生产体系。** 第一篇论文提供设计意图与空间共同生成的方法,PCG-QD 提供多样候选库的方法;《一箭又一箭》的开发者分享补充了大量关卡生成、分档、重排和反馈的实践。三者都没有给出可以直接照抄的千关难度曲线。
|
||||
|
||||
对本项目,长路巡游、轻巧反差、清挡换路和整盘释放仍是内容质量的核心。研究支持把它们变成生成约束与回放证据。具体出现频率、长度门槛、困难关比例,需要由我们的样关和玩家验证决定。
|
||||
|
||||
## 1. 本次研究完成了什么
|
||||
|
||||
| 工作 | 完成范围 | 独立笔记 |
|
||||
| --- | --- | --- |
|
||||
| Mission 与 space 论文 | 8 页全文,图 1–3、表 1;案例流程、结论与限制 | [精读条目 P01](level-design-knowledge/01-mission-space.md) |
|
||||
| PCG-QD 论文 | 8 页全文,图 1–5、表 I;算法、应用、评价与开放问题 | [精读条目 P02](level-design-knowledge/02-pcgqd.md) |
|
||||
| 序列与难度补充研究 | Refraction 自动编排研究;Lily’s Garden 真人与代理数据难度建模 | [条目 P03–P04](level-design-knowledge/03-progression-and-difficulty.md) |
|
||||
| 海外竞品 | Arrow Jam 同名消歧;Arrows、Arrow Out、Tap Away、Traffic Escape、Unpuzzle;一份 Grand Games 录像定点观察与两款商店截图观察 | [海外调研](level-design-knowledge/04-international-comparators.md) |
|
||||
| 中文竞品 | 一箭又一箭的版本与主体核对、开发者分享;箭了又箭、箭了个箭的差异与证据缺口 | [中文调研](level-design-knowledge/05-chinese-comparators.md) |
|
||||
| 可复用知识 | 问题索引、设计卡、关卡记录模板、来源与检索台账 | [知识库入口](level-design-knowledge/README.md)、[研究台账](../exa-results/level-design-2026-09-12/README.md) |
|
||||
|
||||
搜索与网页阅读使用 Exa;指定论文还下载原始 PDF 核读,关键图表经过渲染检查。商店介绍属于产品方宣称,录像只说明抽查片段,开发者演讲的多个转录属于同一个经验来源。本次没有安装实玩这些移动游戏,没有审计任何竞品全部 1000 关,也没有获得其内部生成代码或原始 A/B 数据。
|
||||
|
||||
## 2. 两篇论文应该怎样进入我们的制作流程
|
||||
|
||||
### 第一篇:把“玩家经历”做成可编辑的生成对象
|
||||
|
||||
Karavolos 等人的两项案例分别采用“任务图先生成、再落空间”和“空间草图与任务顺序共同输入”。设计者在中间阶段编辑、检查、重跑模块,而非仅反复调整随机参数。原文也承认模板制作、歧义修正和模块测试仍需要工作,精确保留重生成结果中的指定局部尚待完善。[原文](https://livegamedesign.github.io/assets/FDG2015_Karavolos.pdf)
|
||||
|
||||
在我们这里,mission 可以写成“先清外侧挡子,再转一次盘,最后放出朝内的长路棋子”。space 是这个关系实际落在哪个花瓣、环带、交叉和出口。花瓣关可先锁住路线骨架,同时求兼容的放行关系;无需把所有关卡硬塞进同一种生成顺序。
|
||||
|
||||
需要新增的中间表示是**带状态条件的路线与释放关系**。例如“在底盘朝向 r、剩余棋子集合 S 下,移走 A 之后 B 可以沿路径 p 离场”。只记录 A 挡 B 的静态图,会漏掉旋转改变路线的情况。
|
||||
|
||||
### 第二篇:保存不同类型中各自优秀的候选
|
||||
|
||||
Gravina 等人的 PCG-QD 论文是综述与研究方向论述。其核心是让质量和行为多样性共同参与搜索;MAP-Elites 是其中一种方法,通过特征分区保存各类优秀个体。它提供候选库的思路,不负责决定玩家第 1 关到第 1000 关的顺序。[作者全文](https://antoniosliapis.com/articles/pcgqd.php)
|
||||
|
||||
对本项目,直接长路、清挡后巡游、一转反差、多阶段释放应该有各自的优秀候选。不能让所有关卡在“越长、越绕、旋转越多”这一个标准下竞争。先按主要放行方式分库,再用少量坐标浏览,形状与其他属性作为标签,避免过早建立巨大而空洞的多维网格。
|
||||
|
||||
第一版可以先实现分类、评审与检索;等特征有效,再决定是否加入从档案选择父代、变异、局部竞争的完整搜索。普通分组筛选不应冒称已实现 MAP-Elites。
|
||||
|
||||
### 两者结合后仍缺少的环节
|
||||
|
||||
可解性、核心回报是否出现、真人是否喜欢、连续十关是否重复,是四个不同判断。两篇论文都不能替我们验证后两项。补充的 Refraction 研究展示了基于解法特征的编排实验,但也暴露概念耗尽后连续选相似关的问题;Lily’s Garden 研究则说明结构、代理和玩家数据需要结合,且预测仍有误差。[Refraction 研究](https://www.ericbutler.net/assets/papers/chi2015_progression.pdf)、[难度建模研究](https://arxiv.org/html/2401.17436)
|
||||
|
||||
## 3. 相似游戏提供了哪些具体经验
|
||||
|
||||
### 先解决名称混淆
|
||||
|
||||
Arrow Jam 不是唯一产品:本轮发现 PoseidonJoy、Grand Games、CyberGame 等不同版本,还有 GAMEE 的 Arrows Jam、TidalAurum 的 Arrow Jam Go。Grand Games 的版本有倒计时;Lessmore 的 Arrows 官方明确无计时。身份、规则和压力来源必须分别建档。[Grand Games 商店](https://apps.apple.com/us/app/arrow-jam-tap-puzzle/id6762192889)、[Lessmore 商店](https://play.google.com/store/apps/details?id=com.ecffri.arrows&hl=en)
|
||||
|
||||
《一箭又一箭》也区分微信小程序与 Google Play App:腾讯平台条目列海南掌趣,开发者大会分享者是广州畅想互动何毅坤,Google Play 同名 App 的开发者信息对应畅想互动。本次没有擅自解释这些主体间的业务关系,也未假定两个平台同步更新。[腾讯条目](https://sj.qq.com/appdetail/wx69949b45b793b612)、[Google Play 条目](https://play.google.com/store/apps/details?hl=zh_HK&id=com.cxgame.yjyyjgoo)
|
||||
|
||||
### 核心对照
|
||||
|
||||
| 对象 | 可靠资料中的机制/观察 | 最值得迁移到本项目的设计问题 |
|
||||
| --- | --- | --- |
|
||||
| 一箭又一箭 | 开发者自述用 AI 参与生成、评分、编辑、排序;随熟练提高增加后段困难关频率,从三档扩到五档并做 A/B。[演讲实录](https://www.youxituoluo.com/534534.html) | 内容生成、难度标定和关号编排分开;用问卷解释为什么觉得无聊 |
|
||||
| Arrow Jam / Grand Games | 官方列倒计时、连接箭头、转角和管道;录像可见小局起步、遮挡幕布、围框与 Super Hard 标签。[商店](https://apps.apple.com/us/app/arrow-jam-tap-puzzle/id6762192889)、[录像](https://www.youtube.com/watch?v=6tObwJPw-JA) | 新机关、空间结构、时间压力分别分析,不能把一个标签当真实难度 |
|
||||
| Arrows / Lessmore | 官方强调无计时、避免碰撞与提示;商店截图可见密集折线构成整体轮廓。[商店](https://play.google.com/store/apps/details?id=com.ecffri.arrows&hl=en) | 有辨识度的整体形态与逐步清空;验证密集画面是否仍可跟线 |
|
||||
| Arrow Out | 商店列形状、缩放和辅助工具;二手体验报道讨论颜色分组、星级和章节。商店部分规则文案与报道有差异,未合并成已确认规则。[商店](https://apps.apple.com/us/app/arrow-out/id6754243057?l=zh-Hans-CN)、[报道](https://www.huxiu.com/article/4860736.html) | 把局部视觉分组作为可读性实验;章节奖励与谜题结构分开评价 |
|
||||
| Tap Away / Popcore | 官方说明单向移出方块、旋转立体形状观察角度,逐步改变规模和外形。[商店](https://play.google.com/store/apps/details?id=com.jctswbglsm.SwipeAway&hl=en) | 从拥挤到解开的层次感;其观察视角旋转与我们的底盘换轨作用不同 |
|
||||
| Traffic Escape / FOMO | 官方说明车顶箭头指示路线,按顺序移出、避免车辆碰撞。[商店](https://play.google.com/store/apps/details?id=com.bonnie.trafficescape&hl=en) | 看得懂“谁挡了谁”以及移除后新机会;并行调度细节本轮未实测 |
|
||||
| Unpuzzle / KekGames | 创作者发布页描述逐块拆解,平台说明被挡住时不能拉出、可以有多个解法。[原发布页](https://www.kongregate.com/en/games/kekgames/unpuzzle)、[平台规则](https://poki.com/en/g/unpuzzle) | 用拆解顺序与机制组合提供内容;明确可解、多解与无惩罚的区别 |
|
||||
|
||||
这些产品的“折线箭头有多长”“盘面轮廓是什么”,和本游戏“一枚棋子沿共享轨道行驶多远”不是同一个度量。只能迁移体验问题和组织方法,不能直接照搬它们的箭头数量或线条长度阈值。
|
||||
|
||||
### 有直接观察证据的片段
|
||||
|
||||
本轮定点查看了 IOSTouchplayHD 于 2026-06-02 发布的 Grand Games 录像:
|
||||
|
||||
- [00:20–00:39](https://www.youtube.com/watch?v=6tObwJPw-JA&t=20s):起步阶段的多个小局,适合研究反馈与教学密度。
|
||||
- [01:00](https://www.youtube.com/watch?v=6tObwJPw-JA&t=60s):画面可见 Level 6。
|
||||
- [04:00](https://www.youtube.com/watch?v=6tObwJPw-JA&t=240s):幕布及数字 7;只有画面事实,不能据此编造幕布完整触发规则。
|
||||
- [07:00](https://www.youtube.com/watch?v=6tObwJPw-JA&t=420s):围框箭头与内部簇,提供外层/内层结构对照。
|
||||
- [10:00](https://www.youtube.com/watch?v=6tObwJPw-JA&t=600s):可见 Super Hard 标签;没有验证其实际难度或对应的全局关号位置。
|
||||
|
||||
这是约 12 分钟录像中的抽查,不是连续通关测试。无法从视频准确读出点击是否被缓存、同时在途上限或丢输入情况;因此本轮没有用它宣称竞品已实现何种并行逻辑。
|
||||
|
||||
## 4. 《一箭又一箭》的量产经验,哪些能用
|
||||
|
||||
2026-05-27 的开发者分享,是本轮最贴近千关目标的实践材料。作者称早期简单—中等—困难循环在熟练用户中逐渐失去吸引力,后来增加后段困难关频率,扩充分档、重排大量关卡,并用 A/B 和问卷迭代。公开稿没有给出评分公式、实验分组规模或最优曲线参数。[全文实录](https://www.youxituoluo.com/534534.html)
|
||||
|
||||
由此可支持的项目决策是:
|
||||
|
||||
1. **关卡 ID 与关号分离。** 重新评级后可以调整顺序,同时保留来源、结构和历史表现。
|
||||
2. **结构难度和熟练玩家的体感分离。** 后期是否增加组合与挑战,要看玩家反馈和行为;固定结构难度不保证体感稳定。
|
||||
3. **保留核心,克制增加规则。** 演讲中的巨大箭头、彩色箭头、连击等是不同的新鲜感入口。我们的花瓣、螺旋、编织可以在原规则内提供变化。
|
||||
4. **数据和解释一起采集。** “后期无聊”“看不清”“连点没反应”“只剩重复清理”应触发不同改动。
|
||||
|
||||
演讲中的低频特殊机制、动态计时和商业反馈需要放回其产品目标理解。长路与反差是我们的核心内容,不应因竞品特殊机关低频就降为偶尔奖励;倒计时也不能未经验证进入当前强调巡游观看、免费试路的主线。
|
||||
|
||||
## 5. 长路、反差、花瓣应分别怎样制作
|
||||
|
||||
以下为本项目方案,尚未通过本轮新试玩验证。
|
||||
|
||||
| 内容 | 生成时必须表达 | 验收时看什么 | 在序列中的角色 |
|
||||
| --- | --- | --- | --- |
|
||||
| 长路巡游 | 关键棋子的真实成功路线、转弯与空间展开,明确何时放行 | 实际行进是否成立、是否愿意跟完、多策略是否容易遇到 | 教学、舒缓、中段兑现和收尾都可使用 |
|
||||
| 轻巧反差 | 第一眼预期、目标棋子、简短放行条件 | 模型证明动作轻巧;玩家证据证明预期落差 | 用少量动作带来清楚回报,可与短路或长路结合 |
|
||||
| 花瓣等形状路线 | 可辨认的整体形态与实际可行驶的关键路段 | 图案是否可读、关键路线是否被真实使用、交叉是否清楚 | 成为常见路线家族;高完成度作品可承担章节记忆点 |
|
||||
| 逐层释放 | 带状态条件的阻挡与换路关系、阶段奖励位置 | 哪一步打开哪些机会,是否只靠作者特定解才看得见 | 构成关内进展,并提供组合变化 |
|
||||
|
||||
花瓣需要分别记录三种证据:静态轮廓、实际路线、解开的阶段。轮廓相同可以换清挡/旋转关系;关系相同可以换路线形态。但仅换颜色或整体对称变换,不能自动计成新的体验原型。
|
||||
|
||||
一个花瓣原型至少可以提出三种不同制作意图:开局直接巡游、外侧让路后释放主瓣、一转接通内向长路。是否值得分别进入主线,要看实际释放顺序、路线和玩家感知是否有差别。
|
||||
|
||||
“反差”尤其不能只靠数值打标签。PCG-QD 中的算法 surprise 指结果偏离历史行为预测,与人看到内向箭头后说“原来转一下就行”含义不同。我们需要分别验证操作简洁与玩家预期,而不是套一个 surprise 算法名称。[P02 的概念辨析](level-design-knowledge/02-pcgqd.md)
|
||||
|
||||
## 6. 1000 关生产体系的具体建议
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[体验意图与已教规则] --> C[带状态条件的路线和释放关系]
|
||||
B[花瓣等空间草图与固定路段] --> C
|
||||
C --> D[生成棋子与轨道候选]
|
||||
D --> E{正式规则与回放验证}
|
||||
E -->|冲突或未确定| C
|
||||
E -->|通过| F[分类候选库与类内评审]
|
||||
F --> G[去重和按熟练度编排]
|
||||
G --> H[连续试玩与输入体验检查]
|
||||
H -->|排序不合适| G
|
||||
H -->|奖励或可读性有问题| C
|
||||
H -->|通过| I[版本化发布与持续反馈]
|
||||
I --> H
|
||||
```
|
||||
|
||||
### 先固定真实操作逻辑
|
||||
|
||||
用户已经指出快速连点与并行体验的重要性。生产工具要使用最终约定的输入与运动规则:接受点击的时机、占用何时变化、旋转是否可与运动交叠、队列或并行动画如何表现。记录为 `rulesVersion`,让求解、回放和实际操作对应同一版本。
|
||||
|
||||
如果未来真实并行改变了沿路动态占用,静态顺序求解的证明范围也要重审。即便只是动画串行,快速点击等待仍会影响长路的体感;这类时间应与主动观察、主动观看分别计量。
|
||||
|
||||
### 三个可以分别改动的产物
|
||||
|
||||
| 产物 | 内容 | 何时修改 |
|
||||
| --- | --- | --- |
|
||||
| 原型/骨架库 | 路线语汇、释放关系、固定约束、变化范围 | 需要新体验或发现某类内容无法稳定生成 |
|
||||
| 关卡候选库 | 固定布局、完整回放、体验标签、评审、近似家族 | 生成新布局或修改单关 |
|
||||
| 主线编排表 | 关卡 ID 顺序、目标熟练度、相邻差异、版本 | 难度重新校准、连续体验重复或节奏失衡 |
|
||||
|
||||
评价按规则正确性、体验类型、本类质量和难度证据分别保存。先用已有样关标定可解释的档位,不让现有总分替代全部判断。每次修改筛选规则都保留淘汰原因,检查是否系统性删掉了轻松而漂亮的内容。
|
||||
|
||||
### 难度曲线控制的对象
|
||||
|
||||
推荐控制的是某类玩家连续游玩时的体感,而非强制结构分数单调变化。前期逐步引入箭头起步、沿轨转向、交叉不换轨、清挡和转盘,再增加熟悉关系的组合。后期保持舒缓与挑战的变化,并按熟练度反馈调整挑战出现率。
|
||||
|
||||
长路观看量、推理负担、视觉负担、操作量应该画成不同序列。难关后的舒缓关可以继续有丰富巡游;章节观赏高点也可以是轻松的。一段 **仅用于说明的八关节奏** 可以是:
|
||||
|
||||
| 位置 | 主要内容 | 目标推理负担 | 回报安排 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | 熟悉入口,直接长路 | 低 | 立即巡游 |
|
||||
| 2 | 清一枚放出目标 | 低至中 | 清楚因果 |
|
||||
| 3 | 已教旋转带来内向出口 | 中 | 轻巧反差 |
|
||||
| 4 | 花瓣形态,宽松放行 | 低 | 丰富观看 |
|
||||
| 5 | 两个熟悉关系组合 | 中 | 分段兑现 |
|
||||
| 6 | 跨区清挡与换路 | 较高 | 完成后充分放行 |
|
||||
| 7 | 开放出口的长绕行 | 低 | 熟练感与舒缓 |
|
||||
| 8 | 另一种形态的整盘释放 | 中 | 阶段收束 |
|
||||
|
||||
这不是发现了竞品的八关周期,也不是要求每段第六关最难。不同段落需要错开长度、峰值和内容顺序,具体节奏应比较后选择。
|
||||
|
||||
### 扩到 1000 的验收顺序
|
||||
|
||||
建议沿用“基准样关 → 首批 100 → 300 → 600 → 1000”的分批思路。基准样关按体验和负担覆盖,不直接当玩家前几十关。每批发布前分别检查:
|
||||
|
||||
1. **全部可验证。** 每关有正式规则下可回放的清盘解;超时或未确定的候选不混入已验证集合。
|
||||
2. **承诺内容成立。** 主长路、反差、形状路线和阶段释放有对应证据;关键效果不是只存在于未使用装饰线。
|
||||
3. **有可感知变化。** 同骨架、同释放节奏和相邻近似关可被查出;不以种子不同代替新内容。
|
||||
4. **连续体验成立。** 按序游玩覆盖开局、中段和收尾,排查重复清理、视觉拥挤、输入等待及熟练后无聊。
|
||||
5. **来源可追踪。** 规则、生成器、模板、评价、编排和试玩记录均有版本。
|
||||
|
||||
一批未通过时,先判断问题在骨架、布子、显示/输入还是排序,再修对应环节。不要靠扩大候选数掩盖评价目标不正确的问题。
|
||||
|
||||
## 7. 对之前 1000 关方案的修正
|
||||
|
||||
| 原有建议 | 研究后的处理 |
|
||||
| --- | --- |
|
||||
| 20 章 × 50 关、固定 D1–D5 数量 | 保留为制作预算假设;没有论文或竞品公开证据证明这些精确配额 |
|
||||
| 后半程平均难度平台 | 改为追求目标玩家的体感稳定;结构要求和困难关频率可随熟练变化 |
|
||||
| 长路、反差、花形的具体覆盖比例 | 不由学术引用背书;先验证识别、观看意愿与连续疲劳,再定频率 |
|
||||
| 先体验骨架再几何 | 保留,同时允许花瓣空间草图与体验关系共同输入 |
|
||||
| 使用质量多样性管理候选 | 支持方向;先检验标签与类内评审是否有效,再决定算法复杂度 |
|
||||
| 原有多维评审与节奏编排 | 保留相邻差异、奖励曝光和熟练度校准,并补充解法特征编排研究及可比较实验 |
|
||||
| 自动化提升制作效率 | 计入模板、评价器、工具和人工评审成本,实测总工时与验收产量 |
|
||||
|
||||
这些修正针对论据和实施方式,不代表本轮已经生成或验收了 1000 关。原始讨论稿继续保留:[1000 关制作方案](1000-level-production-plan.md)。
|
||||
|
||||
## 8. 最值得先做的三组验证
|
||||
|
||||
| 验证 | 控制什么 | 观察什么 | 用结果决定什么 |
|
||||
| --- | --- | --- | --- |
|
||||
| 同一释放结构,换花瓣/环绕等空间;同一形态,换释放结构 | 尽量保持棋子数、输入规则与主要操作负担可比 | 玩家是否感到不同、愿意看哪条路、能否说明关键变化 | 哪些维度真能支持内容扩容 |
|
||||
| 相同候选预算:现有单分筛选与分类后类内评审 | 使用相同规则、候选来源与评审条件 | 合格数量、可感知差异、重复率、人工筛选时间 | 候选档案是否值得进一步实现 QD 搜索 |
|
||||
| 同一批关卡,不同编排序列 | 规则、动画、内容和外部奖励保持一致;按熟练度分组 | 连续游玩、主动观察、奖励识别、疲劳及不继续的解释 | 难度波动、舒缓位置与后期挑战比例 |
|
||||
|
||||
先用小规模观察找机制问题,不能将探索性样本的通关率当精确行业指标。规模化 A/B 前再定义主要指标、样本与停止规则;同时保存反例和定性反馈。实际体验评审应覆盖慢点观看与快速连续点出的玩法,避免只优化其中一种。
|
||||
|
||||
## 9. 研究还没有回答的事情
|
||||
|
||||
- 各竞品真实的千关布局、重复率与难度分布;商店关数声明尚未逐关核对。
|
||||
- Arrow Jam 与《一箭又一箭》的实际点击缓存、并行动画、状态提交与碰撞实现。
|
||||
- 开发者自述中的 AI 技术类型、原始评级公式、A/B 最优参数与效果量。
|
||||
- 本项目玩家对长路长度、花瓣密度、反差和难度波动的偏好分布。
|
||||
|
||||
这些缺口已进入知识库的验证问题。现阶段足够明确的方向是:用有意图的路线和释放结构生成,用分类候选库维护变化,用真人连续体验校准顺序,逐批扩大已验收的内容。
|
||||
+21
-83
@@ -19,25 +19,21 @@
|
||||
"id": "my-level",
|
||||
"name": "转个方向",
|
||||
"rotationEnabled": true,
|
||||
"moveLimit": 1,
|
||||
"moveLimit": 3,
|
||||
"cells": [{ "q": 0, "r": 0, "tracks": [3, 4, 5, 0, 1, 2] }],
|
||||
"tiles": [{ "id": "t0", "q": 0, "r": 0, "dir": 1, "color": 0 }]
|
||||
}
|
||||
```
|
||||
|
||||
`tracks[i]` 为进入 i 端口后使用的出口,必须满足 `tracks[tracks[i]]===i` 且不能与自己相连。六端口共有 15 种完整配对。`color` 为 0–11;旧文件的 0–3 仍有效。编辑器使用完整 12 色库;主线渲染按初始棋子顺序取主题色组,保持单关 3–4 色,颜色不参与规则。`rotationEnabled` 可选,默认开启;旧版 JSON 仍可导入,但会按新的碰撞规则重新验证。
|
||||
`tracks[i]` 为进入 i 端口后使用的出口,必须满足 `tracks[tracks[i]]===i` 且不能与自己相连。六端口共有 15 种完整配对。`color` 为 0–3。`rotationEnabled` 可选,默认开启;旧版 JSON 仍可导入,但会按新的碰撞规则重新验证。
|
||||
|
||||
导入限制:1–127 格、坐标半径不超过 6、`moveLimit` 为 1–999。该字段现在表示成功消除预算,只有移除棋子扣 1;旋转和失败试路不扣预算。主线将其设为初始棋子数 `N`,只表达剩余工作量。自定义关卡仍可导入不同预算,但预算不足 `N` 时无法完成全部消除。
|
||||
|
||||
编辑器提供半径 2/3/4(19/37/61 格)的板型,模型支持半径 4、61 格底板。底板不具备六重旋转对称性时,禁用整体旋转,避免棋子旋转后悬空。
|
||||
导入限制:1–61 格、坐标半径不超过 4、步数 1–999。编辑器提供半径 2/3 的常用板型。底板不具备六重旋转对称性时,禁用整体旋转,避免棋子旋转后悬空。
|
||||
|
||||
## 旋转是真实的规则变化
|
||||
|
||||
顺时针一步将所有底板格子变为 `(q,r) → (-r,q+r)`,同时将轨道端口和对应出口都加 1(模 6)。上层棋子的 `(q,r,dir)` 均不改变。六次旋转恢复原状。
|
||||
|
||||
每次旋转免费;只有成功离场才扣 1 次消除预算。阻挡和闭环试路均不扣预算,也不改变棋子的模型位置。旋转次数与失败尝试次数仍可单独统计。撤销保存并恢复底板、棋子、预算、朝向和这些计数。重开读取原始关卡,不能从已旋转的中间状态重开。
|
||||
|
||||
可旋转关卡在当前朝向没有直接出口时,不会仅因此判负。主线预算为 `N`,玩家可以反复试路和转盘,不会因为这些尝试耗尽预算。
|
||||
v2 旋转不扣步,点击棋子(含碰撞)扣 1 步。撤销保存并恢复底板、棋子、步数、朝向和旋转计数。重开读取原始关卡,不能从已旋转的中间状态重开。
|
||||
|
||||
## 连续碰撞
|
||||
|
||||
@@ -47,88 +43,30 @@
|
||||
|
||||
例如:移动棋子在 `(1,1)` 向上走,另一棋子在 `(0,0)`。路线经过的格子不含 `(0,0)`,但经过相邻两格之间时,移动棋子的侧面可能擦到它,因此仍被阻挡。这比仅检查路线格子占用更严格。
|
||||
|
||||
上述擦碰仍属于通用模型规则,工坊及任意导入数据需要正确处理。新主线另设清晰度发布门槛:沿参考解答的各决策状态检查所有剩余棋子,排除路线经过格之外的擦碰阻挡。筛选参考解答不能证明所有任意旋转、点击序列都满足同样的清晰度要求,也不代表每次任意旋转都必然产生出口。
|
||||
|
||||
判定发生在移动前,动画只展示结果:成功沿线离场;失败走到接触位置再退回。不允许多个棋子同时运动,避免时序歧义。生成器、求解器、提示与工坊都调用同一个 `trace()`。
|
||||
判定发生在移动前,动画只展示结果:成功沿线离场;失败走到接触位置再退回。成功点击立即更新逻辑棋盘,各棋子的离场动画独立并行播放;后续点击按最新棋盘判断,离场中的棋子不再占用原格。碰撞回退期间暂存后续点击。转盘和撤销等待全部动画结束。生成器、求解器、提示与工坊都调用同一个 `trace()`。
|
||||
|
||||
## 旋转求解与生成
|
||||
|
||||
移走可行棋子只会减少障碍,不改变轨道,因此在任意朝向下先移除所有安全棋子不会损害后续可解性。求解器对“朝向+剩余棋子集合”做 BFS,到达一个朝向后先消除所有可离场棋子。搜索仍将每次旋转计为一条代价为 1 的边,用于寻找最少旋转方案;这是搜索目标,不是玩家的预算扣费。
|
||||
移走可行棋子只会减少障碍,不改变轨道,因此在任意朝向下先移除所有安全棋子不会损害后续可解性。求解器对“朝向+剩余棋子集合”做 BFS,每次转盘代价为 1,到达一个朝向后先消除所有可离场棋子。
|
||||
|
||||
求解结果区分两种数量:
|
||||
v2 最短扣费步数 = 初始棋子数;最少操作次数 = 初始棋子数 + 最少旋转数。BFS 返回混合 `tap` / `rotate` 动作序列。最大扩展状态数为 20,000;若触及上限,则返回 `exhausted` 表示尚未确定,不能宣称无解。
|
||||
|
||||
关卡生成先在碰撞规则下逆向放入可离场棋子,再旋转初始底盘,筛选必须旋转才能完成的布局,最后重新求解验证。主线按评分非递减排列,共 24 关,必要旋转 1–3 次。
|
||||
|
||||
## 数字化难度(0–100)
|
||||
|
||||
设 N=棋子数、T=忽略占用的平均转弯数、W=解答中的消除层数、F=初始无碰撞可离场数量、R=最少旋转数、K=N=最短扣费步数、M=上限:
|
||||
|
||||
```text
|
||||
minimumMoves = N // 最少成功消除成本
|
||||
minimumActions = N + R // 最少交互数:消除 + 旋转
|
||||
```
|
||||
|
||||
其中 `R` 是最少旋转数。BFS 返回混合 `tap` / `rotate` 动作序列;`reachable` 表示可以清空棋盘,`solvable` 还要求预算不少于 `N`。最大扩展状态数为 20,000;若触及上限,则返回 `exhausted` 表示尚未确定,不能宣称无解或已验证可解。
|
||||
|
||||
基础生成器在碰撞规则下逆向放入可离场棋子,主线编排在候选基础上进行独立筛选与回放。主线制作规模为 48 关、8 章,每章 6 拍:进入、换路、展开、小挑战、释放、长局回报。顺序不按认知难度非递减排序,也不再要求每一关都必须旋转。
|
||||
|
||||
9 月 9 日版的全部布局由 `levels/campaign-seeds.json` 中的种子及 `options` 明确指定;`scripts/generate-levels.mjs` 据此生成关卡、共享模块和验收数据。修改种子或参数后运行 `npm run levels`,不要直接编辑派生的关卡文件。参考成功路径统计保存在 `levels/campaign-analysis.json` 的逐关 `pathUsage` 中。
|
||||
|
||||
`minBaseTurns` / `maxBaseTurns` 限制逆向放置时的基准朝向,`startRotation` 在此之后施加。发布门槛另按最终朝向的真实参考解答统计,不能把基准朝向的参数当成旋转后的路径保证。
|
||||
|
||||
大棋盘用于增加熟悉规则下的工作量:早期就可使用 37 格,后期舒缓关采用 61 格,19 格也可承载较难的局部关系。小挑战后必须有认知负担回落,长局回报不能仅靠更复杂的路线或反复空转延长时间。
|
||||
|
||||
当前清单单关最多 25 枚棋子,长局的工作量来自更多实际弯轨消除,不以直出棋子数量或空白格上的弯线充数。每关参考解答至少 65% 的成功离场棋子经过弯道,且至少 3 枚;直线只作少量调剂,主线不安排纯直出关。
|
||||
|
||||
第 1 关为 37 格、8 枚棋子,开局全部可离场,参考解答每枚恰好经过 1 处弯道,无需旋转或强制先后顺序;这不意味着转到任意朝向后仍全部可出。前 7 关通过 `lesson` 字段依次明确:箭头起步与弯轨转向、旋转换路而棋子箭头不动、交叉不换轨、阻挡先后、一两弯的舒缓消除、大盘连续解路径、完整路线观察。对应制作说明见 [前期学习与章节节奏](gameplay-direction.md)。
|
||||
|
||||
发布要求包括:每枚棋子在 6 个朝向下忽略占用的独立路线均无闭环;参考解答全程排除路线格外擦碰阻挡;换路和小挑战关在参考解答中最多连续旋转 1 次就打开下一次消除进展。它们是候选发布门槛,不能用来代替实际生成结果或玩家验收。完整制作方向见 [玩法方向](gameplay-direction.md),生成后逐关核对 [主线审阅报告](campaign-review.md)。
|
||||
|
||||
## 实际参考路径使用量
|
||||
|
||||
`solutionPathUsage(level, actions)` 按参考动作回放旋转和成功移除,在每次移除时调用同一 `trace()` 读取实际离场路径。它忽略没有成功离场的尝试,不统计棋盘上未使用的装饰曲线;正式通过验收的完整解答还必须满足 `pathUsage.removals === N`。
|
||||
|
||||
| `pathUsage` 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| `removals` | 参考解答中的成功移除数量 |
|
||||
| `curvedRemovals` / `straightRemovals` | 经过至少 1 处弯道 / 没有经过弯道的成功棋子数 |
|
||||
| `curvedRatio` | `curvedRemovals / removals`;主线要求至少 0.65 |
|
||||
| `singleBendRemovals` / `multiBendRemovals` | 实际经过恰好 1 处 / 多于 1 处弯道的成功棋子数 |
|
||||
| `totalBends` / `maxBends` | 全部实际成功路径的总转弯数 / 单枚最大转弯数 |
|
||||
| `maxConsecutiveStraight` | 参考解答中连续直出棋子的最长段落 |
|
||||
| `paths` | 逐棋子的 `id`、`bends` 和路线步骤数 `cells` |
|
||||
|
||||
弯轨门槛同时检查 `curvedRatio >= 0.65` 与 `curvedRemovals >= 3`。它约束参考解答中真正发生的消除,不证明所有其他操作顺序具有相同比例。初始独立路线的平均转弯数也不能替代这个指标,尤其是必须先旋转才有出口的关卡。
|
||||
|
||||
## 认知难度(0–100)
|
||||
|
||||
`analyze()` 的分数只估计路线阅读与依赖判断,不直接给棋盘面积、棋子数或试错预算加分。设:
|
||||
|
||||
- `N`:初始棋子数。
|
||||
- `T`、`Tmax`:初始朝向忽略占用时,各棋子独立路线的平均、最大转弯数。
|
||||
- `W`:参考解答中的消除层数;`D = max(0, W-1)/(N-1)`,当 `N≤1` 时为 0。
|
||||
- `F`:初始无碰撞可离场棋子数。
|
||||
- `S`:初始状态中因路线经过格之外的擦碰而被挡的棋子数。
|
||||
- `R`:求解器得到的最少旋转数。
|
||||
|
||||
```text
|
||||
弯道追踪 = min(1, T/4) × 22
|
||||
最长路线 = min(1, Tmax/8) × 12
|
||||
依赖比例 = min(1, D) × 18
|
||||
初始阻塞 = (1-F/N) × 28
|
||||
格外擦碰 = S/N × 12
|
||||
必要旋转 = min(1, R/3) × 8
|
||||
规模 = min(1, N/37) × 15
|
||||
弯道追踪 = min(1, T/5) × 20
|
||||
解锁层数 = min(1, max(0,W-1)/9) × 20
|
||||
路线阻塞 = (1-F/N) × 15
|
||||
必要旋转 = min(1, R/4) × 20
|
||||
步数压力 = clamp(1-(M-K)/max(1,0.4N), 0, 1) × 10
|
||||
总分 = 四舍五入各项未取整值之和
|
||||
```
|
||||
|
||||
`N=0` 时比例项按 0 处理,空关卡为 0 分且不能判为有效可解关卡。不可解、搜索未确定和消除预算不足分别处理。分项显示时若单独取整,显示值之和可能与总分略有差异。
|
||||
空关卡为 0 分且不能判为有效可解关卡。不可解、搜索未确定和步数不足分别展示。分项单独取整,显示值之和可能与总分略有差异。
|
||||
|
||||
0–29 轻松、30–49 进阶、50–69 烧脑、70–100 挑战。分数是制作与比较用的结构估计,没有经过玩家通关率标定,不应直接决定主线排序。相同分数的两关可能拥有不同棋盘规模与工作量。
|
||||
|
||||
## 工作量与内部时长估计
|
||||
|
||||
`analyze().workload` 单独提供 `removals`(棋子数)、`rotations`(最少旋转数)、`minimumActions`(最少交互数)、`routeCells`(初始朝向独立路线的格步骤总数,可能包含重复访问)及 `estimatedSeconds`。
|
||||
|
||||
```text
|
||||
estimatedSeconds = round(3 × N + 0.75 × 总转弯数 + 4 × R)
|
||||
```
|
||||
|
||||
总转弯数是初始朝向下、忽略占用的各棋子独立路线转弯数之和。该公式仅为内部制作假设,没有真人用时数据支撑,不能称为平均通关时长或向玩家承诺的完成时间。搜索未确定或关卡不可解时,不应将其作为可发布关卡的估时。
|
||||
|
||||
此处总转弯数与 `pathUsage.totalBends` 口径不同:前者是初始独立路线,后者是逐步旋转后真正成功走过的参考路径。两者应分别保留,不将弯轨覆盖率、增加的路线内容或最多 25 枚棋子的规模直接换算成已验证的真人时长。
|
||||
|
||||
后续测试应观察主动停顿、成功消除间隔、旋转到下一次成功的间隔、失败试路原因、最后一枚棋子阶段,以及提示、撤销和重开的发生位置;明确区分观察停顿、动画占用和离开游戏的时间,再校准认知评分与工作量估计。
|
||||
0–29 轻松、30–49 进阶、50–69 烧脑、70–100 挑战。目前 24 关范围为 25–75。它是用于关卡排序的结构估计,没有经过玩家通关率标定;后续可用首次成功率、碰撞率、提示率、旋转次数、撤销率与耗时校准。
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>关卡制作流程复盘</title>
|
||||
<style>
|
||||
:root{
|
||||
--ground:#EFF1F3; --surface:#FFF; --panel:#F6F8F9; --ink:#131C24; --ink2:#465766; --ink3:#6D7C89;
|
||||
--rule:#D4DAE0; --rail:#3F5E79; --good:#226D63; --bad:#AF3A26; --warn:#895B0E;
|
||||
color-scheme:light;
|
||||
}
|
||||
@media (prefers-color-scheme:dark){:root:not([data-theme=light]){
|
||||
--ground:#0E151B; --surface:#131C24; --panel:#131C24; --ink:#E3E9EE; --ink2:#ADBCC8; --ink3:#8393A1;
|
||||
--rule:#27333E; --rail:#8BAFCB; --good:#4EC6B6; --bad:#E3826B; --warn:#DFAD5D;
|
||||
color-scheme:dark;
|
||||
}}
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;background:var(--ground);color:var(--ink);
|
||||
font-family:"PingFang SC","Hiragino Sans GB",ui-sans-serif,system-ui,sans-serif;line-height:1.7}
|
||||
.wrap{max-width:920px;margin:0 auto;padding:44px 22px 96px}
|
||||
h1{font-size:31px;margin:0 0 12px;letter-spacing:-.02em}
|
||||
.lede{color:var(--ink2);font-size:15.5px;max-width:68ch;margin:0 0 6px}
|
||||
.meta{font-size:12.5px;color:var(--ink3);font-family:ui-monospace,monospace;margin:0 0 34px}
|
||||
h2{font-size:20px;margin:44px 0 12px;padding-bottom:7px;border-bottom:1px solid var(--rule)}
|
||||
p{max-width:70ch}
|
||||
.tiles{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));margin:18px 0 8px}
|
||||
.tile{background:var(--surface);border:1px solid var(--rule);border-radius:10px;padding:13px 15px}
|
||||
.tile .k{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink3);font-weight:600}
|
||||
.tile .v{font-size:25px;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;margin:3px 0 1px}
|
||||
.tile .n{font-size:11.5px;color:var(--ink3)}
|
||||
.tile.ok .v{color:var(--good)} .tile.miss .v{color:var(--bad)}
|
||||
.rule{background:var(--surface);border:1px solid var(--rule);border-radius:12px;padding:17px 20px;margin:14px 0}
|
||||
.rule h3{margin:0 0 9px;font-size:16.5px;display:flex;gap:10px;align-items:baseline}
|
||||
.rule h3 .no{font-family:ui-monospace,monospace;color:var(--rail);font-weight:700}
|
||||
.rule dl{margin:0;display:grid;grid-template-columns:auto 1fr;gap:5px 13px;font-size:13.5px}
|
||||
.rule dt{color:var(--ink3);white-space:nowrap;font-size:11.5px;letter-spacing:.04em;padding-top:3px}
|
||||
.rule dd{margin:0;color:var(--ink2)}
|
||||
.rule dd.ev{color:var(--ink)}
|
||||
table{width:100%;border-collapse:collapse;font-size:13.5px;margin:14px 0 8px}
|
||||
th,td{text-align:left;padding:8px 10px;border-bottom:1px solid var(--rule);vertical-align:top}
|
||||
th{font-size:11px;letter-spacing:.06em;color:var(--ink3);text-transform:uppercase;font-weight:600}
|
||||
td.n{text-align:right;font-family:ui-monospace,monospace;white-space:nowrap}
|
||||
.no{color:var(--bad);font-weight:600}.yes{color:var(--good);font-weight:600}
|
||||
ol.recipe{counter-reset:s;list-style:none;padding:0;margin:14px 0}
|
||||
ol.recipe li{counter-increment:s;position:relative;padding:0 0 13px 40px;font-size:14px;color:var(--ink2);max-width:70ch}
|
||||
ol.recipe li::before{content:counter(s);position:absolute;left:0;top:0;width:25px;height:25px;border-radius:50%;
|
||||
background:var(--rail);color:#fff;font-family:ui-monospace,monospace;font-size:12.5px;font-weight:700;
|
||||
display:grid;place-items:center}
|
||||
ol.recipe b{color:var(--ink)}
|
||||
code{font-family:ui-monospace,monospace;font-size:.92em;background:var(--panel);padding:1px 5px;border-radius:4px;border:1px solid var(--rule)}
|
||||
footer{margin-top:54px;padding-top:18px;border-top:1px solid var(--rule);color:var(--ink3);font-size:12px}
|
||||
a{color:var(--rail)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<h1>关卡制作流程复盘</h1>
|
||||
<p class="lede">这一轮做 50 关的过程里,最有用的结论是一个<b>否定结论</b>:原计划的「agent 打分 → 拟合权重 → 重选关卡」这个闭环<b>合不上</b>,而且不是样本量的问题。下面是它为什么合不上,以及流程该改成什么样。</p>
|
||||
<p class="meta">交付批次 R2 · 实测轮次 R1 / R2 / R3 · 生成于 2026-09-14 17:25</p>
|
||||
|
||||
<h2>交付这一版实测到了什么</h2>
|
||||
<div class="tiles">
|
||||
<div class="tile ok"><div class="k">通关</div><div class="v">100/100</div><div class="n">无死局</div></div>
|
||||
<div class="tile ok"><div class="k">空点 / 关</div><div class="v">0.00</div><div class="n">目标 0</div></div>
|
||||
<div class="tile ok"><div class="k">盲转 / 关</div><div class="v">0.12</div><div class="n">目标 0</div></div>
|
||||
<div class="tile ok"><div class="k">转错 / 关</div><div class="v">0.12</div><div class="n">目标 0</div></div>
|
||||
<div class="tile miss"><div class="k">难度评分</div><div class="v">84/100</div><div class="n">都是 2 分 — 不区分</div></div>
|
||||
</div>
|
||||
<p>机械面干净,说明生成期的闸门是有效的:「动了很多次没结果」这类结构缺陷已经被挡在关卡集之外。<b>难度评分那一格是这两轮真正的发现</b>:机械上差着三倍的关卡,它一律给 2 分。更早的记录里这项的复测可信度是 0.93,那是个更小的样本——在这一批 99 对复测上实测是 0.46,所以它既不区分、也不像以为的那么稳。</p>
|
||||
|
||||
<h2>两轮之间改了什么,效果如何</h2>
|
||||
<p>第一轮唯一可用的读数是「整批偏易」,加上抱怨里反复出现的「转了没反应」。据此只改了两件事:给<b>连续空转</b>设闸门(最多一次转动没反应,此前有 11 关能连着两次),以及把难度曲线<b>写成旋转深度的配额</b>而不是指望它从排序里自己长出来。第三轮又只改了一件:桶内改按<b>反差</b>取。每轮一个变量,才看得出是哪个变量起的作用。</p>
|
||||
<table>
|
||||
<thead><tr><th>同一个规则机器人,三套关卡集</th><th class="n">第一版</th><th class="n">第二版</th><th class="n">第三版</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>盲转 / 关</td><td class="n ">0.24</td><td class="n yes">0.12</td><td class="n yes">0.14</td></tr>
|
||||
<tr><td>最长连续盲转</td><td class="n ">4</td><td class="n yes">1</td><td class="n yes">1</td></tr>
|
||||
<tr><td>空点 / 关</td><td class="n ">0.00</td><td class="n ">0.00</td><td class="n ">0.00</td></tr>
|
||||
<tr><td>决策 / 关(要做的事)</td><td class="n ">10.3</td><td class="n ">10.3</td><td class="n ">9.8</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>要做的事一样多,浪费掉的动作少了一半,而且第三版保住了这个成绩。这是同一个玩家的对照,所以变的是关卡不是模型的心情——一次 50 关的全量验收 1 秒跑完,这也是为什么全量验收该交给它而不是 agent。</p>
|
||||
<table>
|
||||
<thead><tr><th>grok 实测,按档(每关计一次,与它自己玩的那一版对齐)</th><th class="n" colspan="2">R1</th><th class="n" colspan="2">R2</th><th class="n" colspan="2">R3</th></tr>
|
||||
<tr><th></th><th class="n">难度</th><th class="n">无解感</th><th class="n">难度</th><th class="n">无解感</th><th class="n">难度</th><th class="n">无解感</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>前档 L1–L12</td><td class="n">2.00</td><td class="n">1.33</td><td class="n">2.00</td><td class="n">1.21</td><td class="n">2.00</td><td class="n">1.17</td></tr>
|
||||
<tr><td>中档 L13–L32</td><td class="n">2.10</td><td class="n">1.35</td><td class="n">2.05</td><td class="n">1.15</td><td class="n">2.05</td><td class="n">1.20</td></tr>
|
||||
<tr><td>后档 L33–L50</td><td class="n">2.17</td><td class="n">1.61</td><td class="n">2.39</td><td class="n">1.72</td><td class="n">2.19</td><td class="n">1.64</td></tr>
|
||||
<tr><td>后档的关卡参数</td><td class="n">3.5 转</td><td class="n">反差 21.7</td><td class="n">4.1 转</td><td class="n">反差 27.9</td><td class="n">4.0 转</td><td class="n">反差 28.5</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>第一轮三档几乎是一条平线。第二轮把后档的旋转深度从 3.5 提到 4.1 转,后档评分随之升到 2.39——<b>评分第一次表现出梯度</b>,但只在按档平均之后。</p>
|
||||
<p><b>第三轮是一个被自己的数据否掉的假设,已经回退。</b>第二轮显示打 3 分的关比打 2 分的关反差高 59%,于是第三轮改成按反差选关——只动这一个变量,后档反差从 27.9 提到 28.5,旋转深度不变。</p>
|
||||
<p>结果是后档<b>更简单了</b>:2.39 ± 0.10 对 2.19 ± 0.08,约两个标准误;平均分到 2.5 以上的关从 11 关掉到 8 关。评分复测只有 0.46,但那限制的是<b>逐关排序</b>,不妨碍组间均值——两轮各 100 与 100 局,这个差距站得住。</p>
|
||||
<p>所以交付的是第二版。反差仍然是策划点名的好玩机制,也确实和「被评得更难」相关,但<b>按它选关并不能造出更难的关</b>——相关不等于可操纵。这条写进规则 4:每个新做法都要能在数据里看到它挡掉/换来了什么,看不到就撤回。</p>
|
||||
|
||||
<h2>哪些信号复测得住</h2>
|
||||
<p>下面的 r 是在<b>这一批关卡</b>上现算的:同一个 agent 把每关玩了两次,99 对。不是引用更早、更小的样本。</p>
|
||||
<table>
|
||||
<thead><tr><th>信号</th><th class="n">复测 r</th><th class="n">n</th><th>怎么用</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>盲转次数</td><td class="n yes">1.00</td><td class="n">99</td><td>可用:驱动了真实修复</td></tr>
|
||||
<tr><td>转错方向次数</td><td class="n yes">1.00</td><td class="n">99</td><td>可用</td></tr>
|
||||
<tr><td>实际旋转数</td><td class="n yes">1.00</td><td class="n">99</td><td>可用</td></tr>
|
||||
<tr><td>步数</td><td class="n yes">1.00</td><td class="n">99</td><td>可用</td></tr>
|
||||
<tr><td>决策数</td><td class="n yes">0.93</td><td class="n">99</td><td>可用</td></tr>
|
||||
<tr><td>无解感评分</td><td class="n ">0.47</td><td class="n">99</td><td>只按档看</td></tr>
|
||||
<tr><td>难度评分</td><td class="n ">0.46</td><td class="n">99</td><td>只按档看,约 20 局起</td></tr>
|
||||
<tr><td>好玩评分</td><td class="n no">0.10</td><td class="n">99</td><td>不可用</td></tr>
|
||||
<tr><td>清晰度评分</td><td class="n no">0.28</td><td class="n">99</td><td>不可用</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>机械指标全部 r ≈ 1.00,但那多半是因为 agent <b>88% 的情况下重放了完全相同的动作序列</b>——这本身才是有用的那条结论:重复跑同一关买不到新信息。评分则相反:同一条轨迹,12 对给出了不同的难度分。</p>
|
||||
|
||||
<h2>五条规则,各自的证据</h2>
|
||||
<div class="rule">
|
||||
<h3><span class="no">1</span>难度评分只能按档看,不能逐关看</h3>
|
||||
<dl>
|
||||
<dt>证据</dt><dd class="ev">100 局里有 84 局打的是 2 分,而这些关卡的决策数从 3 到 15。逐关复测 r = 0.46,而且 13 对分歧里有 12 对<b>走的是同一条轨迹</b>——同样的动作、同样的结果,模型给自己打了不同的分。但按档平均约 20 局后,曲线第一次显形了(见上表)。</dd>
|
||||
<dt>为什么</dt><dd>文字盘面把每颗棋子的路线、挡路者、紧贴者列成清单,agent 不必用眼睛顺线走一遍——而那正是这游戏的难点。agent 自己写过:「挡路名单已经写全,不用顺着格子数」。剩下的评分噪声,只有靠聚合才压得下去。</dd>
|
||||
<dt>现在怎么做</dt><dd>逐关排序改为机械假设(旋转深度、棋子数、互锁),由人工审核裁定;评分只用来读整档的高低。</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="rule">
|
||||
<h3><span class="no">2</span>先用规则机器人扫,再花 agent 时间;同一关不要跑两遍</h3>
|
||||
<dl>
|
||||
<dt>证据</dt><dd class="ev">第二轮意外把每关跑了两次,得到 99 对复测:其中 87 对(88%)重放了<b>完全相同</b>的动作序列,机械指标复测 r = 1.00。规则机器人跑完 50 关只要 1 秒。</dd>
|
||||
<dt>为什么</dt><dd>agent 近乎确定性,重复同一关几乎不产生新信息。为「提高可信度」而重复跑,是把预算花在已经知道的答案上。</dd>
|
||||
<dt>现在怎么做</dt><dd>全量验收交给规则机器人;agent 每关只跑一次,省下的预算用来多覆盖关卡。</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="rule">
|
||||
<h3><span class="no">3</span>门槛写在生成期,不写在筛选期</h3>
|
||||
<dl>
|
||||
<dt>证据</dt><dd class="ev">把开局门槛提到「可点≥3 枚、演出≥0.8s」后筛选写出了 0 关——池子的中位数是 2 枚 / 0.57s。</dd>
|
||||
<dt>为什么</dt><dd>筛选只能从池子里挑,挑不出池子里没有的东西。分布不对时,要改的是构造。</dd>
|
||||
<dt>现在怎么做</dt><dd>开局问题由构造里的展示位插入解决,不是靠筛。</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="rule">
|
||||
<h3><span class="no">4</span>每加一个门槛,先证明它挡掉了东西</h3>
|
||||
<dl>
|
||||
<dt>证据</dt><dd class="ev">两次结构性猜测被实测推翻:「插入端多朝向出口」过滤器对漏斗零效果;为解释难度评分而建的 legibility 指标与评分相关 -0.02。</dd>
|
||||
<dt>为什么</dt><dd>一个不改变漏斗的门槛,只会让人以为问题已经解决了。</dd>
|
||||
<dt>现在怎么做</dt><dd>两者都已撤回/降级为纯测量。漏斗每一级的剩余数量都打印出来。</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="rule">
|
||||
<h3><span class="no">5</span>抱怨要对照基线,不要直接当缺陷</h3>
|
||||
<dl>
|
||||
<dt>证据</dt><dd class="ev">agent 33 条抱怨里最集中的是「路线太长读不完」。但已上线的 v0.5 最长路线 74 格,比这批新关卡的 74 格还长。</dd>
|
||||
<dt>为什么</dt><dd>那是这个游戏本来的性格。把它当缺陷修掉,改的是游戏而不是关卡。</dd>
|
||||
<dt>现在怎么做</dt><dd>只在审核页标出,交给人裁定。</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h2>agent 能测什么,不能测什么</h2>
|
||||
<table>
|
||||
<thead><tr><th>指标</th><th class="n">可用</th><th>依据</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>盲转 / 多余转 / 转错方向</td><td class="n yes">可用</td><td>本批复测 r = 1.00;驱动了真实修复(盲转 1.17 → 0.12)</td></tr>
|
||||
<tr><td>是否通关、空点次数</td><td class="n yes">可用</td><td>直接观察,无主观成分</td></tr>
|
||||
<tr><td>自由文本抱怨</td><td class="n yes">可用</td><td>33 条里两个主题高度重复,指标抓不到;但须对照基线(规则 5)</td></tr>
|
||||
<tr><td>难度评分</td><td class="n no">只按档看</td><td>逐关复测 r = 0.46,且同一条轨迹会打出不同分;按档平均约 20 局才显出梯度</td></tr>
|
||||
<tr><td>无解感评分</td><td class="n">只按档看</td><td>复测 r = 0.47;按档看时与难度同向抬升,可当挫败感的代理</td></tr>
|
||||
<tr><td>好玩 / 清晰度评分</td><td class="n no">不可用</td><td>复测 r = 0.10 / 0.28,是模型噪声</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>要做 1000 关的话</h2>
|
||||
<ol class="recipe">
|
||||
<li><b>先把判据写成可执行的闸门</b>,再开始生成。这一轮的闸门链是:长成 → 首转双向 → 锁住 ≤90% → 无不可解态 → 终局朝向 ≥2 → 每转释放 ≥2 → 反差 ≥12 → 开局可点 ≥3 → 开局演出 ≥0.9s → 长巡游 ≥3。每一级剩多少必须打印出来。</li>
|
||||
<li><b>用规则机器人做全量验收</b>(12 秒 / 全池),不用 agent。机械旋转指标已证明测的是关卡不是玩家。</li>
|
||||
<li><b>agent 只抽样跑</b>,而且只看两样东西:机械缺陷指标,和自由文本抱怨。不要为难度标定花 agent 时间——那条路这一轮已经证明走不通。</li>
|
||||
<li><b>难度曲线靠机械假设铺,靠人眼裁定。</b>用 <code>select-50.mjs</code> 按特征打分并均匀铺开,家族上限防止一套模板占满(上一版 1000 关实际只有 30 套模板)。</li>
|
||||
<li><b>每一轮只动一个变量</b>,并且必须能在漏斗里看到它挡掉了什么,否则撤回。</li>
|
||||
<li><b>人工审核要准备好材料</b>:开局盘面从求解器取(不是示意图)、标明哪些数字可信、每关一个试玩直达链接。</li>
|
||||
</ol>
|
||||
|
||||
<h2>被实测否掉的做法</h2>
|
||||
<table>
|
||||
<thead><tr><th>试过什么</th><th>结果</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>拟合 difficulty ~ 机械特征,用来重选关卡</td><td>响应几乎无方差(84/100 同分),回归的是常数</td></tr>
|
||||
<tr><td>legibility(一眼看穿的成本)解释难度评分</td><td>相关 -0.02,无效;降级为纯测量</td></tr>
|
||||
<tr><td>路线交叠度当难度轴</td><td>中位已达 89%,没有上升空间</td></tr>
|
||||
<tr><td>换开局朝向来提高判断成本</td><td>127 个候选里只有 7 个变好</td></tr>
|
||||
<tr><td>「插入端多朝向出口」过滤器</td><td>对漏斗零效果,已删除</td></tr>
|
||||
<tr><td>把锁住比例当难度主轴排序</td><td>方向反了:它奖励「开局什么都做不了」</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<footer>
|
||||
<p class="mono">生成:node scripts/build-process-report.mjs · 页面所有数字由脚本从 levels/campaign-50.json 与 bench/runs 直接测得</p>
|
||||
<p>相关:<a href="review-50.html">五十关人工审核页</a> · <a href="level-board.html">任务看板</a> · <a href="bench-reliability.html">bench 复测可信度</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,69 +0,0 @@
|
||||
# 发布手机版 · 交给 agent 执行的说明
|
||||
|
||||
整份内容可以直接复制给另一个 agent。
|
||||
|
||||
---
|
||||
|
||||
**任务:把 HEX TRAILS 的 50 关手机版发布到一个手机能访问的网址。**
|
||||
|
||||
仓库:`git@git.zeroplus.fun:Zeroplus/HexTrails.git`,分支 `main`(本地路径 `/Users/wukaibing/Codex/hex-arrow`)。构建脚本 `scripts/build-phone.mjs` 已经写好并测过,你**不需要改游戏代码**。
|
||||
|
||||
## 第一步,构建
|
||||
|
||||
```bash
|
||||
node scripts/build-phone.mjs --standalone --out=build/phone-standalone
|
||||
```
|
||||
|
||||
产物约 5.2MB:`index.html`(完整 HTML 文档,样式已内联)+ `src/` 22 个 ES module + `assets/` 7 个资源(贴图、图标图集、背景、托盘、两个 woff2 字体)。
|
||||
|
||||
如果目标托管平台**自带 `<html>` / `<head>` / `<body>` 外壳**(比如 Claude Artifacts),改用不带 `--standalone` 的默认模式,产出的 `index.html` 只有 body 内容:
|
||||
|
||||
```bash
|
||||
node scripts/build-phone.mjs
|
||||
```
|
||||
|
||||
两种模式只差文档外壳,其余完全一样。**别把两者搞混**——给普通静态托管发了片段版,页面会没有 viewport meta,手机上按 980px 宽渲染。
|
||||
|
||||
## 第二步,发布
|
||||
|
||||
发到任意静态托管都行(Vercel / Netlify / Cloudflare Pages / GitHub Pages / 对象存储)。要求只有三条:
|
||||
|
||||
1. **保持目录结构。** `index.html` 里是 `<script type="module" src="src/app.js">`,模块之间用相对路径互相 import,`assets/` 也是相对路径引用。不要扁平化目录,不要给资源加 hash 重命名,除非你同时改写所有引用。
|
||||
2. **`.js` 必须以 `text/javascript` 返回。** 用 `application/octet-stream` 返回的话 ES module 会被浏览器拒绝执行,页面白屏。
|
||||
3. **全站 HTTPS 或全站 HTTP,别混。**
|
||||
|
||||
## 第三步,验收(必做,逐条确认)
|
||||
|
||||
用手机宽度(375px)打开发布后的网址,确认:
|
||||
|
||||
- [ ] 标题栏是 `LEVEL 01`,`待解棋子 8`
|
||||
- [ ] 左上角有九宫格图标、右上角有齿轮图标(**不是空白、不是破图**)
|
||||
- [ ] 底部三个圆按钮里有撤销 / 重来 / 灯泡图标
|
||||
- [ ] toast 里**没有**「棋子图片加载失败,已切换基础绘制」——出现这句说明 `assets/tiles-matte-clean-v8.png` 没发上去或 404
|
||||
- [ ] 棋盘上 8 枚彩色六角棋子带箭头,背景有轨道线
|
||||
- [ ] 点一下第 1 关左下角那枚粉色棋子,它应该沿轨道滑出棋盘,计数变成 7
|
||||
- [ ] 页面**没有横向滚动条**
|
||||
|
||||
浏览器控制台不应有 404 或模块加载错误。有的话先查是不是第 1 条(目录结构)或第 2 条(MIME)。
|
||||
|
||||
**已知的、不是 bug 的现象**:375×812 下棋盘只占上半屏,下半屏是空的。这是游戏现有布局,和未打包的原版一模一样,不要去「修」它。
|
||||
|
||||
## 背景
|
||||
|
||||
这 50 关是 `c50` 版本。构建脚本会把 campaign 注册表换成只含这一版,从而甩掉千关版那个 9.2MB 的 `src/levels-v05.js`——完整静态构建是 10MB+,这里是 645KB 代码 + 4.5MB 图。
|
||||
|
||||
进度存在浏览器 localStorage(key `hex-trails-campaign-c50`),通一关自动进下一关。清空进度:
|
||||
|
||||
```js
|
||||
localStorage.setItem('hex-trails-campaign-c50', JSON.stringify({current:0,completed:[]}))
|
||||
```
|
||||
|
||||
## 如果只是自己在局域网里玩
|
||||
|
||||
不用发布,电脑跑着 `npm run dev`,手机连同一个 Wi-Fi 打开:
|
||||
|
||||
```
|
||||
http://<电脑的局域网IP>:4173/index.html?campaign=c50
|
||||
```
|
||||
|
||||
IP 用 `ipconfig getifaddr en0` 查。服务已绑 `0.0.0.0`,不用改配置。
|
||||
File diff suppressed because one or more lines are too long
@@ -1,30 +0,0 @@
|
||||
# 三关入门序章
|
||||
|
||||
2026-09-12。入口:[开始教学](http://localhost:4173/?campaign=v0.5&tutorial=1)。选关窗口将三个教学入口放在正式章节前,可以随时重玩。
|
||||
|
||||
| 教学 | 棋盘 / 棋子 | 玩家学会什么 | 最少操作 |
|
||||
| --- | --- | --- | --- |
|
||||
| 点一下,出发 | 完整 19 格 / 1 枚 | 箭头决定起步方向,沿弯道自动转向,离场即完成 | 1 次点击 |
|
||||
| 先给它让路 | 同一完整 19 格盘 / 2 枚 | 先移下方挡子,再点上方棋子;可以连续点击 | 2 次点击 |
|
||||
| 转一下,路就通了 | 完整 19 格 / 2 枚 | 旋转轨道打开新出口,棋子位置和箭头不动 | 1 次旋转 + 2 次点击 |
|
||||
|
||||
根据用户反馈,原先的 4 / 4 / 7 格教学盘统一替换为与正式第 1 关相同的完整半径 2 六边形,保留全部 19 个格子和边角,仅减少棋子。三课由规整的直脊和两侧连续圆弯组成,前两课共用同一底板;第二课只增加一个新的阻挡关系。第三课上下对称,左右任一方向转一次都能清盘。主路线经过 6 格、转 5 次弯;第二课的挡子走 2 弯离场。每格的三对轨道全部真实、完整且格内不交叉,统一颜色和线宽。
|
||||
|
||||
界面与操作沿用游戏已有逻辑:教学说明使用原来的限时提示,旋转、撤销、重来和提示使用原有控件。前两课通过关卡数据禁用旋转,第三课允许旋转;不新增或隐藏教学专用控件,不另设布局或配色。每课结算复用原有弹窗;完成第三课后点击“开始第 1 关”,进入原来的正式关卡。
|
||||
|
||||
## 入口与进度
|
||||
|
||||
教学布局位于 `src/tutorial-levels.js`,作为 `campaign.tutorials` 接入,未插入正式的 `levels` 数组。正式 1–1000 的编号、关卡 ID、直接链接和已完成记录都保持原位。
|
||||
|
||||
新玩家无指定关号进入 v0.5 时自动开始教学。未完成的教学可以续玩;有正式关进度的玩家继续原关卡。`?tutorial=1` 至 `?tutorial=3` 明确打开对应教学,`?level=1` 仍直达正式第 1 关。教学使用独立键 `hex-trails-tutorial-v1-v0.5`,完成或重玩教学不计入正式通关数。
|
||||
|
||||
## 已完成的验证
|
||||
|
||||
- 正式 `Game`、`validateLevel`、`trace` 和求解器验证全部三课。第二课点击被挡棋子不耗额度;清挡后的新点击立即可用。第三课验证左右两种旋转和两种清盘顺序。
|
||||
- 本轮 **43 项相关测试通过**,覆盖三课布局与显式 19 格坐标集合、三课衔接、重玩、旧正式关进度、切版本后刷新、从教学进入工坊,以及原快速连点规则。静态构建通过。正式 1000 关的布局和生成流水线未改动。
|
||||
- 390×844 浏览器正常动画下重新依次完成完整棋盘的三课。第二课挡子与主棋子可连续点击;第三课向右旋转一次,两个箭头保持原位并成功离场。教学期间正式存档保持不变,点击开始第 1 关后只更新当前正式关位置,保留原通关集合。[当前操作记录](tutorial-review/playthrough.json)。旧小棋盘截图与操作证据移至 `tutorial-review/initial-small/`,不作为当前布局的验收证据。
|
||||
- 检查 320×568 与 1440×1000 的第三课、390×844 的全部三课与选关入口。[尺寸记录](tutorial-review/responsive.json)。这是浏览器视口与实际指针操作验证,不等同于真机手指误触测试。
|
||||
|
||||
按用户限定的制作范围,已撤回自行添加的缩放按钮显示、教学控件隐藏、常驻提示及专用布局与配色。43 项相关测试再次通过,包含原提示到时消失的验证。390×844 浏览器确认原有控件显示,前两课旋转禁用、第三课启用,选关使用既有按钮样式且能够切换教学,正式第 1 关也无新增缩放按钮。[恢复现有界面后的画面](tutorial-review/ui-restored-mobile.png)。
|
||||
|
||||
以下为恢复界面前的完整棋盘记录,布局与操作验证仍适用,控件样式以最新画面为准:[第一课](tutorial-review/lesson-1-mobile.png) · [第二课](tutorial-review/lesson-2-mobile.png) · [第三课](tutorial-review/lesson-3-mobile.png) · [选关入口](tutorial-review/map-mobile.png) · [小屏](tutorial-review/lesson-3-small.png) · [桌面](tutorial-review/lesson-3-desktop.png)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user