<!doctype html><html lang="zh"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>AMG UI Standard v2</title><style>
:root{color-scheme:dark}*{box-sizing:border-box}
body{margin:0;font:16px/1.6 -apple-system,system-ui,"Segoe UI",sans-serif;background:#1a130c;color:#f1e6d3;overflow-wrap:anywhere}
main{max-width:960px;margin:0 auto;padding:12px 14px 60px}
a{color:#ffc850}h1{font-size:1.5rem;line-height:1.3}h2{font-size:1.2rem;border-top:1px solid #5a4630;padding-top:18px;margin-top:28px;scroll-margin-top:8px}
li{scroll-margin-top:8px}
img{max-width:100%;height:auto;background:#2a2016;border-radius:6px}
.tw{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:12px 0}table{border-collapse:collapse;font-size:.88rem}
th,td{border:1px solid #5a4630;padding:6px 8px;vertical-align:top;min-width:6em}th{background:#2e2318}
pre{overflow-x:auto;background:#241a10;padding:10px;border-radius:6px}code{background:#241a10;padding:1px 4px;border-radius:4px;font-size:.9em}
blockquote{margin:12px 0;padding:2px 12px;border-left:3px solid #ffc850;background:#241a10}
nav.toc{background:#241a10;border:1px solid #5a4630;border-radius:8px;padding:8px 12px;margin:12px 0}
nav.toc summary{cursor:pointer;font-weight:600}nav.toc ol{margin:8px 0 0;padding-left:0;list-style:none;display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:4px 10px}
nav.toc a{display:block;padding:6px 0;text-decoration:none;font-size:.9rem}
.dl{font-size:.9rem}
</style></head><body><main><h1 id="amg-ui-标准-v2--amg-ui-standard-v2深棕玻璃">AMG UI 标准 v2 · AMG UI STANDARD v2(深棕玻璃)</h1><p class="dl"><a href="STANDARD.md">STANDARD.md</a> · <a href="latest.json">latest.json</a> · <a href="pieces/">pieces/</a> · <a href="CHANGELOG.md">CHANGELOG.md</a></p><nav class="toc" id="toc"><details open><summary>目录 Contents · P1–P30 + 开工规则</summary><ol><li><a href="#p1">P1 · 封面 · 元信息 · Cover · metadata</a></li><li><a href="#p2">P2 · 色彩令牌 · 字体 · Colour tokens · fonts</a></li><li><a href="#p3">P3 · 顶栏 · 主页钮 Home · Top bar · Home</a></li><li><a href="#p4">P4 · 顶栏 · 说明钮 Info (i) · Top bar · Info (i)</a></li><li><a href="#p5">P5 · 顶栏 · 声音钮 Sound(开 / 静音) · Top bar · Sound (on / muted)</a></li><li><a href="#p6">P6 · 顶栏 · 记录钮 History(时钟 + 徽标) · Top bar · History (clock + badge)</a></li><li><a href="#p7">P7 · 余额胶囊 Balance capsule · Balance capsule (DEMO / name + balance)</a></li><li><a href="#p8">P8 · 筹码 1K–500K + 选中环 · Chips 1K–500K + selected ring</a></li><li><a href="#p9">P9 · PLAY 钮 · PLAY button</a></li><li><a href="#p10">P10 · 清除 / HAPUS 钮 · Clear (HAPUS) button</a></li><li><a href="#p11">P11 · 总下注框 TOTAL TARUHAN · Total bet box</a></li><li><a href="#p12">P12 · 下注面板底 Bet panel base · Bet panel base (bottom sheet)</a></li><li><a href="#p13">P13 · 说明弹窗 Info (rules) popup · Info popup</a></li><li><a href="#p14">P14 · 记录面板 History panel (RIWAYAT) · History panel</a></li><li><a href="#p15">P15 · 结算卡 / 赢钱弹窗 · Result card / win popup</a></li><li><a href="#p16">P16 · 错误卡 Error card V1 · Error card (V1: dark-brown)</a></li><li><a href="#p17">P17 · 载入页 Loading screen · Loading screen</a></li><li><a href="#p18">P18 · 状态总表:按下 · 选中 · 禁用 · State table: pressed · selected · disabled</a></li><li><a href="#p19">P19 · 差异裁决表 · Decision table</a></li><li><a href="#p20">P20 · 摆法图 · 直立 390×844 · Placement · portrait</a></li><li><a href="#p21">P21 · 摆法图 · 横屏 844×390 · Placement · landscape</a></li><li><a href="#p22">P22 · 缺件 · 未核实 · 不取 · Missing · unverified · not taken</a></li><li><a href="#p23">P23 · 验收规则 + check-conformance · Acceptance rule + check-conformance</a></li><li><a href="#p24">P24 · 动画必备五类 · Required animation set</a></li><li><a href="#p25">P25 iPhone Duo 适配</a></li><li><a href="#p26">P26 声音钮首按即响</a></li><li><a href="#p27">P27 home/返回钮必须有动作</a></li><li><a href="#p28">P28 · 手机全屏 · Mobile full screen(Victor 2026-10-28 13:2x/13:3x 令,必备)FULLSCREEN</a></li><li><a href="#p29">P29 · 禁缩放 · No zoom(Victor 2026-10-28 13:0x 问「double tap 有挡吗」→ 定为必备)ZOOMLOCK</a></li><li><a href="#p30">P30 · 演出逻辑关 · Animation causality gate(Victor 2026-10-28 11:5x 批、#1849 定)LOGIC</a></li><li><a href="#rules">开工规则(Victor 2026-10-28 13:3x):做任何新游戏,工单第一行写「照本 STANDARD P1–P30 全部做完」,不挑页;缺一页 = 不过。</a></li></ol></details></nav>
<blockquote>
<p><strong>本版取代 2026-10-20 v3;唯一来源＝线上深棕玻璃原件(零件取线上原件,附来源与 SHA,不重画、不 AI 生成)。</strong><br />
<strong>正本存放位置:<code>(internal)</code>(NAS 正本;工作副本 <code>(internal)</code>)。版本固定 v2 一个正本。</strong><br />
Supersedes the 2026-10-20 v3. Single source = the live dark-brown glass originals. No piece is redrawn or AI-generated.</p>
</blockquote>
<p>配套:<code>PIECES.csv</code>(零件清单+SHA256)· <code>pieces/</code>(原档)· <code>AMG-UI-STANDARD-v2.pdf</code>(同内容,一页一表)· <code>DIFF-TO-ADOPT.md</code>(5 款换件)· <code>check-conformance</code>(只读检查脚本)。</p>
<h2>验收规则 Acceptance rule(Victor 2026-10-23)</h2>
<p>改完后<strong>每款游戏的每个标准零件必须与 <code>PIECES.csv</code> 的 SHA256 完全相同</strong>(逐档比对,不是目视);以后每次改动都跑 <code>./check-conformance</code>。细节见本文件第 23 节与下文。</p>
<h2 id="p1">P1 · 封面 · 元信息 · Cover · metadata <code>ALL</code></h2>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>文件 File</td>
<td>AMG-UI-STANDARD v2(固定一个正本)· 2026-10-23 · hq-designer</td>
<td>本版<strong>取代 2026-10-20 v3</strong>;唯一来源=线上深棕玻璃原件。v3 只供对照,<strong>不取其任何件</strong>。</td>
</tr>
<tr>
<td>正本存放位置 Canonical location</td>
<td>(internal)(NAS 正本;工作副本 (internal))</td>
<td>改标准 = 改 PIECES.csv + STANDARD.md + 本 PDF,版本号永远是 v2;任何改动都要先问 Victor。</td>
</tr>
<tr>
<td>唯一来源 Single source</td>
<td>线上深棕玻璃:chicken=kancilroad、croc=komodo、wheel、tower(四款已核最接近);fishshoot 属统一目标,房内 UI 未核实</td>
<td>Victor 2026-10-23 12:4x 拍板:AMG 唯一标准=深棕玻璃;plinko/catfish/crash/赛马/赛车都改成它。</td>
</tr>
<tr>
<td>来源核实基点 Verified base</td>
<td>源码包 amg-minigames-src-20261019.zip(sha256 0808135d…)· git main@67df3c9;线上 8 站 225 个文件 2026-10-23 重取,SHA 与盘点 CSV 0 差(量的);线上构建戳(meta mg-build,今日复核未变):chicken 20261018-081812 · croc -081818 · wheel -081823 · tower -081835 · plinko -081829 · catfish -081840 · crash 20261016-222106</td>
<td>源码件仅在 SHA256 与线上一致时取用;25/25 图/字件一致(量的)。</td>
</tr>
<tr>
<td>零件 Pieces</td>
<td>图/字 25 件(取到,SHA=线上)· 代码件 14(DOM/CSS/SVG,保留原实现+引用,不重制 PNG)· 缺/未定/未核实/不取 7 项</td>
<td>明细见 PIECES.csv(46 行)。线上没有的件列「缺」,不补画、不 AI 生成。</td>
</tr>
<tr>
<td>裁决规则 Decision rule</td>
<td>线上四款有差异处:取最多款版本;原并列/各异的「未定」项由总监 #1650(2026-10-23)一律取 wheel 实测值(见第 19 页)</td>
<td>另发现盘点没列的差异(玻璃透明度、阴影、按下态、底部留白)一并按同规则列出。</td>
</tr>
<tr>
<td>标准视口 Viewports</td>
<td>手机 390×844、430×932(DPR3,本版实拍);横屏 844×390(DPR3,本版实拍);折叠 1812×2176 / iPad 直立 1024×1366 / 桌面 1920×1080:本版<strong>未重拍</strong>,旧盘点截图为 DPR1,不冒称符合家规;顶栏钮边长按 fit.ts 公式 clamp(44,72,min(vw,vh)×0.11) 推得:折叠/iPad/桌面=72、430 宽=47.3(推的,未实拍)</td>
<td>直立/横屏是同一套零件的两种摆法(第 20、21 页),不是两套。</td>
</tr>
<tr>
<td>证据目录 Evidence</td>
<td>shots/&lt;款&gt;/(线上实机截图 + dump JSON)· _live/ + refetch-live-sha.csv(今日重取的线上字节与 SHA)· measure/(conformance / compare / decisions JSON)· sbs/(并排图)· layout/(摆法图)· tools/(可重跑脚本)</td>
<td>全部只读 GET 取得;无头浏览器一次一个</td>
</tr>
<tr>
<td>怎么用 How to use</td>
<td>要某个零件:PIECES.csv 找 id → file 列取原档(live_sha256 为准);DOM 件按 implementation_ref 取原实现;验收跑 ./check-conformance</td>
<td>一页一表,中英对照;截图均为线上实机(headless),不是画的。</td>
</tr>
</tbody>
</table></div>
<blockquote>
<p>每页左为线上实机截图(DPR3),右为 1 张表。色值/尺寸/字号均为 getBoundingClientRect/getComputedStyle 量测;croc、tower 的 DOM 在 828 宽设计舞台里再缩放 0.471 到 390,表内已换算成显示值(推的:computed×0.471)。</p>
</blockquote>
<h2 id="p2">P2 · 色彩令牌 · 字体 · Colour tokens · fonts <code>TOKENS · FONT-*</code></h2>
<p><img loading="lazy" src="shots/chicken/piece-userbox.png" alt="chicken 余额胶囊(玻璃面实例)" /><br />
<img loading="lazy" src="shots/croc/piece-userbox.png" alt="croc 同件" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>金 Gold</td>
<td>--gold #ffd24a(4/4 款同)</td>
<td>图标/余额/选中边/强调;对比度 金/玻璃 8.4–13.4:1(量的:黑底~白底两端)</td>
</tr>
<tr>
<td>玻璃面 Glass</td>
<td>--glass1 rgba(40,30,18,.9) → --glass2 rgba(20,15,10,.9);<strong>取 croc=wheel(2/4)</strong>;chicken .88/.92、tower .92/.92 与多数不同</td>
<td>线上 :root 实测;FRAG-TOKENS 检查</td>
</tr>
<tr>
<td>描边线 Line</td>
<td>--line rgba(255,200,80,.45)(chicken、croc、wheel 3/4);tower .5</td>
<td>取 .45</td>
</tr>
<tr>
<td>顶栏钮底 Top-bar btn</td>
<td>linear-gradient(rgba(40,30,18,.9), rgba(20,15,10,.94));1px solid rgba(255,200,80,.5);圆角 9.68px(4/4 款同)</td>
<td>线上 computed</td>
</tr>
<tr>
<td>文字色 Text</td>
<td>名 rgba(255,220,150,.85)(croc=wheel,取);余额 #ffd24a;白 #fff;面板标题 #f1dfae;按钮墨 #3a2605;错误红 #e14b4b / 浅 #ffb4b4</td>
<td>对比度见各页</td>
</tr>
<tr>
<td>字体 Fonts</td>
<td>Playfair Lining 800(sha 31337251)= --fn 倍率牌;Space Grotesk 可变(sha acad6de1)= 载入页文字 700;按钮/标签正文 "Segoe UI",Arial,Helvetica,sans-serif(<strong>系统字回落</strong>,各平台观感不同)</td>
<td>字体档已入 pieces/fonts/;正文实际 font-family 以实测为准,不以附字体档代替</td>
</tr>
<tr>
<td>页面底 Page bg</td>
<td>body/#app #060a18;舞台 #080b16</td>
<td>线上 CSS</td>
</tr>
<tr>
<td>阴影 Shadow</td>
<td>.glass CSS 写法:croc=wheel <code>0 2px 10px #00000080</code>(取,FRAG-GLASS 检查此写法);chicken <code>0 4px 18px #00000073</code>。显示值因舞台缩放(croc/tower ×0.471)四款各异</td>
<td>CSS 写法取 croc=wheel;<strong>显示值取 wheel 的 0 2px 10px #00000080(总监 #1650 定 2026-10-23)</strong></td>
</tr>
</tbody>
</table></div>
<blockquote>
<p>以上令牌是「线上多数版」,不是我新定;chicken(.88/.92)与 tower(.92/.5)要改到多数版才能「一模一样」(见 DIFF 与第 19 页)。</p>
</blockquote>
<h2 id="p3">P3 · 顶栏 · 主页钮 Home · Top bar · Home <code>TB-HOME</code></h2>
<p><img loading="lazy" src="shots/chicken/piece-home.png" alt="idle(chicken 实拍 DPR3)" /><br />
<img loading="lazy" src="shots/chicken/pressed-home.png" alt="pressed(mousedown 0.3s)" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>位置/尺寸 Pos/size</td>
<td>x12 y12 · 44×44 css px(4/4 款同,量的)</td>
<td>线上 getBoundingClientRect</td>
</tr>
<tr>
<td>底/边/角 Skin</td>
<td>linear-gradient(rgba(40,30,18,.9), rgba(20,15,10,.94));1px solid rgba(255,200,80,.5);圆角 9.68;阴影 rgba(0,0,0,.45) 0 4px 18px(4/4 款同)</td>
<td>4/4 款同(量的)</td>
</tr>
<tr>
<td>图标 Icon</td>
<td>内联 SVG 24×24,viewBox 0 0 24 24,stroke currentColor 2.2,round;path「M3 11.5 12 4l9 7.5」「M5.5 10v9.5h13V10」「M10 19.5v-5h4v5」;色 #ffd24a</td>
<td>线上无 PNG;SVG 串 7/7 款线上相同(FRAG-SVG-HOME-1..3)</td>
</tr>
<tr>
<td>文字 Text</td>
<td>无字;aria-label=Home;.ib 基础 font 800 22px(显示)</td>
<td>shell.ts:38</td>
</tr>
<tr>
<td>间距 Spacing</td>
<td>距屏左 12、屏顶 12;与余额胶囊间隔 8(56→64)</td>
<td>推的:56+8=64</td>
</tr>
<tr>
<td>按下 Pressed</td>
<td>:active{filter:brightness(1.35); box-shadow:0 1px 6px rgba(0,0,0,.6) inset}(fit.ts HOME_CSS,四款同;实测 mousedown 吻合,截图见左)</td>
<td>量的+源码</td>
</tr>
<tr>
<td>规则源 Rule source</td>
<td>fit.ts HOME_CSS(sharedHudCss;运行时注入、!important;8 款 bundle 都带同一份):边长 side=clamp(44,72,min(vw,vh)×0.11) css(390 宽→44、430→47.3;折叠/iPad/桌面→72,推的:公式算);margin 12 · gap 8;圆角=side×.22;字 800 side×.5;svg 55%;z-index 30;transition filter .08s;右上从右往左 记录(1.5×side 宽)→声音→(全屏)→i</td>
<td>graphic-amg/skin/src/fit.ts:105-118(hudSlots / homeCssSpec / HOME_CSS)</td>
</tr>
<tr>
<td>禁用/隐藏 Disabled</td>
<td>无禁用态;宿主不可退出时 display:none(platform.nav.canExit=false)</td>
<td>shell.ts render()</td>
</tr>
<tr>
<td>触控 Hit</td>
<td>热区扩到 ≥44×44 css(.ib::after,--hit)</td>
<td>style.css</td>
</tr>
<tr>
<td>来源 Source</td>
<td>graphic-amg/shell/src/shell.ts:38 + style.css(.ib/.glass);线上 CSS <a href="https://amg-kancilroad.pages.dev/assets/index-Bk4cNRm-.css">https://amg-kancilroad.pages.dev/assets/index-Bk4cNRm-.css</a></td>
<td>代码件,保留原实现</td>
</tr>
</tbody>
</table></div>
<h2 id="p4">P4 · 顶栏 · 说明钮 Info (i) · Top bar · Info (i) <code>TB-INFO</code></h2>
<p><img loading="lazy" src="shots/chicken/piece-info.png" alt="idle(chicken)" /><br />
<img loading="lazy" src="shots/chicken/pressed-info.png" alt="pressed" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>位置/尺寸 Pos/size</td>
<td>x208 y12 · 44×44 css px(4/4 款同,量的)</td>
<td>线上 getBoundingClientRect</td>
</tr>
<tr>
<td>底/边/角 Skin</td>
<td>同 Home(第 3 页)</td>
<td>4/4 款同</td>
</tr>
<tr>
<td>文字 Text</td>
<td>字母「i」,font 800 22px,#ffd24a;无 SVG</td>
<td>shell.ts:39</td>
</tr>
<tr>
<td>行为 Behaviour</td>
<td>点开说明弹窗(第 13 页);弹窗面板从 y≈85 起,不盖住顶栏,四钮仍可见(线上截图 panel-info-m390.png);暗幕盖满视口</td>
<td>线上实拍</td>
</tr>
<tr>
<td>按下/禁用 States</td>
<td>:active{filter:brightness(1.35);box-shadow:0 1px 6px rgba(0,0,0,.6) inset}(同 Home,共用 fit.ts);无禁用态</td>
<td>量的+源码</td>
</tr>
<tr>
<td>位置规则 Slot rule</td>
<td>右上从右往左排:记录 → 声音 →(全屏)→ i,钮间 gap 8,右缘距屏 12;i 的 x=屏宽−12−(1.5+1+1)×side−2×8(390 宽:390−12−154−16=208)</td>
<td>推的(fit.ts hudSlots 公式),与实测 x208 吻合</td>
</tr>
<tr>
<td>触控 Hit</td>
<td>同 Home</td>
<td></td>
</tr>
<tr>
<td>来源 Source</td>
<td>shell.ts:39;线上 CSS <a href="https://amg-kancilroad.pages.dev/assets/index-Bk4cNRm-.css">https://amg-kancilroad.pages.dev/assets/index-Bk4cNRm-.css</a></td>
<td>代码件</td>
</tr>
</tbody>
</table></div>
<h2 id="p5">P5 · 顶栏 · 声音钮 Sound(开 / 静音) · Top bar · Sound (on / muted) <code>TB-SOUND</code></h2>
<p><img loading="lazy" src="shots/chicken/piece-sound.png" alt="on" /><br />
<img loading="lazy" src="shots/chicken/piece-sound-muted.png" alt="muted" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>位置/尺寸 Pos/size</td>
<td>x260 y12 · 44×44 css px(4/4 款同,量的)</td>
<td>线上 getBoundingClientRect</td>
</tr>
<tr>
<td>底/边/角 Skin</td>
<td>同 Home</td>
<td>4/4 款同</td>
</tr>
<tr>
<td>图标 Icon</td>
<td>开:24×24 SVG 喇叭「M4 9.5v5h3.5L12 18.5v-13L7.5 9.5z」fill #fff + 声波「M16 9a4 4 0 010 6M18.5 6.5a8 8 0 010 11」stroke #fff 2.4;静音:喇叭 + 斜线「M3.5 3.5l17 17」stroke #ff6b5a</td>
<td>ui-logic.ts:14 soundIconSvg();7/7 款线上字串相同</td>
</tr>
<tr>
<td>对比度 Contrast</td>
<td>白图标/玻璃 12.1–19.3:1;静音红斜线 #ff6b5a/玻璃 6.05:1(黑底)~4.35:1(白底最坏)</td>
<td>量的(按玻璃合成色算;亮底最坏 4.35 略低于 AA 4.5,图标非正文)</td>
</tr>
<tr>
<td>状态 States</td>
<td>on / muted 两态,点按切换;无禁用态</td>
<td>线上实拍(点 #snd 后截)</td>
</tr>
<tr>
<td>来源 Source</td>
<td>graphic-amg/skin/src/ui-logic.ts:14;shell.ts:39</td>
<td>代码件</td>
</tr>
</tbody>
</table></div>
<h2 id="p6">P6 · 顶栏 · 记录钮 History(时钟 + 徽标) · Top bar · History (clock + badge) <code>TB-HIST · FSBTN</code></h2>
<p><img loading="lazy" src="shots/chicken/piece-hist.png" alt="idle(徽标=0)" /><br />
<img loading="lazy" src="shots/chicken/pressed-hist.png" alt="pressed" /><br />
<img loading="lazy" src="shots/chicken/android-bet-m390.png" alt="Android UA 顶栏(全屏钮探测)" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>位置/尺寸 Pos/size</td>
<td>x312 y12 · 66×44 css px(4/4 款同,量的)</td>
<td>线上 getBoundingClientRect</td>
</tr>
<tr>
<td>底/边/角 Skin</td>
<td>同 Home</td>
<td>4/4 款同</td>
</tr>
<tr>
<td>图标 Icon</td>
<td>时钟 SVG 22×22,viewBox 24,stroke #fff 2.4 round:circle(12,13,r8)+「M12 8v5l3 2」</td>
<td>6/7 款线上有(crash 没有记录钮)</td>
</tr>
<tr>
<td>徽标 Badge</td>
<td>金底圆 #ffd24a,字 #2a1b06 800,字号 56px×transform scale(--bdk)(故 computed 为 56px,显示≈13px 目视);显示盒 22×22,位置 x345.9 y23;内容=最近记录条数</td>
<td>4/4 款同(量的);样式在 fit.ts HOME_CSS 的 .hs .bd</td>
</tr>
<tr>
<td>全屏钮 Fullscreen</td>
<td>源码有共用模块(common/fullscreen/src/mount.ts):安卓/iPad 显示 HUD 钮,窄竖屏放第二行、右缘齐历史钮;iPhone Safari 不显示改收栏</td>
<td>线上 Android UA(390×844 DPR3,无头)实测渲染:x334 y64 · 44×44 · 同顶栏钮皮(渐变 .9/.94、1px rgba(255,200,80,.5)、圆角 9.68、金 #ffd24a),在第二行、右缘齐记录钮(量的,截图见左);iPhone 不显示;path 串 7/7 款线上都带</td>
</tr>
<tr>
<td>来源 Source</td>
<td>shell.ts:40 + graphic-amg/skin/src/fit.ts:105-118(共用 HOME_CSS);style.css .ib .bd(被 fit.ts 覆盖)</td>
<td>代码件</td>
</tr>
</tbody>
</table></div>
<h2 id="p7">P7 · 余额胶囊 Balance capsule · Balance capsule (DEMO / name + balance) <code>BAL</code></h2>
<p><img loading="lazy" src="shots/chicken/piece-userbox.png" alt="chicken 140×48" /><br />
<img loading="lazy" src="shots/croc/piece-userbox.png" alt="croc 136.6×50.4" /><br />
<img loading="lazy" src="shots/wheel/piece-userbox.png" alt="wheel 140×56" /><br />
<img loading="lazy" src="shots/tower/piece-userbox.png" alt="tower 141.3×50.9" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>位置 Pos</td>
<td>x64 y12(4/4 款同)</td>
<td>量的</td>
</tr>
<tr>
<td>尺寸 Size(宽×高)</td>
<td>chicken 140×48 · croc 136.6×50.4 · wheel 140×56 · tower 141.3×50.9</td>
<td><strong>取 140×56(wheel 实测,总监 #1650 定 2026-10-23)</strong>;chicken/croc/tower 要改</td>
</tr>
<tr>
<td>底/边 Skin</td>
<td>玻璃渐变(令牌 .9/.9,第 2 页);边 1px rgba(255,200,80,.45);显示边宽:chicken 1 · wheel 1 · croc 0.47 · tower 0.94(推的:×0.471)</td>
<td>边宽取 1px(chicken、wheel 2/4)</td>
</tr>
<tr>
<td>圆角 Radius</td>
<td>显示值:chicken 10 · wheel 10 · croc 4.7 · tower 6.6(推的:croc CSS 10px、tower 14px ×0.471)</td>
<td>取 10px(2/4);croc/tower 偏小</td>
</tr>
<tr>
<td>阴影 Shadow</td>
<td>显示值各异:chicken 0 4 18 .45 · wheel 0 2 10 .5 · croc≈0 .9 4.7 · tower≈0 1.4 5.7(推的)</td>
<td><strong>取 0 2px 10px #00000080(wheel 实测,总监 #1650 定 2026-10-23)</strong>;croc/tower 的显示值已被舞台缩放缩小,要按 wheel 值出</td>
</tr>
<tr>
<td>名字行 Name</td>
<td>12.05px/600:chicken #f1dfae · croc=wheel rgba(255,220,150,.85) · tower 12.25px/700 rgba(255,226,160,.92)</td>
<td>取 croc=wheel(2/4):12.05/600 rgba(255,220,150,.85)</td>
</tr>
<tr>
<td>余额数 Value</td>
<td>800 · #ffd24a:chicken 16.0px · tower 16.0px · croc 14.1px · wheel 20.0px;千分位点</td>
<td><strong>取 20px/800(wheel 实测,总监 #1650 定 2026-10-23(r2:一律取 wheel))</strong>;chicken/croc/tower 要改</td>
</tr>
<tr>
<td>内边距 Padding</td>
<td>名字行 x79(距胶囊左 15)、y21;数值行 y35(chicken);其余款以截图为准</td>
<td>量的(chicken)</td>
</tr>
<tr>
<td>对比度 Contrast</td>
<td>余额金/玻璃 8.4–13.4:1;名字 rgba(255,220,150,.85)/玻璃 7.1–10.7:1</td>
<td>量的(玻璃合成色)</td>
</tr>
<tr>
<td>状态 States</td>
<td>无按下/禁用态(纯显示);名字=宿主 userName,宿主不给时 PLAYER;未取到余额显示「—」</td>
<td>shell.ts render()</td>
</tr>
<tr>
<td>来源 Source</td>
<td>shell.ts:38 (.userbox.glass);style.css .userbox;线上 CSS <a href="https://amg-kancilroad.pages.dev/assets/index-Bk4cNRm-.css">https://amg-kancilroad.pages.dev/assets/index-Bk4cNRm-.css</a></td>
<td>代码件</td>
</tr>
</tbody>
</table></div>
<h2 id="p8">P8 · 筹码 1K–500K + 选中环 · Chips 1K–500K + selected ring <code>HUD-CHIP-* · HUD-RING · CHIPROW</code></h2>
<p><img loading="lazy" src="pieces/_chips-sheet.png" alt="六张筹码原图(pieces/hud/imgCoins1–6.png,深色衬底只为看清,非画)" /><br />
<img loading="lazy" src="shots/chicken/piece-chips.png" alt="chicken 实拍:1K 选中 + 500K 禁用" /><br />
<img loading="lazy" src="shots/chicken/piece-chip-sel.png" alt="sel" /><br />
<img loading="lazy" src="shots/chicken/piece-chip-disabled.png" alt="cdis" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>面值/色序 Face/colour</td>
<td>1K 蓝 imgCoins1(a894815d)· 5K 绿(339aaef0)· 10K 青(fce4f3e4)· 50K 紫(49d5efc1)· 100K 红(1d22cb81)· 500K 灰(8679e0d0)</td>
<td>6 图字节各异(盘点「6 个全同」是指 5 款用同一批,不是筹码互同);5 款线上同档</td>
</tr>
<tr>
<td>原图 px Source px</td>
<td>178×186 · 179×189 · 178×186 · 178×188 · 180×188 · 178×188(原图像素,≠显示)</td>
<td>量的(PIL)</td>
</tr>
<tr>
<td>显示尺寸 Display</td>
<td>常态 48×50.7;选中 52.8×55.2(scale 1.1);tower 常态 48×48</td>
<td>取 48×50.7(chicken、croc、wheel 3/4)</td>
</tr>
<tr>
<td>间距 Pitch</td>
<td>中心距:chicken 53.0 · croc 52.7 · wheel 52.0 · tower 52.7</td>
<td>取 52.7(croc=tower 2/4)</td>
</tr>
<tr>
<td>面值字 Label</td>
<td>DOM <i>,居中叠在筹码上;font 800 12.05px,色 #fff(croc、wheel、tower);chicken rgba(255,255,255,.78);tower 字重 700</td>
<td>取 800/#fff(2~3/4)。<strong>面值=请求 bet=扣款,K/M 允许(Victor 10-10)</strong></td>
</tr>
<tr>
<td>选中 Selected</td>
<td>scale(1.1) + imgHighlight 环(241×241 px)盒 inset −8px,3s linear 无限自转;选中钮 z 在上</td>
<td>源码 CSS 实读;线上截图见左(chicken 1K)</td>
</tr>
<tr>
<td>禁用 Disabled</td>
<td>.cdis:img grayscale(1) brightness(.55)、字 opacity .55;整列局中变淡 .chips.off:opacity chicken .5 · croc .45 · wheel .45 · tower 另用 grayscale(1) brightness(.6) opacity .8</td>
<td>取 .45(croc=wheel 2/4);500K 在 demo 下为 cdis(实拍)</td>
</tr>
<tr>
<td>币径公式 Diameter</td>
<td>coinDiameterDesign:竖屏 48 css(=48×舞台宽/390);横屏 116 设计 px(舞台 1792);币面字号 chipFontDesign=max(12/scale, 横屏?26:0);CHIP_CSS 写死 .chips button{width:var(--coind)}</td>
<td>fit.ts:113 / :145-148(源码)</td>
</tr>
<tr>
<td>触控 Hit</td>
<td>≥48×50 css(满足 44)</td>
<td>量的</td>
</tr>
<tr>
<td>来源 Source</td>
<td>graphic-amg/skin/chicken/hud/imgCoins1-6.png + imgHighlight.png;shell.ts:47 / render();style.css .chips</td>
<td>图=原档(SHA=线上);叠字/选中/禁用=代码件</td>
</tr>
</tbody>
</table></div>
<h2 id="p9">P9 · PLAY 钮 · PLAY button <code>HUD-PLAY</code></h2>
<p><img loading="lazy" src="shots/chicken/piece-play.png" alt="idle(chicken)" /><br />
<img loading="lazy" src="shots/chicken/pressed-play.png" alt="pressed(chicken:无变化)" /><br />
<img loading="lazy" src="shots/wheel/pressed-play.png" alt="pressed(wheel:scale .93 + 亮 1.2)" /><br />
<img loading="lazy" src="shots/wheel/disabled-forced-play.png" alt="disabled(强设 disabled,渲染线上规则)" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>原图 Source</td>
<td>btnPlay.png 200×77 px,sha 57009998(5 款线上同档);图上带「PLAY」字(图内字),<strong>无 DOM 文字</strong></td>
<td>量的</td>
</tr>
<tr>
<td>显示高 Display h</td>
<td>chicken 56 · croc 56.5 · wheel 56 · tower 51.8</td>
<td>取 56(3/4)</td>
</tr>
<tr>
<td>显示宽 Display w</td>
<td>chicken 136 · croc 185.6 · wheel 216 · tower 134.2(background-size:contain,宽随版面)</td>
<td><strong>取 216(wheel 实测,总监 #1650 定 2026-10-23)</strong></td>
</tr>
<tr>
<td>位置 Pos</td>
<td>chicken x242 y670 · croc x193 y759 · wheel x162 y752 · tower x243 y715;距底:118 / 28 / 36 / 77</td>
<td><strong>取 wheel:PLAY x162 y752,距底 36,不留纯色垫底(总监 #1650 定 2026-10-23)</strong>;见第 19/20 页</td>
</tr>
<tr>
<td>禁用 Disabled</td>
<td>.imgbtn:disabled{filter:grayscale(.85) brightness(.7)}(chicken、croc、wheel;wheel 用 .play.off 同值);tower grayscale(1) brightness(.6)</td>
<td>取 grayscale(.85) brightness(.7)(3/4)</td>
</tr>
<tr>
<td>按下 Pressed</td>
<td>wheel scale(.93)+brightness(1.2);tower scale(.92)+brightness(1.25);chicken、croc 无按下变化</td>
<td><strong>取 scale(.93)+brightness(1.2)(wheel,总监 #1650 定 2026-10-23)</strong>;见第 18 页</td>
</tr>
<tr>
<td>触控 Hit</td>
<td>高 ≥44(51.8–56.5)</td>
<td>量的</td>
</tr>
<tr>
<td>来源 Source</td>
<td>graphic-amg/skin/chicken/hud/btnPlay.png;shell.ts:49 (button.imgbtn.play);style.css .imgbtn</td>
<td>图=原档</td>
</tr>
</tbody>
</table></div>
<h2 id="p10">P10 · 清除 / HAPUS 钮 · Clear (HAPUS) button <code>HUD-CLEAR</code></h2>
<p><img loading="lazy" src="shots/chicken/piece-clear.png" alt="idle(chicken)" /><br />
<img loading="lazy" src="shots/wheel/piece-clear.png" alt="wheel(同图)" /><br />
<img loading="lazy" src="shots/chicken/pressed-clear.png" alt="pressed(无变化)" /><br />
<img loading="lazy" src="shots/chicken/disabled-forced-clear.png" alt="disabled(强设)" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>原图 Source</td>
<td>btnClear.png 217×212 px,sha fc438457(5 款线上同档);图上无字</td>
<td>量的</td>
</tr>
<tr>
<td>显示尺寸 Display</td>
<td>58.5×58.5(4/4 款同)</td>
<td>量的</td>
</tr>
<tr>
<td>文字 Label</td>
<td>「HAPUS」DOM <span>:font 900,竖屏 12px,白,text-shadow 0 2px 3px #000,letter-spacing .04em;居中叠在图上</td>
<td>style.css .clear span(源码);截图可见</td>
</tr>
<tr>
<td>位置 Pos</td>
<td>chicken x177 y671 · croc x131 y758 · wheel x323 y651 · tower x328 y652(wheel/tower 与筹码同行,chicken/croc 在下一行)</td>
<td><strong>取 wheel 摆法:与筹码同行 x323 y651(总监 #1650 定 2026-10-23)</strong>;见第 20 页</td>
</tr>
<tr>
<td>禁用 Disabled</td>
<td>chicken filter grayscale(.85) brightness(.7);croc=wheel <code>.clear.imgbtn:disabled{filter:none;opacity:.5}</code>;tower grayscale(.5) brightness(.95) contrast(1.4) opacity .9</td>
<td>取 opacity .5(croc=wheel 2/4)</td>
</tr>
<tr>
<td>按下 Pressed</td>
<td>.clear:active:not(:disabled){filter:brightness(1.35)};.clear{transition:filter .08s};.clear span{color:#fff!important;font-weight:900;text-shadow:0 2px 3px #000;letter-spacing:0}</td>
<td>fit.ts:112 CLEAR_CSS(8 款里 7 款 bundle 带同串;四款实测吻合)</td>
</tr>
<tr>
<td>来源 Source</td>
<td>graphic-amg/skin/chicken/hud/btnClear.png;shell.ts:48</td>
<td>图=原档</td>
</tr>
</tbody>
</table></div>
<h2 id="p11">P11 · 总下注框 TOTAL TARUHAN · Total bet box <code>TOTAL</code></h2>
<p><img loading="lazy" src="shots/chicken/piece-totalbet.png" alt="chicken 150×72" /><br />
<img loading="lazy" src="shots/croc/piece-totalbet.png" alt="croc" /><br />
<img loading="lazy" src="shots/wheel/piece-totalbet.png" alt="wheel" /><br />
<img loading="lazy" src="shots/tower/piece-totalbet.png" alt="tower" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>尺寸 Size</td>
<td>chicken 150×72 · croc 118.7×56.5 · wheel 140×56 · tower 167.7×54.6</td>
<td><strong>取 140×56(wheel 实测,总监 #1650 定 2026-10-23)</strong></td>
</tr>
<tr>
<td>位置 Pos</td>
<td>左下:chicken x12 y664 · croc x11 y759 · wheel x12 y752 · tower x210 y591(与「PETAK」框同行)</td>
<td><strong>取 wheel 摆法:左下 x12 y752(总监 #1650 定 2026-10-23)</strong>;见第 20 页</td>
</tr>
<tr>
<td>底/边/角 Skin</td>
<td>玻璃渐变 .9/.9;1px rgba(255,200,80,.45);圆角 10(chicken、wheel;croc 显示 4.7、tower 6.6)</td>
<td>取圆角 10(2/4)</td>
</tr>
<tr>
<td>标签行 Label</td>
<td>「TOTAL TARUHAN」: chicken 12.1px/700 · croc 12.1px/800 · wheel 12.1px/800 · tower 未取到(显示值)</td>
<td>量的;色 chicken #e8d9a8</td>
</tr>
<tr>
<td>数值行 Value</td>
<td>chicken 22.0px/800 · croc 17.0px/800 · wheel 22.0px/800 · tower 未取到;白,千分位点,tabular-nums</td>
<td>量的(显示值)</td>
</tr>
<tr>
<td>错误态 Error</td>
<td>余额不足:边 #e14b4b、数字 #ffb4b4(chicken 源码 CSS .totalbet.err)</td>
<td>线上 demo 触发不了(余额 5,000,000),<strong>仅源码 CSS,未取线上截图</strong></td>
</tr>
<tr>
<td>对比度 Contrast</td>
<td>白数字/玻璃 12.1–19.3:1;错误红边/玻璃 4.28:1(非文字边)</td>
<td>量的</td>
</tr>
<tr>
<td>来源 Source</td>
<td>shell.ts:45 (#totalbet.totalbet.glass);style.css .totalbet;tower 用 .card.total 另一套 DOM</td>
<td>代码件</td>
</tr>
</tbody>
</table></div>
<h2 id="p12">P12 · 下注面板底 Bet panel base · Bet panel base (bottom sheet) <code>PANEL-BOTTOM</code></h2>
<p><img loading="lazy" src="shots/croc/piece-panel-base.png" alt="croc:顶圆角 28、高 283.5" /><br />
<img loading="lazy" src="shots/wheel/piece-panel-base.png" alt="wheel:直角、高 374" /><br />
<img loading="lazy" src="shots/chicken/bet-m390.png" alt="chicken:无面板底(底部留白 118)" /><br />
<img loading="lazy" src="shots/tower/bet-m390.png" alt="tower:无面板底" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>有无 Exists</td>
<td>croc 有 · wheel 有 · chicken 无 · tower 无</td>
<td><strong>取 有,直角(wheel,总监 #1650 定 2026-10-23)</strong>:y470 起 390×374,渐变 #2a1f12f7→#120d08fc、上边 2px rgba(255,200,80,.55)、阴影 0 -10px 30px #0009;croc 的圆角 28 要改直角;chicken/tower 要补</td>
</tr>
<tr>
<td>croc</td>
<td>x0 y560.5 · 390×283.5 · 渐变 · 圆角 28 28 0 0;box-shadow</td>
<td>线上 getBoundingClientRect(量的)</td>
</tr>
<tr>
<td>wheel</td>
<td>x0 y470 · 390×374 · linear-gradient(rgba(42,31,18,.97), rgba(18,13,8,.99)) · 圆角 0 · 阴影 rgba(0,0,0,.6) 0 −10 30</td>
<td>量的</td>
</tr>
<tr>
<td>实现 Impl</td>
<td>各款自己的 CSS(#panel / .panel),无 PNG 原件</td>
<td>无共用源码,列为「缺共用件」</td>
</tr>
<tr>
<td>与 Victor 令的关系</td>
<td>10-10 令「底部不准纯色垫底」:有面板底的款(croc、wheel)底部由面板铺满;chicken 竖屏最底 60px 条标准差 2.2(≈纯色)</td>
<td>盘点 #15;裁决见第 19 页</td>
</tr>
</tbody>
</table></div>
<h2 id="p13">P13 · 说明弹窗 Info (rules) popup · Info popup <code>PANEL-INFO</code></h2>
<p><img loading="lazy" src="shots/chicken/panel-info-m390.png" alt="chicken(TUTUP 全大写)" /><br />
<img loading="lazy" src="shots/wheel/panel-info-m390.png" alt="wheel(Tutup 首字大写)" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>面板 Panel</td>
<td>chicken:x24 y85 · 341.8×674 · padding 22/28 · 2px solid #ffd24a · 圆角 18 · linear-gradient(#b8956f → #61492e) · 阴影 0 10 40 rgba(0,0,0,.6)</td>
<td>量的;wheel 366×479(x12 y70,圆角 16,padding 16)、croc 329.7×206(圆角 16)</td>
</tr>
<tr>
<td>标题 Title</td>
<td>font 900,竖屏 24px,letter-spacing 1px,白 + text-shadow 0 2px 0 rgba(0,0,0,.4)(源码 CSS)</td>
<td>实读源码</td>
</tr>
<tr>
<td>正文 Body</td>
<td>font 500 17px/1.5 白;规则表:th 14px/800 #2a1b06,td 14px/700 白 on rgba(20,15,10,.55)</td>
<td>源码 CSS</td>
</tr>
<tr>
<td>关闭钮 Close pill</td>
<td>金胶囊「Tutup」:chicken 120×44、字 900 18px、#3a2605、2px #ffd24a、渐变 #ffe48a→#e0a52a 60%→#a87414、圆角 999;croc 109×45(字 30px×0.471)、wheel 126×46(字 20px)</td>
<td>量的</td>
</tr>
<tr>
<td><strong>TUTUP 大小写</strong></td>
<td>chicken=croc「TUTUP」全大写 · wheel=tower「Tutup」首字大写(四款均已量:tower 实测 Tutup)</td>
<td><strong>取 「Tutup」(wheel,总监 #1650 定 2026-10-23)</strong>;chicken/croc 要改</td>
</tr>
<tr>
<td>暗幕 Scrim</td>
<td>盖满整个视口 rgba(0,0,0,.55)(含延伸带)</td>
<td>源码 CSS r5 #49/#50</td>
</tr>
<tr>
<td>对比度 Contrast</td>
<td>正文白/面板:上沿 #b8956f <strong>2.78:1</strong>、下沿 #61492e 8.4:1;标题 #2a1b06/#b8956f 6.02:1;TUTUP #3a2605/金 3.54–11.45:1</td>
<td>量的。<strong>白字在面板上半部低于 AA 4.5:1,为线上现状,标准照取,列「要 Victor 拍」</strong></td>
</tr>
<tr>
<td>来源 Source</td>
<td>shell.ts:116-119(sheet===rules 段);style.css .popup/.popup.info/.go2;线上 CSS <a href="https://amg-kancilroad.pages.dev/assets/index-Bk4cNRm-.css">https://amg-kancilroad.pages.dev/assets/index-Bk4cNRm-.css</a></td>
<td>代码件</td>
</tr>
</tbody>
</table></div>
<h2 id="p14">P14 · 记录面板 History panel (RIWAYAT) · History panel <code>PANEL-HIST</code></h2>
<p><img loading="lazy" src="shots/chicken/panel-hist-m390.png" alt="chicken(空态)" /><br />
<img loading="lazy" src="shots/croc/panel-hist-m390.png" alt="croc(空态)" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>面板 Panel</td>
<td>x78 y64 · 300 宽(右缘距屏 12)· padding 12 · linear-gradient(rgb(40,30,18) → rgb(20,15,10)) · 1px rgba(255,200,80,.5) · 圆角 10(chicken、wheel;croc computed 2px/21.2px,×0.471=显示 0.94/10)</td>
<td>4/4 款位置同(量的)</td>
</tr>
<tr>
<td>标题 Title</td>
<td>RIWAYAT:h3 14px/800 #f1dfae,letter-spacing .1em</td>
<td>量的(chicken、wheel computed)</td>
</tr>
<tr>
<td>行 Rows</td>
<td>.r:display flex 两端对齐;font 600 13px;上缘 1px rgba(255,200,80,.2);padding 6px 0</td>
<td>源码 CSS</td>
</tr>
<tr>
<td>空态 Empty</td>
<td>「Belum ada riwayat…」(印尼文;en:No history yet)</td>
<td>线上实拍</td>
</tr>
<tr>
<td>有数据态 With data</td>
<td>线上 demo 无记录,<strong>未取有数据截图</strong>;行内容=时间/下注/结果/派彩(宿主 history.load)</td>
<td>未核实:有数据排版</td>
</tr>
<tr>
<td>来源 Source</td>
<td>shell.ts:121(sheet===history 段);style.css .hist</td>
<td>代码件</td>
</tr>
</tbody>
</table></div>
<h2 id="p15">P15 · 结算卡 / 赢钱弹窗 · Result card / win popup <code>WINPOP · WP-*</code></h2>
<p><img loading="lazy" src="pieces/_winparts-sheet.png" alt="11 个原图(pieces/winpopup/*@2x.png 等比缩小,深色衬底只为看清)" /><br />
<img loading="lazy" src="shots/chicken/win-t3.0.png" alt="chicken 实拍(+1.570)" /><br />
<img loading="lazy" src="shots/wheel/win-t5.0.png" alt="wheel 实拍(+2.500)" /><br />
<img loading="lazy" src="shots/croc/win-t3.0.png" alt="croc 实拍" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>件 Parts(11 个原图,@2x)</td>
<td>面板 9-slice 680×600 (7a014815) · 标题彩带 800×104 (651f9a56) · 金额牌 584×152 (6c44773f) · 奖杯台 360×44 (46b7de2f) · 英雄位(默认) 192×192 (96b1701e) · 光芒 1200×1200 (317db752) · 金币 56×56 (6e0ceaf1) · 飞行标记 80×80 (78776eba) · 彩纸精灵表 288×48 (0c47edf0) · 继续钮 340×96 (a4bec331) · 关闭钮 88×88 (9534129e)</td>
<td>6 款线上同档(每件 SHA 逐件相同,量的);batik-strip 线上未引用,不取</td>
</tr>
<tr>
<td>版式 Layout</td>
<td>layout.ts DIMS(面板宽,英雄槽,金额字号,彩带高):竖屏 small 320/88/34/44、big 340/104/42/46、mega 350/124/52/52;横屏 small 400/64/32/40、big 440/76/38/42、mega 470/88/44/46</td>
<td>源码 winpopup/src/layout.ts(与设计稿 layouts.json 对拍)</td>
</tr>
<tr>
<td>档 Tiers</td>
<td>small / big / mega(MEGA MENANG),同一张卡;<strong>赢才弹,输不弹</strong>(Victor 规则)</td>
<td>线上无输态弹窗件(缺,设计如此)</td>
</tr>
<tr>
<td>文案 Copy</td>
<td>「MENANG」「+金额」「2.50x · Net +1.500」「LANJUT」(印尼文);关闭 × 在右上</td>
<td>线上实拍</td>
</tr>
<tr>
<td>位置 Pos</td>
<td>屏幕正中弹出,面板水平居中;金额大字 + 派彩飞入余额</td>
<td>Victor 10-22 规则</td>
</tr>
<tr>
<td>对比度 Contrast</td>
<td>金额 #ffd24a/绿牌深绿(目视,未逐色量);LANJUT 钮同 TUTUP 3.54–11.45:1</td>
<td>推的/量的混合,金额对比度<strong>未逐色量</strong></td>
</tr>
<tr>
<td>来源 Source</td>
<td>graphic-amg/winpopup/src/{layout,view,parts}.ts + parts/*.png</td>
<td>PNG=原档;组装=代码件</td>
</tr>
</tbody>
</table></div>
<h2 id="p16">P16 · 错误卡 Error card V1 · Error card (V1: dark-brown) <code>ERRCARD</code></h2>
<p><img loading="lazy" src="shots/croc/err-net-m390.png" alt="croc:连不上(V1,取)" /><br />
<img loading="lazy" src="shots/chicken/err-net-m390.png" alt="chicken:藏青底(不取)" /><br />
<img loading="lazy" src="shots/croc/err-nosession-m390.png" alt="croc:无会话" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>版式 Layout</td>
<td>全屏居中:印尼文主句 17px/600 → 英文副句 13px/500(opacity .7)→ 金胶囊钮;容器 max-width 340;gap 14</td>
<td>量的(croc、wheel、tower 三款逐像素同:钮 x125.7 y457.8 138.6×48)</td>
</tr>
<tr>
<td>底色 Bg</td>
<td>V1 深棕 #120d08(croc、wheel、tower);chicken 藏青 #060a18</td>
<td><strong>取 V1(3/4)</strong>(盘点 #11)</td>
</tr>
<tr>
<td>字色 Text</td>
<td>#f1dfae;对比度 14.64:1(V1)/ 14.94:1(chicken)</td>
<td>量的</td>
</tr>
<tr>
<td>钮 Button</td>
<td>「Coba lagi」:高 48,padding 0 28,圆角 999,2px #ffd24a,渐变 #ffe48a→#e0a52a,字 900 17px #3a2605;对比度 6.57–11.45:1</td>
<td>量的</td>
</tr>
<tr>
<td>无会话态 No-session</td>
<td>V1:同卡,文案「Tidak ada sesi…」+ 英文副句 + 同钮(croc、wheel、tower);chicken 是单语 +「OK」钮(V2,不取)</td>
<td>线上实拍</td>
</tr>
<tr>
<td>来源 Source</td>
<td>games/{croc,wheel,tower}/graphic-amg/app-*/src/card.ts(三份逐行同,仅 import 不同);chicken 在 app-chicken/src/main.ts:30(藏青)</td>
<td>代码件,内联样式</td>
</tr>
</tbody>
</table></div>
<h2 id="p17">P17 · 载入页 Loading screen · Loading screen <code>LD-TRACK · LD-FILL · LD-KNOB · LOADBAR</code></h2>
<p><img loading="lazy" src="pieces/_loadparts-sheet.png" alt="条三件原图 bar-track / bar-fill / bar-knob(深色衬底)" /><br />
<img loading="lazy" src="shots/chicken/load-m390-b.png" alt="chicken(把手 08d6964d)" /><br />
<img loading="lazy" src="shots/croc/load-m390-b.png" alt="croc(把手 d5843c93)" /><br />
<img loading="lazy" src="shots/tower/load-m390-b.png" alt="tower(把手 cd97e0cd)" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>条三件 Bar parts</td>
<td>bar-track.png 1024×112(88b6463c)· bar-fill.png 1024×88(f08a022f)· bar-knob.png 192×192(08d6964d);轨/填充 7 款同档</td>
<td>量的;9-slice 帽 56/44(图 px)</td>
</tr>
<tr>
<td>把手 Knob</td>
<td>4 款 3 个版本:chicken=wheel(08d6964d)· tower(cd97e0cd)· croc(d5843c93,clay)</td>
<td><strong>取 08d6964d(2/4)</strong>(盘点 #12)</td>
</tr>
<tr>
<td>设计舞台 Stage</td>
<td>竖 828×1792、横 1792×828;轨框竖 72,1640,684×56(skin/loading.ts);桌面 ≥1024 宽:细条 360×6 居中</td>
<td>源码</td>
</tr>
<tr>
<td>文字 Label</td>
<td>「Memuat…」(印尼)+「N%」,Space Grotesk 700,色 #FFEBC2,描边 #2a1608 5px;桌面 14px</td>
<td>对比度 16.8:1(#FFEBC2/#060a18 暗带)</td>
</tr>
<tr>
<td>背景图 Backdrop</td>
<td>各款专属标题图(loading-port/land.webp),含底部暗带;<strong>不属标准件</strong>(每款各有个性,Victor 10-11)</td>
<td>不列入 SHA 判定</td>
</tr>
<tr>
<td>失败态 Failed</td>
<td>条隐藏,文字「Gagal memuat」+ 金边胶囊「Coba lagi」(88 高/44px)</td>
<td>源码 view.ts;线上载入失败态未取到截图</td>
</tr>
<tr>
<td>来源 Source</td>
<td>common/engine/src/loading/view.ts + graphic-amg/skin/src/loading.ts</td>
<td>代码件 + 原档</td>
</tr>
</tbody>
</table></div>
<h2 id="p18">P18 · 状态总表:按下 · 选中 · 禁用 · State table: pressed · selected · disabled <code>STATES</code></h2>
<div class="tw"><table>
<thead>
<tr>
<th>件 · 状态 Piece · state</th>
<th>chicken</th>
<th>croc</th>
<th>wheel</th>
<th>tower</th>
<th>判定 Verdict</th>
</tr>
</thead>
<tbody>
<tr>
<td>顶栏四钮 · 按下 pressed</td>
<td>brightness(1.35)+内凹阴影</td>
<td>同</td>
<td>同</td>
<td>同</td>
<td>取(4/4;fit.ts HOME_CSS :active;实测 mousedown 吻合)</td>
</tr>
<tr>
<td>CLEAR/HAPUS · 按下</td>
<td>brightness(1.35)</td>
<td>同</td>
<td>同</td>
<td>同</td>
<td>取(4/4;fit.ts CLEAR_CSS)</td>
</tr>
<tr>
<td>PLAY · 按下 pressed</td>
<td>无规则</td>
<td>无规则</td>
<td>scale .93 + brightness 1.2</td>
<td>scale .92 + brightness 1.25</td>
<td><strong>取 scale(.93)+brightness(1.2)(wheel,总监 #1650 定 2026-10-23);chicken/croc/tower 要加</strong></td>
</tr>
<tr>
<td>筹码 · 按下</td>
<td>无规则</td>
<td>无规则</td>
<td>无规则</td>
<td>无规则</td>
<td>取 无(4/4)</td>
</tr>
<tr>
<td>PLAY · 禁用 disabled</td>
<td>grayscale(.85) brightness(.7)</td>
<td>同(+cursor default)</td>
<td>同(.play.off)</td>
<td>grayscale(1) brightness(.6)(.play.off)</td>
<td>取 grayscale(.85) brightness(.7)(3/4)</td>
</tr>
<tr>
<td>CLEAR/HAPUS · 禁用 disabled</td>
<td>grayscale(.85) brightness(.7)(沿用 .imgbtn:disabled)</td>
<td>opacity .5(filter none)</td>
<td>opacity .5(filter none)</td>
<td>grayscale(.5) brightness(.95) contrast(1.4) opacity .9</td>
<td>取 opacity .5(croc=wheel 2/4)</td>
</tr>
<tr>
<td>PLAY · 请求中 pend(脉冲动画)</td>
<td>无</td>
<td>无</td>
<td>.play.pend:brightness 脉冲 .5s 往返(到 1.35)+金色 drop-shadow</td>
<td>同 wheel</td>
<td><strong>取 wheel:.play.pend 脉冲 .5s 往返(到 1.35)+金色 drop-shadow(总监 #1650 定 2026-10-23(r2:一律取 wheel));chicken/croc 要加</strong></td>
</tr>
<tr>
<td>筹码 · 选中 selected</td>
<td>scale 1.10 + 环</td>
<td>scale 1.10 + 环</td>
<td>scale 1.10 + 环</td>
<td>scale 1.10 + 环(chip.sel)</td>
<td>取(4/4,量的:选中 52.8×55.2 vs 常态 48×50.7)</td>
</tr>
<tr>
<td>筹码 · 禁用 .cdis</td>
<td>grayscale(1) brightness(.55)</td>
<td>同</td>
<td>同</td>
<td>同(tower 常态 48×48)</td>
<td>取(500K 在 demo 余额下实拍为 cdis)</td>
</tr>
<tr>
<td>筹码列 · 局中 .chips.off</td>
<td>opacity .5</td>
<td>opacity .45</td>
<td>opacity .45</td>
<td>grayscale(1) brightness(.6) opacity .8</td>
<td>取 .45(croc=wheel)</td>
</tr>
<tr>
<td>总下注框 · 错误 err</td>
<td>边 #e14b4b / 数字 #ffb4b4(源码)</td>
<td>未核</td>
<td>未核</td>
<td>未核</td>
<td>部分:仅 chicken 源码 CSS,线上未触发</td>
</tr>
</tbody>
</table></div>
<blockquote>
<p>本页数值读自线上 CSS/注入样式(grep 实读 + fit.ts 源码),并用真 mousedown 实测交叉验证(PLAY 在 wheel/tower 的 scale 与规则吻合;注意 wheel/tower 的 PLAY 在 pend 态有脉冲动画,mousedown 取样可能混入动画帧,所以以规则为准)。禁用态截图是把 disabled 属性强设后渲染线上规则(shots/&lt;款&gt;/disabled-forced-*.png),因 demo 下 PLAY/CLEAR 不会自然进入禁用态。</p>
</blockquote>
<h2 id="p19">P19 · 差异裁决表 · Decision table <code>DECISIONS</code></h2>
<div class="tw"><table>
<thead>
<tr>
<th># 项 Item</th>
<th>chicken</th>
<th>croc</th>
<th>wheel</th>
<th>tower</th>
<th>判定 Verdict(多数款;原未定项=总监 #1650 定,一律取 wheel 实测)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>票内 5 项</strong> 1 · 余额胶囊尺寸(盘点 #3)</td>
<td>140×48</td>
<td>136.6×50.4</td>
<td>140×56</td>
<td>141.3×50.9</td>
<td><strong>取 140×56(wheel,总监 #1650 定 2026-10-23)</strong></td>
</tr>
<tr>
<td>2 · 说明弹窗关闭钮大小写(#8)</td>
<td>TUTUP</td>
<td>TUTUP</td>
<td>Tutup</td>
<td>Tutup</td>
<td><strong>取 「Tutup」(wheel,总监 #1650 定 2026-10-23)</strong></td>
</tr>
<tr>
<td>3 · 错误卡底色(#11)</td>
<td>藏青 #060a18</td>
<td>深棕 #120d08</td>
<td>深棕 #120d08</td>
<td>深棕 #120d08</td>
<td><strong>取深棕 V1(3/4)</strong></td>
</tr>
<tr>
<td>4 · 载入把手(#12)</td>
<td>08d6964d</td>
<td>d5843c93</td>
<td>08d6964d</td>
<td>cd97e0cd</td>
<td><strong>取 08d6964d(2/4,第一名唯一)</strong></td>
</tr>
<tr>
<td>5 · 竖屏底部留白(#15)</td>
<td>最底 60px 条标准差 2.2(≈纯色;盘点 DPR2 量的,其余款 6.8–67.7);本版 DPR3 实拍 PLAY 距底 118</td>
<td>距底 28</td>
<td>距底 36</td>
<td>距底 77</td>
<td><strong>取 wheel:PLAY 距底 36;不留纯色垫底(3/4 多数)(总监 #1650 定 2026-10-23)</strong></td>
</tr>
<tr>
<td><strong>票外新发现</strong> 6 · 玻璃令牌 glass1/glass2/line</td>
<td>.88/.92/.45</td>
<td>.9/.9/.45</td>
<td>.9/.9/.45</td>
<td>.92/.92/.5</td>
<td><strong>取 .9/.9/.45(croc=wheel,2/4)</strong>;chicken、tower 要改</td>
</tr>
<tr>
<td>7 · .glass CSS 写法(渐变/边/圆角/阴影)</td>
<td>无 180deg;阴影 0 4 18 #00000073</td>
<td>180deg;阴影 0 2 10 #00000080</td>
<td>同 croc</td>
<td>tower 无 .glass(用 .card)</td>
<td>CSS 写法取 croc=wheel(FRAG-GLASS);<strong>显示阴影取 wheel 的 0 2px 10px #00000080(总监 #1650 定 2026-10-23)</strong></td>
</tr>
<tr>
<td>8 · 顶栏四钮(位置/尺寸/渐变/边/圆角/阴影)</td>
<td>同</td>
<td>同</td>
<td>同</td>
<td>同</td>
<td><strong>取(4/4 全同,量的)</strong></td>
</tr>
<tr>
<td>9 · 筹码/清除 显示尺寸</td>
<td>48×50.7;58.5</td>
<td>同</td>
<td>同</td>
<td>常态 48×48;58.5</td>
<td>取(筹码 3/4;清除 4/4)</td>
</tr>
<tr>
<td>10 · PLAY 显示高/宽</td>
<td>56/136</td>
<td>56.5/185.6</td>
<td>56/216</td>
<td>51.8/134.2</td>
<td><strong>取 216×56(wheel;高 56 亦 3/4 多数)(总监 #1650 定 2026-10-23)</strong></td>
</tr>
<tr>
<td>11 · PLAY 按下态</td>
<td>无</td>
<td>无</td>
<td>scale .93 + 亮 1.2</td>
<td>scale .92 + 亮 1.25</td>
<td><strong>取 scale(.93)+brightness(1.2)(wheel,总监 #1650 定 2026-10-23)</strong></td>
</tr>
<tr>
<td>12 · 下注面板底</td>
<td>无</td>
<td>有(圆角 28)</td>
<td>有(直角)</td>
<td>无</td>
<td><strong>取 有,直角(wheel,总监 #1650 定 2026-10-23)</strong></td>
</tr>
<tr>
<td>13 · 总下注框/余额数字号/位置</td>
<td>150×72</td>
<td>118.7×56.5</td>
<td>140×56</td>
<td>167.7×54.6</td>
<td><strong>总框取 140×56(wheel,总监 #1650 定 2026-10-23)</strong>;<strong>余额数取 20px(wheel 实测,总监 #1650 定 2026-10-23(r2:一律取 wheel))</strong>;横屏余额/总框照 P21 实测</td>
</tr>
<tr>
<td>14 · 余额圆角(显示)</td>
<td>10</td>
<td>4.7</td>
<td>10</td>
<td>6.6</td>
<td>取 10(2/4)</td>
</tr>
<tr>
<td>15 · 面值字重/色</td>
<td>800/白.78</td>
<td>800/白</td>
<td>800/白</td>
<td>700/白</td>
<td>取 800/白(croc=wheel)</td>
</tr>
</tbody>
</table></div>
<blockquote>
<p>票述「5 项小差」在 1–5 行;6–15 行是本次实测另发现的差异,按同一规则处理(取最多款;并列/各异=未定,不擅定)。croc/tower 的显示值=computed×0.471(推的),其余为量的。<strong>原「未定」项(1、2、5、7、10、11、12、13 + P20 摆法参考)已由总监 #1650(Victor 授权)一律取 wheel 实测值定案,裁决正本 reports/amg-ui-decisions-1650-20261023.md;改完全部界面逐张给 Victor 过目、点头才上。</strong></p>
</blockquote>
<h2 id="p20">P20 · 摆法图 · 直立 390×844 · Placement · portrait <code>LAYOUT</code></h2>
<p><img loading="lazy" src="layout/portrait.png" alt="Placement · portrait:线上 wheel 实机 DOM,隐藏玩法本体,只留标准零件;编号=下表" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 · Home → TB-HOME</td>
<td>x12 y12 · 44×44</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>2 · 余额胶囊 Balance → BAL</td>
<td>x64 y12 · 140×56</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>3 · 说明 i → TB-INFO</td>
<td>x208 y12 · 44×44</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>4 · 声音 Sound → TB-SOUND</td>
<td>x260 y12 · 44×44</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>5 · 记录 History → TB-HIST</td>
<td>x312 y12 · 66×44</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>6 · 筹码列 Chips → CHIPROW + HUD-CHIP-* + HUD-RING</td>
<td>x10 y656 · 308×48</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>7 · 总下注 Total → TOTAL</td>
<td>x12 y752 · 140×56</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>8 · 清除 HAPUS → HUD-CLEAR</td>
<td>x323 y651 · 58×58</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>9 · PLAY → HUD-PLAY</td>
<td>x162 y752 · 216×56</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>10 · 下注面板底 Panel → PANEL-BOTTOM</td>
<td>x0 y470 · 390×374(直角,深棕渐变,上边 2px 金)</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>已定 Decided</td>
<td>参考排法=wheel;距底 36;面板底有且直角</td>
<td>总监 #1650 定 2026-10-23</td>
</tr>
<tr>
<td>确定 Fixed</td>
<td>顶栏五件(Home x12 / 余额 x64 / i x208 / 声音 x260 / 记录 x312,y12)四款完全相同;筹码 48×50.7、清除 58.5×58.5</td>
<td>4/4 款同</td>
</tr>
</tbody>
</table></div>
<blockquote>
<p>线上 wheel 实机渲染(隐藏玩法控件、中性灰底),零件是线上原件,非重画。参考由 croc 改 wheel(总监 #1650 定 2026-10-23)。</p>
</blockquote>
<h2 id="p21">P21 · 摆法图 · 横屏 844×390 · Placement · landscape <code>LAYOUT</code></h2>
<p><img loading="lazy" src="layout/landscape.png" alt="Placement · landscape:线上 wheel 实机 DOM,隐藏玩法本体,只留标准零件;编号=下表" /></p>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 · Home → TB-HOME</td>
<td>x12 y12 · 44×44</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>2 · 余额胶囊 Balance → BAL</td>
<td>x64 y12 · 118×53</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>3 · 说明 i → TB-INFO</td>
<td>x662 y12 · 44×44</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>4 · 声音 Sound → TB-SOUND</td>
<td>x714 y12 · 44×44</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>5 · 记录 History → TB-HIST</td>
<td>x766 y12 · 66×44</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>6 · 筹码列 Chips → CHIPROW + HUD-CHIP-* + HUD-RING</td>
<td>x169 y329 · 507×55</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>7 · 总下注 Total → TOTAL</td>
<td>x13 y333 · 123×51</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>8 · 清除 HAPUS → HUD-CLEAR</td>
<td>x779 y265 · 58×58</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>9 · PLAY → HUD-PLAY</td>
<td>x728 y335 · 110×45</td>
<td>wheel 实机 DOM(量的)</td>
</tr>
<tr>
<td>说明 Note</td>
<td>wheel 有横屏版,以其实测为准(量的);横屏无面板底;余额/总框/PLAY 在横屏的显示尺寸小于直立</td>
<td>目视+量的</td>
</tr>
<tr>
<td>同套零件 Same set</td>
<td>与直立页是同一批件(同 PIECES id);只是摆法不同,不算两套</td>
<td>Victor 10-23 令</td>
</tr>
</tbody>
</table></div>
<blockquote>
<p>同上;横屏。</p>
</blockquote>
<h2 id="p22">P22 · 缺件 · 未核实 · 不取 · Missing · unverified · not taken <code>MISSING</code></h2>
<div class="tw"><table>
<thead>
<tr>
<th># 件 Piece</th>
<th>状态 Status</th>
<th>说明 Detail</th>
<th>处置 Handling</th>
</tr>
</thead>
<tbody>
<tr>
<td>WP-batik-strip 赢钱弹窗·<a href="mailto:batik-strip@2x.png">batik-strip@2x.png</a></td>
<td>缺(线上未引用,不取)</td>
<td>源码包 graphic-amg/winpopup/parts/ 有此档,但线上 8 款的 CSS/JS 都没引用(sha-live-assets.csv 无此名);规则:源码件仅 SHA 与线上一致才取</td>
<td>不补画、不 AI 生成;要新件须先问 Victor</td>
</tr>
<tr>
<td>LOSE-POPUP 输态结算弹窗</td>
<td>缺(设计如此)</td>
<td>Victor 规则:输钱不弹窗;线上也没有该件,不补画</td>
<td>不补画、不 AI 生成;要新件须先问 Victor</td>
</tr>
<tr>
<td>PANEL-BOTTOM 下注面板底(底部玻璃抽屉)</td>
<td>已定(总监 #1650 取 wheel)</td>
<td>croc、wheel 有深棕面板底(croc 顶圆角 28、h283;wheel 直角、h374),chicken、tower 没有 → 总监 #1650 定 2026-10-23:取 wheel(有,直角,y470 起 390×374);实现是各款自己的 CSS(.panel),无 PNG</td>
<td>不补画、不 AI 生成;要新件须先问 Victor</td>
</tr>
<tr>
<td>FISH-ROOM fishshoot 房内 HUD/下注/结算</td>
<td>未核实</td>
<td>线上包无 demo 开关,房内需真后端会话;选房页/载入页是藏青+金另一套,不当深棕玻璃件取;不补画</td>
<td>不补画、不 AI 生成;要新件须先问 Victor</td>
</tr>
<tr>
<td>ERR-STATES 错误卡其它版本(V2 藏青单语+OK / V3 crash 浅棕绿钮 / V4 fishshoot)</td>
<td>不取</td>
<td>不属多数版(V1 深棕 3/4)</td>
<td>不补画、不 AI 生成;要新件须先问 Victor</td>
</tr>
<tr>
<td>TOTAL-ERR 总下注框「余额不足」态</td>
<td>部分(仅源码 CSS)</td>
<td>style.css .totalbet.err 有规则;线上 demo 余额 5,000,000 触发不了,未取到线上截图</td>
<td>不补画、不 AI 生成;要新件须先问 Victor</td>
</tr>
<tr>
<td>PRESS-STATE PLAY 按下态(顶栏钮/CLEAR 按下态四款同=brightness(1.35),已入标准)</td>
<td>已定(总监 #1650 取 wheel)</td>
<td>线上 wheel/tower 有 :active scale(.93/.92)+brightness(1.2/1.25),chicken/croc 无 → 总监 #1650 定 2026-10-23:取 wheel scale(.93)+brightness(1.2)(FRAG-PLAY-PRESS);见 STANDARD 状态总表(第 18 页)</td>
<td>不补画、不 AI 生成;要新件须先问 Victor</td>
</tr>
<tr>
<td>FSBTN 全屏钮(线上渲染)</td>
<td>取到(线上渲染,Android UA 无头)</td>
<td>线上 chicken Android UA 390×844 DPR3:钮 x334 y64 44×44,底 linear-gradient(rgba(40, 30, 18, 0.9), rgba(20, 15, 10, 0.94)),边 1px solid rgba(255, 200, 80, 0.5),圆角 9.68px,色 rgb(255, 210, 74)(量的;截图 shots/chicken/android-bet-m390.png)</td>
<td>iPhone 不显示(设计如此);不补画</td>
</tr>
<tr>
<td>折叠 1812×2176 / iPad 1024×1366 / 桌面 1920×1080 实拍</td>
<td>未重拍</td>
<td>旧盘点为 DPR1 截图,不冒称符合家规;顶栏钮边长按 fit.ts 公式推为 72(推的);其它件(筹码/PLAY/总框)在桌面/iPad 的位置未在本版重量</td>
<td>派下一轮实拍</td>
</tr>
<tr>
<td>真 token 会话下的状态(真余额/真历史/真赢钱金额)</td>
<td>未核实</td>
<td>不登入后台;demo 数字是 mock,UI 件是线上真件</td>
<td>—</td>
</tr>
<tr>
<td>记录面板有数据态</td>
<td>未核实</td>
<td>demo 无记录</td>
<td>—</td>
</tr>
<tr>
<td>载入失败态(Gagal memuat)</td>
<td>仅源码</td>
<td>线上未触发</td>
<td>—</td>
</tr>
<tr>
<td>MEGA 档赢钱弹窗(大赢)线上渲染</td>
<td>部分</td>
<td>源码 DIMS 有 big/mega;plinko、catfish 实拍到 MEGA MENANG(同卡),chicken/croc/tower/wheel 只拍到小档</td>
<td>—</td>
</tr>
<tr>
<td>赢后结果条「ANDA MENANG +金额」</td>
<td>已定:取 wheel(有)</td>
<td>弹窗关掉后 wheel 底部多一条结果条(wheel t8 实拍;catfish 亦有),chicken、croc、tower 没有 → 总监 #1650 定 2026-10-23(r2:一律取 wheel):取 wheel,即标准含此结果条;chicken/croc/tower 要补(样式照 wheel shots/wheel/win-t8.0.png)</td>
<td>shots/wheel/win-t8.0.png</td>
</tr>
</tbody>
</table></div>
<h2 id="p23">P23 · 验收规则 + check-conformance · Acceptance rule + check-conformance <code>RULE</code></h2>
<div class="tw"><table>
<thead>
<tr>
<th>项目 Item</th>
<th>规格 Spec(量的,390×844 DPR3 headless Chromium,除注明)</th>
<th>状态 / 来源 Status · Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>规则 Rule</td>
<td>改完后每款游戏的每个标准零件必须与 PIECES.csv 的 SHA256 <strong>完全相同</strong>(逐档比对,不是目视);一款差几件由脚本数出来</td>
<td>Victor 2026-10-23 追令</td>
</tr>
<tr>
<td>范围 Scope</td>
<td>PIECES.csv 中 required=Y 的 25 个图/字件(逐档 SHA);另加 11 个代码件片段(令牌/.glass 的规范化 CSS 与 9 条 SVG path 串);--render 再加显示值(顶栏四钮位置/尺寸/底/边/圆角/色,余额/总框 140×56+阴影,筹码,清除,PLAY 216×56 距底 36,面板底,说明弹窗关闭钮「Tutup」)与 1 个按下态片段 FRAG-PLAY-PRESS</td>
<td>#1650 已定项的阈值已同步进 pieces/code/render-spec.json 与 fragments.json;仍「未定」件不进判定</td>
</tr>
<tr>
<td>脚本 Script</td>
<td>(internal)(Python3 标准库,只读;只做 GET,不写任何档,除非 --json)</td>
<td></td>
</tr>
<tr>
<td>输入 Input</td>
<td>目录(dist/ 或源码树)· .zip · 线上 URL(只 GET)· --each 父目录(每个子目录当一款)</td>
<td>构建哈希文件名无关,按内容 SHA 比</td>
</tr>
<tr>
<td>输出 Output</td>
<td>每款:图/字件 N/25 相同、差几件;逐件 PASS / DIFF(同名不同 SHA)/ MISSING;代码件片段 PASS/DIFF/MISSING;汇总每款差几件;退出码 0=全过 1=有差 2=读不到</td>
<td>--quiet 只印汇总;--json out.json 另存</td>
</tr>
<tr>
<td>渲染比对 Render(代码件)</td>
<td>--render:对 URL 用无头 Chromium(demo 模式,浏览器内 mock,不联网写)量 390×844 下显示值,对 render-spec.json;croc/tower 的舞台缩放自动换算(按 .ib.home 字号)。<strong>为什么要它</strong>:8 款 bundle 都带同一份共用 HUD CSS(fit.ts),字串比对全过,但 plinko/catfish 的奶油皮是后覆盖的——只有量显示值才抓得到</td>
<td>需要 python playwright;没装就跳过这一项</td>
</tr>
<tr>
<td>用法 Usage</td>
<td>./check-conformance [--render] <a href="https://amg-kancilroad.pages.dev">https://amg-kancilroad.pages.dev</a> <a href="https://amg-komodo.pages.dev">https://amg-komodo.pages.dev</a> …(结果见 measure/conformance-live-8*.txt/json)</td>
<td>每次改动(含 AMG 自己改)都跑</td>
</tr>
<tr>
<td>基线 Baseline(#1650 后,线上 4 款,量的)</td>
<td>(#1650 后,含显示值,线上四款)chicken 差 9 · croc 差 7 · wheel 差 0 · tower 差 9</td>
<td>measure/conformance-after-1650-r2.json/.txt(含显示值);改前 8 站基线见 measure/conformance-live-8*.json;赛马 kit v4 差 23、赛车 kit v2f 差 6(图/字件,measure/conformance-kits.json)</td>
</tr>
<tr>
<td>计数口径 Counting</td>
<td>脚本汇总的「差 N 件」按检查项计(同一 id 的图/字 SHA、片段、显示值各算 1 项);DIFF-TO-ADOPT.md 的换件数按 PIECES.csv id 去重计。标准四款自己也有差(#1650 后检查项:wheel 0 · croc 7 · chicken 9 · tower 9;按 id 去重:0 / 6 / 7 / 7 件;wheel 0 差(余额数字标准=20px,#1650 r2)),要一起改才算「一模一样」</td>
<td>见 DIFF-TO-ADOPT.md 末尾「标准四款自己也要对齐」</td>
</tr>
<tr>
<td>变更记录 Change log</td>
<td>v2 · 2026-10-23 · 总监 #1650(Victor 授权)定:原 P19「未定/并列」项(1 余额胶囊 140×56、2 关闭钮 Tutup、5 PLAY 距底 36、7 阴影 0 2 10 #00000080、10 PLAY 216×56、11 PLAY 按下 scale(.93)+brightness(1.2)、12 面板底有且直角、13 总下注框 140×56)。r2(同日总监补裁):余额数字 20px、P18 PLAY pend 脉冲、赢后结果条同取 wheel与 P20/P21 摆法参考一律取 wheel 实测;check-conformance 阈值与 DIFF-TO-ADOPT 件数同步;版本仍 v2。</td>
<td>STANDARD.md 末尾同句</td>
</tr>
<tr>
<td>谁判「通过」 Who passes</td>
<td>全部 PASS 才算「一模一样」;任何 DIFF/MISSING 都要换件(换成 PIECES.csv 的原档),不准重画</td>
<td>版本固定 v2 一个正本;改标准先问 Victor</td>
</tr>
</tbody>
</table></div>
<blockquote>
<p><strong>变更记录</strong>:v2 · 2026-10-23 · 总监 #1650(Victor 授权)定:原 P19「未定/并列」项(1 余额胶囊 140×56、2 关闭钮 Tutup、5 PLAY 距底 36、7 阴影 0 2 10 #00000080、10 PLAY 216×56、11 PLAY 按下 scale(.93)+brightness(1.2)、12 面板底有且直角、13 总下注框 140×56)与 P20/P21 摆法参考一律取 wheel 实测;r2(同日总监补裁):余额数字 20px、PLAY pend 脉冲、赢后结果条同取 wheel;check-conformance 阈值与 DIFF-TO-ADOPT 件数同步;版本仍 v2。</p>
</blockquote>
<h2 id="p24">P24 · 动画必备五类 · Required animation set <code>ANIM</code>(Victor 2026-10-25 22:15 令)</h2>
<blockquote>
<p>Victor:「不是要一模一样的动画,但是都要有这些动画。」每款 AMG 游戏<strong>五类都要有</strong>,做法各款自定;<strong>缺任一类不算过标准</strong>。参考做法与节拍 = Mines AMG 包 <code>(internal)</code> + <code>preview-amg-mines-anim.mp4</code>(Victor 10-25「动画做得很好」)。</p>
</blockquote>
<div class="tw"><table>
<thead>
<tr>
<th>类 Class</th>
<th>必须有什么 Must have</th>
<th>量的验收 Measurable acceptance</th>
</tr>
</thead>
<tbody>
<tr>
<td>① 进场 Entrance</td>
<td>loading 满 → 背景推入/去模糊 → <strong>名字 logo 弹入 + 一次金光扫</strong> → 场面元素(格/盘/道/鱼)依序落位 → 控件淡入;logo 为独立件(P17 载入页也带 logo)</td>
<td>loading 结束到可操作 ≤3.5s;元素落位总时长 ≤0.9s;logo 出现 ≥1.0s 后才允许点 PLAY</td>
</tr>
<tr>
<td>② 主动作反馈 Action feedback</td>
<td>玩家每次下注/翻格/发射/转动有即时反馈:弹出/缩放/闪光 + ≥7 颗粒子或等效光效;倍率/金额数字<strong>滚动</strong>而非跳变</td>
<td>点下到首帧反馈 ≤80ms;数字滚动 300–600ms;连点不丢帧(≥55fps,量的)</td>
</tr>
<tr>
<td>③ 失败/爆点 Lose · bust</td>
<td>失败有「预告→爆发→余波」三段(例:引线闪→爆炸帧→屏震 + 暗角 + 邻近元素被推开);其余隐藏项随后由近到远揭示</td>
<td>预告 ≥120ms;爆发帧 ≥6 帧;屏震幅 8–14px 且 ≤450ms;揭示总时长 ≤1.2s</td>
</tr>
<tr>
<td>④ 收钱/庆祝 Win · cashout</td>
<td>金额脉冲 + 已赢元素轮闪 + 喷泉/飘落(金币/宝石/星屑 ≥3 种) + 结算卡入场(P15 卡本体不改,只加入场与数字滚动)</td>
<td>粒子 ≥60 颗;庆祝 1.2–2.5s;结算卡入场 ≤400ms;大奖(≥50× <strong>或封顶且派彩 ≥ 本金</strong>)有加长版 ≥3s;封顶但派彩 &lt; 本金(例 0.66× 被封)走 ③ 失败段,不庆祝(10-26 04:0x 总监裁)</td>
</tr>
<tr>
<td>⑤ 待机 Idle</td>
<td>画面不死:元素呼吸/金光扫过/余烬或环境粒子;PLAY 钮呼吸(沿 P9 pend 脉冲);有吉祥物位的款留位</td>
<td>任意 3 秒内 ≥1 处像素在动;CPU 待机 &lt;15%(量的,Safari 手机)</td>
</tr>
</tbody>
</table></div>
<div class="tw"><table>
<thead>
<tr>
<th>规则 Rule</th>
<th>规格 Spec</th>
</tr>
</thead>
<tbody>
<tr>
<td>技术 Tech</td>
<td>Pixi/DOM 精灵图集 + 时间线脚本或 Rive 皆可;新增件(动画/特效件)合计 ≤1.5MB/款;皮肤本体不计入此项,REPORT 另列「皮肤总量」对照同类款整包(10-26 Topo 裁:Topo 整包 4.7MB vs mines 8.9MB 收);粒子/数字滚动用数值驱动</td>
</tr>
<tr>
<td>交付 Deliverables</td>
<td>每款:<code>TIMING.md</code>(状态名、触发、时长、层序)+ 20s 预览 mp4(真皮件合成,非示意)+ look-weird 抽 3 帧 NONE;接线后再录一次真机 20s</td>
</tr>
<tr>
<td>自动局/连发 Auto</td>
<td>有自动局/连发的款:间隔随局数加速(例 650→230ms),下一目标先出预告框,STOP 有压缩 + 冲击环</td>
</tr>
<tr>
<td>音效 Sound(<strong>必备</strong>,Victor 2026-10-26 00:3x 令「全部游戏一定要加声音」)</td>
<td>每款交声音包(BGM 循环、按钮、主动作、失败爆点、收钱、大奖、待机环境音),按节拍表钉点对拍;响度 −16 LUFS ±2、循环无缝、档案 ≤1.5MB/款、授权干净;声音钮(P5)真的开/关;<strong>没有声音包不算过标准</strong></td>
</tr>
<tr>
<td>已上线各款 Retrofit</td>
<td>horse/plinko/catfish 已标准化版 + chicken/croc/wheel/tower/crash 逐款补齐五类;次序照 <code>(internal)</code>、总监排程;补完才在 DIFF-TO-ADOPT.md 记「ANIM ✅」</td>
</tr>
<tr>
<td>谁判 Who passes</td>
<td>总监按本表逐项量(mp4 抽帧 + 节拍表数字);任一类缺 = 不过;与 P23 零件 SHA 规则并列,两者都过才算「符合 AMG 标准 v2」</td>
</tr>
</tbody>
</table></div>
<blockquote>
<p>变更记录:P24 · 2026-10-25 22:17 · 总监依 Victor 令新增;v2 版本号不变(追加页)。</p>
</blockquote>
<h2>10-26 10:0x Victor 追加三条(P25–P27,必备)</h2>
<ul>
<li id="p25"><strong>P25 iPhone Duo 适配</strong>:AMG 全款必须在 iPhone Duo 内屏(≈669×951 pt 直/横)、外屏(≈610×850 直/横)四态正常:游戏主体居中、遮罩全屏、壳不重叠、字可读;goalshoot 10-24 已过,其余 9 款逐款补。</li>
<li id="p26"><strong>P26 声音钮首按即响</strong>:第一次点击声音钮必须立刻出声(用那一次手势 resume AudioContext + 已解码件即播;未解码件先播最短 UI 音再补载),钮态即时切换;不准出现「按多次才响」(Victor 10-26 实测)。</li>
<li id="p27"><strong>P27 home/返回钮必须有动作</strong>:优先 <code>returnUrl</code>/<code>lobby</code> 查询参数(AMG 启动时带),其次 <code>history.back()</code>(有来源页),再其次 <code>https://amglobby.pages.dev/</code>;点了 300 ms 内要有可见反应(按钮按下态/转场)。</li>
<li><strong>P26 补注(10-26 10:0x 总监裁)</strong>:进页为「有声」态但 AudioContext 仍 suspended 时,页面上首个任意手势要 resume 并起 BGM;此时 ♪ 第一下视为「开声」(resume+播),不是关声;只有实际出声中按 ♪ 才是关声。钮态=实际可听状态。</li>
<li><strong>P26 补注二(Victor 10-26 11:4x)</strong>:<strong>所有音效/BGM 在 loading 画面阶段就全部加载并解码完(decodeAudioData 不需要手势)</strong>,loading 条走完 = 声音已就绪;♪ 第一下只做 resume + 出声(确认音用真实音效,不是因为没解码而合成 blip);不准等到点声音钮才去加载。</li>
</ul>
<h2>补注四(总监 10-26 11:3x,Sol r3 三款同型 FAIL 后定:「开声状态机」,所有款照这个做,不准各自猜)</h2>
<p>Sol r3 把 mines/tower/wheel 的 v2 全退回,三款败在同一件事:<strong>「实际可听状态」没有一个唯一、随真实播放结果更新的状态源</strong>。以下是唯一正确模型,实作与测试都照它:</p>
<p>状态 <code>soundState ∈ {locked, opening, audible, muted}</code>,<strong>唯一来源</strong>(一个模块持有,壳/按钮/BGM/预载全部订阅它,不准各自再存一份 <code>isMuted</code>/<code>opened</code>/<code>heard</code> 当判断依据):</p>
<ul>
<li><code>locked</code>:AudioContext suspended 或从未真正出过声(页面刚进、resume 没成功过)。用户偏好 <code>prefMuted</code>(localStorage)只是偏好,<strong>不是状态</strong>。</li>
<li><code>opening</code>:某个手势已在同步栈内调了 <code>ctx.resume()</code> + 已排入确认音/BGM,但 resume 的 promise 还没落定。</li>
<li><code>audible</code>:resume 已 resolve 且 ctx.state==='running',且确认音或 BGM 已 <code>start()</code>。</li>
<li><code>muted</code>:用户在 <code>audible</code> 下按 ♪ 关掉(gain=0 / BGM 停),<code>prefMuted=true</code>。</li>
</ul>
<p>转移(全部要有测试,每条一个 case):</p>
<ol type="1">
<li><strong>任意元素的首个手势</strong>(pointerdown/click/touchend,页面级一次性监听)在 <code>locked</code> → 同步栈内 <code>resume()</code> + 若 <code>prefMuted=false</code> 则起 BGM → 进 <code>opening</code>;resume <strong>resolve</strong> → <code>audible</code>;resume <strong>reject 或 1.5 s 内 ctx 仍非 running</strong> → 回 <code>locked</code>(清掉任何「已开」标记,<strong>允许下次手势重试</strong>),不准停在 <code>opening</code>,更不准算 <code>audible</code>。</li>
<li><strong>♪ 在 <code>locked</code> / <code>opening</code></strong> → 视为「开声」:同步 <code>resume()</code> + 播已解码的确认音(<code>ui.sound_on</code> 类)+ 若有 BGM 起 BGM + <code>prefMuted=false</code> → <code>opening</code>(落定规则同 1)。<strong>不是</strong>翻 <code>prefMuted</code>。</li>
<li><strong>♪ 在 <code>audible</code></strong> → <code>muted</code>(gain 0 / BGM pause,<code>prefMuted=true</code>)。</li>
<li><strong>♪ 在 <code>muted</code></strong> → <code>audible</code>(gain 恢复 / BGM 续播,<code>prefMuted=false</code>;若 ctx 期间被系统挂起,则走 2 的 resume 路径)。</li>
<li><code>audible</code> 下 ctx 被系统挂起(<code>statechange</code> → suspended,iOS 切后台/来电)→ 回 <code>locked</code>,<strong>保留</strong> <code>prefMuted</code> 不变;回前台的首个手势按 1 处理(<code>prefMuted=true</code> 时 resume 但不起 BGM)。</li>
<li><strong>按钮图示 = f(soundState)</strong>:<code>locked</code>/<code>opening</code>/<code>muted</code> 画「静音」样式(可加小点表示待开),<code>audible</code> 画「有声」;<strong>不准</strong>用 <code>prefMuted</code> 画图示。</li>
<li><strong>loading 放行条件</strong>(补注二):清单内全部 cue <code>decodeAudioData</code> 完成(断言 <code>decoded === manifest.length</code>);解码不需手势;放行前不准播任何东西;合成 blip 只在某 cue 解码失败时作该 cue 的替身。</li>
<li>转移 1/2 的 <code>resume()</code> 与 <code>start()</code> <strong>必须在手势事件的同步栈内</strong>调用(不在 <code>.then()</code>、不在 <code>await</code> 之后、不在 setTimeout);测试用「resume 返回挂起的 promise」验证:handler 返回时 <code>resume</code> 已被调 1 次、<code>start</code> 已被调 ≥1 次,而 promise 尚未落定。</li>
</ol>
<p>测试最少覆盖(每款):①锁态首按 ♪ → opening → resolve → audible,第二按 → muted;②锁态首按 ♪,resume reject → 回 locked,再按一次又会 resume(重试);③任意元素(非 ♪)首按 → opening → resolve → audible,<strong>随后按 ♪ → muted</strong>(不是再播确认音);④ <code>audible</code> 时 statechange→suspended → locked,图示变静音;⑤图示在上述每个状态的断言;⑥loading 放行时 decoded===manifest.length;⑦退回验红(去掉状态更新那行测试要红)。 Home 钮(P27):按钮元素必须真的带 <code>id="home"</code>(或接线处用的选择器真能选到它),进场 loading 期间可点,点了 300 ms 内有按下态;用<strong>真实 click 事件</strong>测导航函数被调 1 次(mines v2 的 <code>press('home')</code> 取到 null 抛错 = onBack 从没跑,就是这种假接线)。</p>
<h2>P26 补注五 v2(10-26 12:3x 总监裁,Sol 砍过一次 12 条已并入):开声状态机<strong>只准有一份实作</strong>,放在 common/engine,各款只接线</h2>
<p>Sol 四轮(b1/r2/r3/r4a)退回的阻断项是同一件事反复出现:每款各写一套 soundState,各自漏掉一种事件顺序。从本补注起:</p>
<h3 id="1-共用模块唯一实作">1. 共用模块(唯一实作)</h3>
<p><code>common/engine/src/audio/sound-state.ts</code> 导出 <code>createSoundState(opts)</code>。各款壳/页面<strong>不准</strong>再自己持有 muted/opened/audible/hostMuted 任何旗,不准自己调 <code>ctx.resume()</code>/<code>source.start()</code>,不准有自动开声分支。模块拥有:ctx、<strong>输出总闸</strong>(一个 master GainNode,所有声音都经它)、<code>state ∈ {locked, opening, audible, muted}</code>、<code>userMuted</code>(静音偏好,独立于 state)、<code>subscribe(fn)</code>、<code>prepare(manifest, onProgress, {deadlineMs})</code>、<code>bindGestures(root, {exclude})</code>、<code>press()</code>、<code>play(cue, opts) → handle|null</code>、<code>startLoop(cue, {loopStart, loopEnd, syncWith?}) → handle|null</code>、<code>setParam(handle, …)</code>、<code>stopAll()</code>、<code>dispose()</code>。</p>
<h3 id="2-硬规则">2. 硬规则</h3>
<ol type="1">
<li><strong>可信激活事件</strong>:<code>bindGestures</code> 只认 <code>pointerup</code>/<code>touchend</code>/<code>click</code> 与 <code>keydown</code>(仅 Enter/Space,过滤 repeat);同一次操作(pointer→click 链)只算一次尝试(用 attempt token 去重)。♪ 钮经 <code>exclude</code> 排除在通用开声之外,它的一次完整操作只跑一次 <code>press()</code>。</li>
<li><strong>audible 的定义 = 播放就绪并已证明</strong>:本次尝试的 <code>resume()</code> 已 resolve <strong>且</strong> <code>ctx.state==='running'</code> <strong>且</strong> 在该手势同步栈内提交的<strong>内建确认音</strong>(模块自带 ~60 ms 已解码非静音 click,base64 内联,不走网络、不会失败)<code>start()</code> 成功且 source 已连到输出闸。BGM/替身/静音帧都不是证据。<code>opening</code> 期只准起这一个确认音。</li>
<li><strong>事件顺序无关 + 尝试代号</strong>:每次尝试带 token;resolve/running 任一顺序都行;resolve 了但 ctx 仍 suspended → 等 statechange 或 <code>timeoutMs</code>(默认 1500,可配)→ 超时/reject/中断:停掉该尝试的 source、关输出闸、作废其回调,回 <code>locked</code>;迟到的旧 token 结果一律忽略;下一手势可再试。</li>
<li><strong>loading 闸</strong>:<code>prepare()</code> 对清单逐件下载+解码,失败件重试 1 次,再失败建替身(按清单声明的 <code>durationMs</code>/循环点建静音 buffer,<strong>带 failed 标记</strong>,只用于不崩、不作证据、BGM 替身不循环播放);每件互斥计一次(decoded 或 failed);整体 <code>deadlineMs</code>(默认 20000)到期把未完成件都记 failed 并 resolve。<code>prepare()</code> resolve 前:<code>play/startLoop</code> 丢弃不积压;开声手势也<strong>不提交任何声音</strong>(只 resume,状态最高到 opening),ready 后不补播,等下一手势。入口核 <code>decoded + failed === manifest.length</code> 才算 loading 完成。</li>
<li><strong>播放许可唯一</strong>:<code>play/startLoop</code> 只在 <code>audible</code> 放行,否则返回 null(调用方据此维护自己的循环状态,不得假设已播);<code>stopAll()</code> 停模块拥有的全部 source。</li>
<li><strong>生命周期</strong>:同时监听 ctx <code>statechange</code> 与 <code>visibilitychange</code>/<code>pagehide</code>/<code>freeze</code>;离开 running(suspended/interrupted/closed)或页面离开前台 → 立即关输出闸、停循环、作废当前尝试、state→<code>locked</code>(<code>userMuted</code> 不变);系统自行恢复 running <strong>不</strong>开闸、不改 state;回前台等下一手势。<code>pageshow(persisted)</code>(BFCache)视同重挂:重新绑定、state=locked。</li>
<li><strong>静音偏好</strong>:<code>userMuted</code> 由 localStorage 初始化、只由 <code>press()</code> 翻转;通用手势永不清除它。<code>press()</code> 语义:locked/opening → 开声尝试(若 userMuted=true 则同时清偏好);audible → userMuted=true + 关闸 → <code>muted</code>;muted → 开闸 →(ctx 仍 running)<code>audible</code> 否则重走开声。图示 = f(state),壳只 <code>subscribe</code>。</li>
<li><strong>壳不准有第二套决策</strong>:壳里 <code>ctx.resume</code>、<code>muted = !muted</code>、<code>hostMuted</code>、自动开声分支一律删除。</li>
<li><strong>销毁契约</strong>:<code>dispose()</code> 幂等:解绑所有监听/订阅/定时器,作废全部异步结果,停并释放拥有的音频资源。</li>
</ol>
<h3 id="3-测试共用模块自带各款不重写">3. 测试(共用模块自带,各款不重写)</h3>
<p><code>sound-state.test.ts</code> 用假 AudioContext 可控触发 resolve/reject/statechange 顺序与时序,至少覆盖:①–⑦(补注四)+ ⑧ running 先到 reject 后到 → locked;⑨ resolve 先到仍 suspended → 超时 locked 且该尝试 source 被 stop;⑩ 旧 token 迟到 resolve 被忽略;⑪ loading 中手势 → 不提交声音、不 audible、ready 后不补播;⑫ 解码失败件替身计数正确、替身不作证据、BGM 替身不循环;⑬ <code>pagehide</code>/<code>interrupted</code> → 关闸停循环 locked,系统恢复 running 不开闸;⑭ userMuted 下通用手势不出声不清偏好,press 才取消;⑮ ♪ 的 pointer→click 链只算一次 press;⑯ locked 下 play 返回 null、恢复后无积压 start;⑰ dispose 后无监听无 source。 各款只做<strong>接线测试</strong>:挂载真实壳 DOM,派发 pointerdown/pointerup/click 链(合成事件可以,但不准自己造 <code>dispatch()</code> 直接调回调)真点 ♪ 两次(开声→muted)与 <code>#home</code> 一次(导航函数调 1 次,进场期可点、按下态可见);以及 <code>play()</code> 返回 null 时本款循环状态不被标成已播。 <strong>真机验收(每款必做,合成事件不算)</strong>:iOS Safari 与 Chrome Android 各一段录屏,页面加 <code>?snddebug=1</code> 时右上角显示 <code>state / ctx.state / 最近 start 的 cue 名 / attempt#</code>;录:首按 ♪、第二按、快速连按两下、进场期点 Home、切后台再回来后首手势、loading 中点 ♪。录屏是交付物。</p>
<h3 id="4-过渡">4. 过渡</h3>
<p>以 fishshoot v2 的 <code>director.ts</code> 为底搬进 <code>sound-state.ts</code>;<code>director.ts</code> 旧 API(<code>unmuteBlip/primeBlip/build/onCtxState/prepare/press</code>)只保留<strong>转发适配层</strong>,一律委托新模块;以下旧行为<strong>废除</strong>(不是保留):<code>build()</code> 回前台自动 resume、<code>prepare()</code> 完成后补起 BGM、<code>onCtxState()</code> running 自动回 audible、<code>FishSound.loopOn</code> 把被丢弃的启动记成已播。API 要补齐 crash 的双层同步循环(<code>syncWith</code>)与动态混音(<code>setParam</code>)、fishshoot 的循环点,否则各款做不到「只换接线」。各款接线单在共用模块 Sol PASS 之后才派;接线单只准删本款自写状态机、换成模块调用。</p>
<h2 id="p28">P28 · 手机全屏 · Mobile full screen(Victor 2026-10-28 13:2x/13:3x 令,必备)<code>FULLSCREEN</code></h2>
<ul>
<li><strong>iOS</strong>:直/横屏往上滑要能进全屏(Safari 收起网址栏/标签栏:页面可滚 ≥1px、<code>scrollTo(0,1)</code> 法),首次进场出提示卡「Swipe up for full screen / Geser ke atas」。</li>
<li><strong>Android</strong>:右上角一颗<strong>放大钮</strong>(<code>.mg-fs-btn</code> 44×44,图标=放大),点了 <code>requestFullscreen</code>;全屏中变成缩小钮。</li>
<li><strong>唯一实作</strong> <code>common/fullscreen</code> 的 <code>mount()</code>(含 P29 zoomLock + A2HS 提示),每款 app 入口挂一次,不自己写;页面根不准 <code>position:fixed</code>/<code>overflow:hidden</code> 把可滚高度锁死。</li>
<li>验收(量的):iPhone 模拟器 Safari 直屏载入 → 上滑 → <code>window.innerHeight</code> 增加(写前/后 px)且提示卡出现过一次,横屏同测;Android(Chrome 模拟或真机)放大钮可见、点后 <code>document.fullscreenElement</code> 非空;线上包 grep <code>requestFullscreen</code>、<code>Swipe up for full screen</code>、<code>mg-fs-btn</code> 各 ≥1。2026-10-28 线上扫描:crash/tower/wheel/catfish/plinko/kancilroad/fishshoot/komodo/mines/topo 有模块,<strong>dice、goalshoot 没有</strong>(待补)。</li>
</ul>
<h2 id="p29">P29 · 禁缩放 · No zoom(Victor 2026-10-28 13:0x 问「double tap 有挡吗」→ 定为必备)<code>ZOOMLOCK</code></h2>
<ul>
<li>双击放大、双指缩放一律挡掉;<strong>唯一实作</strong> <code>common/fullscreen</code> 的 <code>installZoomLock</code>(随 P28 <code>mount()</code> 自动挂):viewport <code>maximum-scale=1, user-scalable=no</code> + html/body/root <code>touch-action: manipulation</code> + iOS <code>gesturestart/gesturechange/gestureend</code> 与双指 <code>touchmove</code> preventDefault + 300 ms 内第二下 tap 吞掉再补一个 click(连点仍算点击)。</li>
<li>验收(量的):线上包 grep <code>gesturestart</code> ≥1、<code>manipulation</code> ≥1;模拟器双击游戏区 3 次视口 scale 仍 1(截图尺寸不变)。</li>
</ul>
<h2 id="p30">P30 · 演出逻辑关 · Animation causality gate(Victor 2026-10-28 11:5x 批、#1849 定)<code>LOGIC</code></h2>
<ul>
<li>任何演出/结算动画:<strong>每个结果有看得见的原因、原因先于结果、没有东西无缘无故动/偏/变</strong>;放好的东西不动,除非外力。</li>
<li>上游:GDD 演出段必含四栏「演出因果表」(结果 | 原因 | 铺垫在第几步/帧可见 | 结果在第几步/帧);下游:落地录制过 <code>bin/look-logic</code> 盲述审(总监机跑)+ look-weird,两关都过才给 Victor。正本 <code>(internal)</code> 末节。</li>
</ul>
<h2 id="rules">开工规则(Victor 2026-10-28 13:3x):做任何新游戏,工单第一行写「照本 STANDARD P1–P30 全部做完」,不挑页;缺一页 = 不过。</h2>
</main></body></html>