per-genre 轻起点骨架(照 _template-shop/_template-story 打样、L1 六件与 _template 逐字同): 勇者限时闯塔→每层翻遭遇卡(怪物/宝箱/奇遇,难度与奖励亮牌)→点卡=掷 d20+等级加成 vs 难度三档结算(金币/经验升级/怪物卡失败扣血)→清层登塔难度渐升→登顶 win/HP 耗尽 lose/60s 到点结算。掷骰过程可见(飘判定式 d20:骰+加成 vs 难度——不黑箱)。 _forensicsView 的 targets/score 取证契约 = 九门 tap-targets occupied driver 可达 (play 态 ready 遭遇卡 occupied:true、menu 空数组防误点;score=金币战利品单调升, 失败也有安慰 1 金=进展契约;卡命中区=绘制区=取证 targets 三者同源于 core.buildFloor)。 core.js 顶部多样性参数空间(ENCOUNTER_DECK 遭遇表/层数/血量/难度经验曲线)+ 结构约束单测机器化(牌库 ≥4 项三 kind 齐/同层无重复抽样/难度地板 2)。 前任半成品盘点续做:src/ 7 件 + entry/index/manifest 已完整(沿用,零改动); 本次补齐 README.md + test/core.test.mjs + test/headless-boot.test.mjs + assets/gen-ledger.md。 验收:core 单测 13/13 + headless 全链路 3/3(真 tap 坐标起局→targets 驱动逐卡掷骰 →score 严格递增→翻层→over latch→再闯一次;同 seed 确定性;异 seed 牌面多样); scaffold-saa/check/build-saa/stage/smoke 全 PASS(check=API 静态门+形状门对范例签名过门); 独立过九门 9/9(verdict: games/_wg1-gen/p11c-tpl/evidence/verdict.json, H_progress score 0→97 increased + latch over 驻留,F_wiring sessionScore./audioMusic./juice. 全中); 金标 spec 注入复验九门同样 9/9。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
101 lines
4.0 KiB
HTML
101 lines
4.0 KiB
HTML
<!DOCTYPE html>
|
||
<!--
|
||
index.html — 「点圆得分」(_template 克隆起点)宿主页
|
||
用法:
|
||
· 构建产物(iife 全局 TemplateGame):见 entry.js 头注释的 build.mjs 锁参命令(产物 dist/template-bundle.js);
|
||
· serve 本目录,浏览器打开;
|
||
· ?seed=12345 注入主随机种子(缺省固定种子,确定可复现);
|
||
· ?engine=stub(缺省·回滚锚)/ ?engine=real(引擎掌帧);
|
||
· ?mode=evidence 取证模式:stub 下不起 RAF,由 window.__gameHost.stepFrames/tap 确定性驱动;
|
||
· 取证导出:window.__gameForensics / window.__gameHost;就绪标记:__gameBooted。
|
||
注意:页面壳只负责承载;游戏全部绘制在 canvas 内。
|
||
-->
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<!-- 固定取证视口:390×844 移动竖屏基准;禁缩放防像素哈希扰动。 -->
|
||
<meta name="viewport" content="width=390, height=844, initial-scale=1, user-scalable=no" />
|
||
<title>点圆得分</title>
|
||
<style>
|
||
/* 自适应居中画布:游戏全部绘制在 canvas 内,页面壳只承载。
|
||
画布按 390:844 比例缩放 fit 窗口——桌面短窗口不裁底(否则底部内容如按钮/角色看不见)。
|
||
host 输入映射按 getBoundingClientRect 归一化(boot-game-host toCanvasXY),CSS 缩放下点击坐标仍准。 */
|
||
html, body {
|
||
margin: 0;
|
||
padding: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: #0a1622;
|
||
color: #9fb3c8;
|
||
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
|
||
overflow: hidden;
|
||
}
|
||
#wrap {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
#game {
|
||
/* 取「宽受限」与「高受限」的较小者,保 390:844 比例完整可见。
|
||
!important 覆盖 host 在 stub 通道写的内联 display(390×844 硬编码);buffer 不动→evidence 像素哈希不受影响;
|
||
输入经 boot-game-host toCanvasXY 按 getBoundingClientRect 归一,CSS 缩放下点击坐标仍准。 */
|
||
width: min(100vw, calc(100vh * 390 / 844)) !important;
|
||
height: min(100vh, calc(100vw * 844 / 390)) !important;
|
||
background: #10243a;
|
||
display: block;
|
||
touch-action: none; /* 触摸全交 JS(pointer 桥接),禁浏览器默认手势 */
|
||
}
|
||
#status {
|
||
position: absolute; /* 浮层叠于 canvas 顶部,不占布局流 */
|
||
top: 0; left: 0; right: 0;
|
||
z-index: 2;
|
||
pointer-events: none; /* 绝不截触摸 */
|
||
font-size: 12px;
|
||
line-height: 1.4;
|
||
min-height: 15px;
|
||
text-align: center;
|
||
word-break: break-all;
|
||
opacity: 0.7;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="wrap">
|
||
<div id="status">booting…</div>
|
||
<canvas id="game"></canvas>
|
||
</div>
|
||
|
||
<!-- 构建产物(iife 全局 TemplateGame,含 bootGame)。克隆后按 entry.js 头注释构建生成。 -->
|
||
<script src="./dist/template-bundle.js"></script>
|
||
<script>
|
||
// 引导:异步 boot;失败把错误打到 status + 重抛(评估门要看 console 零未捕获错误)。
|
||
(function () {
|
||
'use strict';
|
||
var statusEl = document.getElementById('status');
|
||
var canvas = document.getElementById('game');
|
||
try {
|
||
var G = window.TemplateGame;
|
||
if (!G || typeof G.bootGame !== 'function') {
|
||
throw new Error('TemplateGame.bootGame 未找到(template-bundle.js 未正确加载或 globalName 不符)');
|
||
}
|
||
G.bootGame({ canvas: canvas, statusEl: statusEl })
|
||
.then(function () { window.__gameBooted = true; })
|
||
.catch(function (e) {
|
||
window.__gameBooted = false;
|
||
window.__gameBootError = String((e && e.message) || e);
|
||
if (statusEl) statusEl.textContent = 'BOOT ERROR: ' + window.__gameBootError;
|
||
throw e;
|
||
});
|
||
} catch (e) {
|
||
window.__gameBooted = false;
|
||
window.__gameBootError = String((e && e.message) || e);
|
||
if (statusEl) statusEl.textContent = 'BOOT ERROR: ' + window.__gameBootError;
|
||
throw e;
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|