Files
HexTrails/design/guide-template.html

60 lines
32 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="theme-color" content="#F7F6F2">
<title>HEX TRAILS · 视觉设计手册</title>
<style>
:root{ {{TOKENS}} --atlas:url('{{ICON_ATLAS}}');font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;color:var(--textPrimary);background:var(--surface);font-synthesis:none}
*{box-sizing:border-box}html{scroll-behavior:smooth;scroll-padding-top:90px}body{margin:0}button,input{font:inherit}button,a,input{-webkit-tap-highlight-color:transparent}button{cursor:pointer}button:disabled{cursor:default}a{color:var(--primary);text-underline-offset:4px}button:focus-visible,a:focus-visible,input:focus-visible{outline:3px solid var(--focus);outline-offset:4px}button:active:enabled{transform:scale(.96)}button{transition:transform .15s}p{line-height:1.85}code{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:.88em;overflow-wrap:anywhere}h1,h2,h3,p{margin-top:0}h2{font-size:32px;letter-spacing:-.04em;margin-bottom:12px}h3{font-size:19px;margin-bottom:12px}b,strong{font-weight:650}[hidden]{display:none!important}.svg-defs{position:absolute;pointer-events:none}.page{max-width:1180px;margin:auto;padding:0 36px}.topbar{position:sticky;top:0;z-index:5;background:var(--surface);border-bottom:1px solid var(--secondary)}.topbar .page{min-height:72px;display:flex;align-items:center;justify-content:space-between;gap:24px}.brand{font-weight:800;letter-spacing:.1em;font-size:15px;color:var(--textPrimary);text-decoration:none;white-space:nowrap}.brand span{display:inline-block;width:10px;height:10px;background:var(--primary);margin-right:10px;border-radius:3px}.nav{display:flex;gap:22px;font-size:13px;overflow:auto;white-space:nowrap;padding:13px 3px}.nav a{text-decoration:none;color:var(--textSecondary)}.nav a:hover{color:var(--primary)}.eyebrow{font-size:11px;letter-spacing:.16em;font-weight:700;text-transform:uppercase;color:var(--textSecondary);margin-bottom:18px}.hero{display:grid;grid-template-columns:1.08fr .92fr;align-items:center;gap:70px;padding:60px 0 72px}.hero h1{font-size:clamp(38px,5vw,60px);line-height:1.2;letter-spacing:-.045em;margin:0 0 26px}.hero h1 span{color:var(--primary)}.hero p{font-size:16px;max-width:440px;color:var(--textSecondary)}.hero-note{font-size:12px!important;margin:23px 0 0}.pill{display:inline-flex;align-items:center;gap:7px;border-radius:100px;background:var(--secondary);font-size:11px;padding:7px 11px}.hero-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:28px}.button{display:inline-flex;align-items:center;justify-content:center;gap:9px;min-height:44px;border:0;border-radius:14px;padding:12px 18px;font-size:13px;font-weight:600;text-decoration:none;background:var(--secondary);color:var(--textPrimary);line-height:1.4}.button.primary{background:var(--primary);color:var(--onPrimary)}.button.utility{background:var(--utility);color:var(--onUtility)}.button .icon{width:22px;height:22px}.icon{display:inline-block;width:28px;height:28px;flex-shrink:0;background-image:var(--atlas);background-repeat:no-repeat;vertical-align:middle}.icon-ground{display:inline-flex;align-items:center;justify-content:center;background:var(--utility);border-radius:14px;width:52px;height:52px;color:var(--onUtility)}
{{ICON_CSS}}
.phone-stage{border-radius:32px;background:var(--background);padding:26px 25px 20px;max-width:360px;width:100%;margin:auto}.phone-top{display:flex;justify-content:space-between;align-items:center}.phone-top .icon-ground{width:38px;height:38px;border-radius:12px}.phone-top .icon{width:25px;height:25px}.phone-level{font-size:23px;font-weight:800;letter-spacing:.03em}.phone-moves{text-align:center;font-size:10px;margin-top:10px}.phone-moves b{display:block;font-size:28px;line-height:1.3}.phone-stage .game-art{margin:6px -10px -6px;width:calc(100% + 20px)}.game-art{display:block;width:100%;height:auto}.phone-rotate{display:flex;justify-content:space-evenly;text-align:center;margin:7px 0 20px}.phone-rotate .icon{width:49px;height:49px;filter:drop-shadow(0 1px 1px var(--utility))}.phone-rotate small{display:block;font-size:11px;margin-top:7px}.phone-tools{display:flex;justify-content:center;gap:30px;text-align:center}.phone-tools .icon-ground{width:45px;height:43px;border-radius:12px}.phone-tools .icon{width:25px;height:25px}.phone-tools small{display:block;font-size:10px;margin-top:7px}.preview-caption{text-align:center;font-size:11px;color:var(--textSecondary);margin:14px 0 0}.section{padding:64px 0;border-top:1px solid var(--secondary)}.section-head{display:flex;justify-content:space-between;align-items:flex-start;gap:25px;margin-bottom:28px}.section-head p{font-size:14px;max-width:690px;margin-bottom:0;color:var(--textSecondary)}.section-num{font:12px ui-monospace,monospace;color:var(--primary);display:block;margin-bottom:14px}.principles{display:grid;grid-template-columns:repeat(3,1fr);gap:28px;margin-top:36px}.principle{border-top:3px solid var(--utility);padding-top:20px}.principle:nth-child(2){border-color:var(--primary)}.principle:nth-child(3){border-color:var(--reward)}.principle p{font-size:13px;color:var(--textSecondary);margin:0}.scheme-strip{display:flex;height:54px;border-radius:14px;overflow:hidden;margin-top:25px}.scheme-strip span{flex:1}.search-box{display:flex;gap:14px;align-items:center;margin-bottom:24px}.search-box input{background:var(--input);border:1px solid var(--boardGrid);padding:13px 15px;border-radius:12px;font-size:13px;flex:1;min-width:0;color:var(--textPrimary)}.search-box span{font-size:12px;color:var(--textSecondary);white-space:nowrap}.swatch-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}.swatch{padding:0;border:1px solid var(--secondary);border-radius:16px;overflow:hidden;text-align:left;background:var(--input);color:var(--textPrimary)}.swatch-color{height:88px;display:block;background:var(--swatch);border-bottom:1px solid var(--secondary)}.swatch-label{display:block;padding:15px}.swatch-label strong{display:block;font-size:12px;margin-bottom:6px}.swatch-label>code{display:block;font-size:11px;margin-bottom:12px}.hex{display:flex;justify-content:space-between;font:12px ui-monospace,monospace;gap:6px}.hex>span{font:10px -apple-system,sans-serif;color:var(--textSecondary)}.note{font-size:12px;color:var(--textSecondary);line-height:1.8;margin:20px 0 0}.empty{text-align:center;padding:24px}.pair-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin:28px 0}.pair-card{padding:22px;border-radius:16px;min-height:160px}.pair-card b{font-size:23px;display:block;margin-bottom:15px}.pair-card p{font-size:12px;line-height:1.7;margin:0}.pair-card code{display:block;margin-top:15px;font-size:10px}.primary-pair{color:var(--onPrimary);background:var(--primary)}.utility-pair{color:var(--onUtility);background:var(--utility)}.warning-pair{color:var(--warning);background:var(--warningSurface)}.table-scroll{overflow-x:auto;max-width:100%;border:1px solid var(--secondary);border-radius:14px}table{width:100%;border-collapse:collapse;font-size:12px}th,td{text-align:left;padding:14px 16px;border-bottom:1px solid var(--secondary);line-height:1.65}th{font-size:11px;background:var(--secondary);font-weight:650}tr:last-child td{border-bottom:0}.pair-example{display:inline-grid;place-items:center;width:44px;height:36px;border-radius:8px;margin-right:12px;font-weight:750;font-size:17px;vertical-align:middle}.pair-table td:first-child{min-width:230px}.pair-table td:nth-child(2){min-width:160px}.pair-table td{white-space:nowrap}.component-grid{display:grid;grid-template-columns:1fr 1fr;gap:20px}.card{padding:28px;background:var(--input);border:1px solid var(--secondary);border-radius:20px;min-width:0}.card p{font-size:12px;color:var(--textSecondary);margin:18px 0 0}.demo-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin:25px 0}.demo-column{text-align:center}.demo-column>small{display:block;font-size:11px;margin-top:12px;color:var(--textSecondary)}.demo-disabled{opacity:.55}.pressed{transform:scale(.94);filter:brightness(.96)}.focus-demo{outline:3px solid var(--focus);outline-offset:3px}.rotation-demo{background:var(--background);border-radius:16px;padding:18px;gap:36px;justify-content:center}.rotate-example{background:none;border:0;min-width:80px;min-height:90px;color:var(--textPrimary);font-size:12px}.rotate-example .icon{width:56px;height:56px;filter:drop-shadow(0 1px 1px var(--utility));display:block;margin:0 auto 9px}.rotate-example:active .icon{transform:rotate(10deg)}.level-samples{display:flex;gap:12px;margin:25px 0}.level-sample{border:0;min-width:70px;min-height:68px;border-radius:14px;background:var(--secondary);color:var(--textPrimary);font-weight:750;font-size:22px}.level-sample small{display:block;font-size:10px;margin-top:6px;font-weight:500}.level-sample[aria-pressed=true]{background:var(--primary);color:var(--onPrimary)}.tile-panel{display:grid;grid-template-columns:220px 1fr;gap:24px;align-items:center;margin-top:20px}.tile-panel p{font-size:13px;color:var(--textSecondary)}.tile-panel .game-art{max-width:240px}.icon-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:24px 12px;padding:30px 0 8px}.icon-item{text-align:center;min-width:0}.icon-item .icon-ground{width:58px;height:58px}.icon-item .icon{width:35px;height:35px}.icon-item b{display:block;font-size:12px;margin:11px 0 4px}.icon-item code{font-size:10px;color:var(--textSecondary)}.type-layout{display:grid;grid-template-columns:1fr 1fr;gap:36px}.type-sample{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:18px 0;border-bottom:1px solid var(--secondary)}.type-sample code{font-size:11px;color:var(--textSecondary);text-align:right}.shape-row{display:flex;gap:16px;align-items:flex-end;margin-top:28px}.shape{background:var(--secondary);display:flex;justify-content:center;align-items:center;width:90px;height:78px;font-size:12px}.space-row{display:flex;gap:22px;align-items:flex-end;height:95px;margin:10px 0 20px}.space-row span{width:20px;height:var(--space);background:var(--primary);position:relative}.space-row span:after{content:attr(data-size);position:absolute;top:calc(100% + 8px);left:0;font:10px ui-monospace,monospace}.motion-layout{display:grid;grid-template-columns:1fr 1fr;gap:32px}.motion-preview{background:var(--background);border-radius:22px;display:flex;align-items:center;justify-content:center;min-height:260px;padding:30px}.mini-modal{border-radius:24px;padding:28px;background:var(--surface);text-align:center;max-width:270px;width:100%}.mini-stars{display:flex;justify-content:center;gap:8px;margin-bottom:20px}.mini-stars .icon{width:44px;height:44px;filter:drop-shadow(0 1px 1px var(--reward))}.timings{display:grid;gap:0}.timing{border-bottom:1px solid var(--secondary);padding:17px 0;display:flex;justify-content:space-between;align-items:center;font-size:13px;gap:18px}.timing b{font:20px ui-monospace,monospace;color:var(--primary)}.timing small{font-size:12px}.spec{max-width:880px;margin:0 auto;font-size:14px;line-height:1.9}.spec h2{font-size:30px;margin:32px 0 18px}.spec h3{font-size:23px;margin:45px 0 18px;border-top:1px solid var(--secondary);padding-top:28px}.spec h4{font-size:17px;margin:28px 0 14px}.spec p,.spec li{color:var(--textSecondary)}.spec code{background:var(--secondary);border-radius:4px;padding:2px 4px}.spec table code{background:none;padding:0}.spec .table-scroll{margin:20px 0}.spec ul,.spec ol{padding-left:23px}.spec li{margin-bottom:7px}.footer{border-top:1px solid var(--secondary);padding:28px 0 42px;color:var(--textSecondary);font-size:12px;display:flex;justify-content:space-between;gap:18px}.status{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:var(--textPrimary);color:white;border-radius:12px;padding:12px 18px;font-size:12px;z-index:30;max-width:calc(100% - 30px);pointer-events:none}.demo-dialog{border:0;border-radius:24px;background:var(--surface);color:var(--textPrimary);padding:42px 28px 28px;text-align:center;width:calc(100% - 36px);max-width:360px;max-height:85dvh;overflow:auto}.demo-dialog[open]{animation:arrive .42s cubic-bezier(.22,1,.36,1) both}.demo-dialog::backdrop{background:var(--scrim);backdrop-filter:blur(5px);-webkit-backdrop-filter:blur(5px)}.demo-dialog .close{position:absolute;right:12px;top:12px;width:36px;height:36px;min-height:36px;padding:5px;background:var(--utility);color:var(--onUtility);border:0;border-radius:12px}.demo-dialog .close .icon{width:23px;height:23px}.demo-dialog h3{font-size:24px}.demo-dialog p{font-size:13px;color:var(--textSecondary)}.demo-dialog .button{width:100%;margin-top:10px}.demo-dialog[open] .mini-stars .icon{animation:star .4s cubic-bezier(.2,1.5,.5,1) both;animation-delay:.3s}.demo-dialog[open] .mini-stars .icon:nth-child(2){animation-delay:.49s}.demo-dialog[open] .mini-stars .icon:nth-child(3){animation-delay:.68s}body:has(dialog[open]){overflow:hidden}@keyframes arrive{from{opacity:0;transform:translateY(-60px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes star{from{opacity:0;transform:scale(.25) rotate(-20deg)}to{opacity:1;transform:scale(1) rotate(0)}}
.hero .eyebrow{font-size:11px}.hero .preview-caption{font-size:11px;line-height:1.6}
button{transition-duration:var(--pressMs)}button:active:enabled{transform:scale(.94)}.pressed{filter:none}.button,.icon-ground,.level-sample{border-radius:var(--controlRadius)}.demo-dialog,.mini-modal{border-radius:var(--dialogRadius)}.demo-dialog[open]{animation-duration:var(--modalMs)}.demo-dialog[open] .mini-stars .icon{animation-delay:var(--starOne)}.demo-dialog[open] .mini-stars .icon:nth-child(2){animation-delay:var(--starTwo)}.demo-dialog[open] .mini-stars .icon:nth-child(3){animation-delay:var(--starThree)}.demo-dialog::backdrop{animation:veil-in .25s ease-out}@keyframes veil-in{from{opacity:0}to{opacity:1}}
@media(max-width:850px){.page{padding:0 24px}.hero{gap:32px}.hero h1{font-size:42px}.nav{gap:16px}.swatch-grid{grid-template-columns:repeat(3,1fr)}.icon-grid{grid-template-columns:repeat(4,1fr)}.tile-panel{grid-template-columns:180px 1fr}}
@media(max-width:640px){html{scroll-padding-top:124px}.page{padding:0 20px}.topbar .page{align-items:flex-start;flex-direction:column;gap:0;padding-top:18px}.nav{width:100%;font-size:12px;gap:22px}.hero{grid-template-columns:1fr;gap:38px;padding:38px 0 44px}.hero h1{font-size:43px}.hero p{font-size:14px}.phone-stage{max-width:340px}.section{padding:42px 0}.section-head{display:block}.section-head .pill{margin-top:15px}h2{font-size:28px}.principles{grid-template-columns:1fr;gap:24px}.swatch-grid{grid-template-columns:repeat(2,1fr);gap:12px}.swatch-color{height:75px}.swatch-label{padding:12px}.swatch-label>code{font-size:10px}.swatch-label strong{font-size:11px}.hex{font-size:11px}.search-box{gap:8px}.search-box span{font-size:10px}.component-grid,.type-layout,.motion-layout{grid-template-columns:1fr}.pair-grid{grid-template-columns:1fr}.pair-card{min-height:0}.card{padding:22px}.tile-panel{grid-template-columns:1fr;gap:12px}.tile-panel .game-art{max-width:240px;margin:auto}.icon-grid{gap:24px 8px}.icon-item .icon-ground{width:54px;height:54px}.spec{font-size:13px}.spec h2{font-size:26px}.spec h3{font-size:21px}.footer{display:block}.footer p{margin-bottom:6px}.hero-actions .button{font-size:12px}.pair-table{min-width:620px}}
@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>
<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="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>
<section class="section" id="specification"><div class="section-head"><div><span class="section-num">06 / FULL SPECIFICATION</span><h2>完整设计规范</h2><p>以下内容自动来自 Design.md。颜色数值来自共享 Token;修改源文件并运行 <code>npm run design</code> 即可重新生成本手册。</p></div><button class="button print-hidden" id="download-md">下载 Markdown</button></div><article class="spec">{{SPEC}}</article></section>
<footer class="footer"><p>HEX TRAILS · 视觉设计手册 1.0<br>单文件离线版 · 与 Design.md 同步生成</p><p>HTML 是设计展示快照。<br>在这里试用组件不会修改游戏或设计源文件。</p></footer>
</main>
<dialog class="demo-dialog" id="motion-dialog" aria-labelledby="motion-title"><button class="close" id="close-motion" aria-label="关闭演示"><span class="icon icon-close" aria-hidden="true"></span></button><p class="eyebrow">通关弹窗 · 动效示例</p><div class="mini-stars" aria-label="三颗星星"><span class="icon icon-star" aria-hidden="true"></span><span class="icon icon-star" aria-hidden="true"></span><span class="icon icon-star" aria-hidden="true"></span></div><h3 id="motion-title">漂亮,全部过关!</h3><p>背景已变暗、模糊,并停止响应操作。<br>三颗星星依次出现。</p><button class="button primary" id="finish-motion">完成演示</button><button class="button" id="replay-motion">再播放一次</button></dialog>
<div class="status" id="status" role="status" aria-live="polite" hidden></div>
<script type="application/json" id="guide-data">{{PAYLOAD}}</script>
<script>
(()=>{
const $=id=>document.getElementById(id),status=$('status');let messageTimer;
function notify(message){status.textContent=message;status.hidden=false;clearTimeout(messageTimer);messageTimer=setTimeout(()=>status.hidden=true,2300);}
async function copy(value){let copied=false;try{if(navigator.clipboard){await navigator.clipboard.writeText(value);copied=true;}}catch{}if(!copied){const input=document.createElement('textarea');input.value=value;input.style.cssText='position:fixed;top:0;left:-9999px';document.body.append(input);input.focus();input.select();try{copied=document.execCommand('copy');}catch{}input.remove();}notify(copied?'已复制 '+value:'请手动复制:'+value);}
const swatches=[...document.querySelectorAll('.swatch')];
swatches.forEach(button=>button.addEventListener('click',()=>copy(button.dataset.color)));
function filter(){const query=$('color-search').value.trim().toLowerCase();let count=0;swatches.forEach(button=>{button.hidden=!button.dataset.search.includes(query);if(!button.hidden)count++;});$('color-count').textContent=count+' / '+swatches.length+' 色';$('empty-colors').hidden=count>0;}
$('color-search').addEventListener('input',filter);filter();
document.querySelectorAll('[data-feedback]').forEach(button=>button.addEventListener('click',()=>notify(button.dataset.feedback)));
document.querySelectorAll('.level-sample').forEach(button=>button.addEventListener('click',()=>document.querySelectorAll('.level-sample').forEach(item=>{const selected=item===button;item.setAttribute('aria-pressed',String(selected));item.querySelector('small').textContent=selected?'当前关卡':'选择关卡';})));
const modal=$('motion-dialog');$('show-motion').addEventListener('click',()=>modal.showModal());
['close-motion','finish-motion'].forEach(id=>$(id).addEventListener('click',()=>modal.close()));
$('replay-motion').addEventListener('click',()=>{modal.close();requestAnimationFrame(()=>requestAnimationFrame(()=>modal.showModal()));});
$('print-guide').addEventListener('click',()=>window.print());
$('download-md').addEventListener('click',()=>{const data=JSON.parse($('guide-data').textContent),url=URL.createObjectURL(new Blob([data.markdown],{type:'text/markdown;charset=utf-8'})),link=document.createElement('a');link.href=url;link.download='Design.md';document.body.append(link);link.click();link.remove();setTimeout(()=>URL.revokeObjectURL(url),1000);});
})();
</script>
</body>
</html>