665 lines
90 KiB
HTML
665 lines
90 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>移动端 HUD 草图 · 暗黑 ARPG</title>
|
||
<link rel="stylesheet" href="../themes/default.css">
|
||
<style>
|
||
* { box-sizing: border-box; }
|
||
:root { color-scheme: dark; }
|
||
html, body { margin: 0; min-height: 100%; background: radial-gradient(circle at 50% 0%, #1c3048 0, #0b1018 42rem); color: var(--color-text); font-family: var(--font-sans); }
|
||
body { padding: 34px 20px 60px; }
|
||
button, input { font: inherit; }
|
||
button { color: inherit; cursor: pointer; }
|
||
.page-head { max-width: 1040px; margin: 0 auto 24px; }
|
||
.eyebrow { color: var(--color-primary); font-size: var(--text-xs); letter-spacing: .18em; text-transform: uppercase; }
|
||
h1 { margin: 5px 0; font-size: clamp(1.45rem, 3vw, 2.2rem); }
|
||
.page-head p { margin: 6px 0 0; max-width: 720px; color: var(--color-text-muted); line-height: 1.55; }
|
||
.variant { max-width: 1040px; margin: auto; }
|
||
.variant-intro { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin: 0 auto 14px; max-width: 920px; }
|
||
.variant-intro h2 { margin: 0; font-size: var(--text-lg); }
|
||
.variant-intro p { margin: 0; color: var(--color-text-muted); font-size: var(--text-sm); }
|
||
.device-wrap { display: flex; justify-content: center; }
|
||
.device { position: relative; width: min(844px, calc(100vw - 40px)); aspect-ratio: 844 / 390; overflow: hidden; border: 1px solid rgba(221, 238, 255, .45); border-radius: 30px; background: #0a1018; box-shadow: 0 28px 80px rgba(0,0,0,.55), 0 0 0 7px rgba(255,255,255,.035); transition: width .25s ease, aspect-ratio .25s ease, border-radius .25s ease; }
|
||
.preview-tablet .device { width: min(1280px, calc(100vw - 40px)); aspect-ratio: 16 / 9; border-radius: 24px; }
|
||
.preview-desktop .device { width: min(1440px, calc(100vw - 40px)); aspect-ratio: 16 / 9; border-radius: 18px; }
|
||
.scene { position: absolute; inset: 0; overflow: hidden; background: linear-gradient(145deg, rgba(16,39,54,.85), rgba(8,17,25,.88) 48%, rgba(32,22,42,.94)); }
|
||
.scene::before { content: ""; position: absolute; inset: -12%; opacity: .55; background: radial-gradient(ellipse at 25% 37%, rgba(95,181,187,.28), transparent 24%), radial-gradient(ellipse at 78% 23%, rgba(144,97,221,.28), transparent 22%), linear-gradient(145deg, transparent 35%, rgba(255,211,108,.08) 36%, transparent 37% 58%, rgba(116,185,255,.08) 59%, transparent 60%); transform: rotate(-7deg); }
|
||
.scene::after { content: ""; position: absolute; inset: 0; background: linear-gradient(transparent 57%, rgba(4,8,13,.42) 82%, rgba(4,8,13,.78)); pointer-events: none; }
|
||
.terrain { position: absolute; inset: 32% 4% 16%; opacity: .4; background: repeating-linear-gradient(164deg, transparent 0 19px, rgba(173,214,213,.16) 20px 21px), repeating-linear-gradient(22deg, transparent 0 36px, rgba(46,70,82,.42) 37px 39px); clip-path: polygon(0 25%, 25% 4%, 53% 24%, 75% 0, 100% 21%, 100% 100%, 0 100%); }
|
||
.hero { position: absolute; left: 48%; top: 40%; width: 48px; height: 82px; transform: translate(-50%, -50%); border-radius: 45% 45% 28% 28%; background: linear-gradient(90deg, #152d44, #b7d7e8 45%, #315375 58%, #101d2d); box-shadow: 0 0 18px rgba(116,185,255,.45); }
|
||
.hero::before { content: ""; position: absolute; left: 9px; top: -26px; width: 30px; height: 32px; border-radius: 50%; background: radial-gradient(circle at 40% 42%, #ffe9c5 0 18%, #6f4c3e 19% 54%, #1a2432 55%); }
|
||
.hero::after { content: "✦"; position: absolute; right: -29px; top: 6px; color: var(--color-accent); font-size: 28px; text-shadow: 0 0 14px #ffb638; }
|
||
.mob { position: absolute; left: 68%; top: 44%; width: 58px; height: 42px; border-radius: 48% 52% 35% 35%; background: linear-gradient(140deg, #2b4155, #8c6672 45%, #201824); box-shadow: 0 0 18px rgba(255,111,120,.2); }
|
||
.mob::before { content: ""; position: absolute; left: 13px; top: -17px; width: 34px; height: 22px; border-radius: 55% 45% 35% 35%; background: #5f3442; }
|
||
.mob::after { content: "· ·"; position: absolute; left: 9px; top: -13px; color: #ffb1a9; letter-spacing: 6px; font-size: 13px; }
|
||
.top-status { position: absolute; z-index: 2; top: 14px; left: 14px; right: 14px; display: flex; align-items: center; gap: 9px; }
|
||
.avatar { width: 44px; height: 44px; flex: 0 0 auto; display: grid; place-items: center; border: 1px solid rgba(255,211,108,.78); border-radius: 50%; background: radial-gradient(circle, #658fb6, #182637 62%, #0b121c); box-shadow: 0 0 0 3px rgba(12,20,30,.58); font-size: 20px; }
|
||
.status-copy { min-width: 0; flex: 0 0 148px; width: 148px; }
|
||
.status-line { display: flex; align-items: center; justify-content: space-between; gap: 7px; font-size: var(--text-xs); }
|
||
.status-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.level { color: var(--color-accent); font-family: var(--font-mono); }
|
||
.meter { height: 7px; margin-top: 4px; overflow: hidden; border: 1px solid rgba(255,255,255,.18); border-radius: 8px; background: rgba(3,8,13,.72); }
|
||
.meter i { display: block; height: 100%; border-radius: inherit; }
|
||
.meter.hp i { width: 78%; background: linear-gradient(90deg, #f05767, #ff9d82); }
|
||
.meter.mp i { width: 62%; background: linear-gradient(90deg, #4f91f8, #8dc8ff); }
|
||
.meter.resource { height: 5px; margin-top: 3px; }
|
||
.meter.resource i { width: 68%; background: linear-gradient(90deg, #39217d, #8c55ed 70%, #caa0ff); }
|
||
.mini-map { position: relative; width: 74px; height: 74px; flex: 0 0 auto; overflow: hidden; border: 1px solid rgba(213,235,255,.52); border-radius: 50%; background: radial-gradient(circle at 44% 58%, rgba(101,178,161,.5) 0 12%, transparent 13%), linear-gradient(35deg, #17313a 0 38%, #284b58 39% 44%, #17313a 45% 63%, #4c385d 64%); box-shadow: inset 0 0 0 4px rgba(8,14,22,.55), 0 6px 14px rgba(0,0,0,.3); }
|
||
.mini-map::before { content: ""; position: absolute; left: 47%; top: 43%; width: 7px; height: 7px; border-radius: 50%; background: var(--color-accent); box-shadow: 0 0 0 4px rgba(255,211,108,.18), 16px -20px 0 -2px var(--color-danger); }
|
||
.target-card { position: absolute; z-index: 2; top: 94px; left: 50%; width: 190px; transform: translateX(-50%); padding: 8px 11px; opacity: .92; border: 1px solid rgba(255,111,120,.36); border-radius: 12px; background: rgba(13,19,29,.62); backdrop-filter: blur(12px); box-shadow: var(--shadow-sm); }
|
||
.target-card strong { display: block; font-size: var(--text-sm); }
|
||
.target-card small { color: #ffabb0; font-size: var(--text-xs); }
|
||
.target-card .meter { height: 5px; margin-top: 6px; }
|
||
.target-card .meter i { width: 43%; background: linear-gradient(90deg, #e65060, #ffab87); }
|
||
.quest-pill { position: absolute; z-index: 2; top: 102px; right: 14px; display: flex; align-items: center; gap: 6px; border: 1px solid rgba(255,211,108,.36); border-radius: 12px; padding: 8px 10px; background: rgba(13,19,29,.54); color: #ffe9ab; font-size: var(--text-xs); backdrop-filter: blur(12px); }
|
||
.chat-bubble { position: absolute; z-index: 2; left: 50%; top: 57%; transform: translateX(-50%); max-width: 168px; padding: 7px 10px; border: 1px solid rgba(255,255,255,.23); border-radius: 12px 12px 12px 3px; background: rgba(10,16,24,.72); color: #e3efff; font-size: var(--text-xs); backdrop-filter: blur(10px); }
|
||
.chat-bubble::after { content: ""; position: absolute; left: 11px; bottom: -7px; border: 6px solid transparent; border-top-color: rgba(10,16,24,.72); border-left: 0; }
|
||
.joystick { position: absolute; z-index: 4; left: 22px; bottom: 116px; width: 110px; height: 110px; border: 1px solid rgba(213,235,255,.24); border-radius: 50%; background: radial-gradient(circle, rgba(116,185,255,.2) 0 28%, rgba(116,185,255,.07) 29% 62%, rgba(10,16,24,.15) 63%); box-shadow: inset 0 0 0 12px rgba(9,17,26,.22); touch-action: none; }
|
||
.joystick::before { content: ""; position: absolute; inset: 18px; border: 1px dashed rgba(213,235,255,.24); border-radius: 50%; }
|
||
.stick { position: absolute; left: 50%; top: 50%; width: 54px; height: 54px; transform: translate(-50%,-50%); border: 1px solid rgba(213,235,255,.64); border-radius: 50%; background: radial-gradient(circle at 35% 28%, rgba(255,255,255,.32), rgba(73,134,193,.66) 38%, rgba(19,49,75,.88)); box-shadow: 0 5px 12px rgba(0,0,0,.36); transition: transform .12s ease; }
|
||
.joystick.is-active .stick { box-shadow: 0 0 0 6px rgba(116,185,255,.14), 0 5px 12px rgba(0,0,0,.36); }
|
||
.combat-cluster { position: absolute; z-index: 4; right: 16px; bottom: 116px; width: 156px; height: 156px; }
|
||
.skill { position: absolute; display: grid; place-items: center; width: 52px; height: 52px; border: 1px solid rgba(213,235,255,.54); border-radius: 50%; background: radial-gradient(circle at 36% 30%, rgba(255,255,255,.33), rgba(55,88,129,.8) 45%, rgba(10,19,31,.92)); box-shadow: 0 6px 14px rgba(0,0,0,.36); font-size: 20px; transition: transform .15s ease, filter .15s ease; }
|
||
.skill:hover, .skill:focus-visible { transform: scale(1.08); filter: brightness(1.25); }
|
||
.skill.main { right: 0; bottom: 14px; width: 78px; height: 78px; border-color: rgba(255,211,108,.74); background: radial-gradient(circle at 35% 25%, #ffdf9a, #ad5b4d 42%, #2b1b2e 78%); font-size: 29px; }
|
||
.skill.s1 { left: 12px; top: 5px; }
|
||
.skill.s2 { left: 52px; top: 52px; }
|
||
.skill.s3 { right: 4px; top: 3px; }
|
||
.skill.s4 { left: 0; bottom: 10px; }
|
||
.skill em { position: absolute; right: -2px; bottom: -2px; display: none; min-width: 18px; padding: 2px 4px; border-radius: 8px; background: #0a111c; color: #f9fcff; font-size: 10px; font-style: normal; }
|
||
.skill.cooling { filter: grayscale(.7) brightness(.58); }
|
||
.skill.cooling em { display: block; }
|
||
.context-action { position: absolute; z-index: 4; right: 23px; bottom: 279px; display: flex; align-items: center; gap: 6px; border: 1px solid rgba(101,225,178,.45); border-radius: 18px; padding: 7px 10px; background: rgba(14,44,46,.72); color: #adffe1; font-size: var(--text-xs); backdrop-filter: blur(10px); }
|
||
.utility-btn { min-width: 41px; height: 38px; display: grid; place-items: center; flex: 1; border: 1px solid rgba(213,235,255,.12); border-radius: 12px; background: rgba(116,185,255,.08); font-size: 17px; transition: all .15s ease; }
|
||
.utility-btn:hover, .utility-btn.active { border-color: rgba(116,185,255,.5); background: rgba(116,185,255,.21); transform: translateY(-2px); }
|
||
.utility-btn span { display: block; margin-top: 1px; color: var(--color-text-muted); font-size: 9px; }
|
||
.floating-cooldown { position: absolute; z-index: 5; left: 50%; top: 69%; transform: translate(-50%, -50%); padding: 9px 13px; border: 1px solid rgba(255,211,108,.42); border-radius: 16px; background: rgba(22,18,19,.74); color: #ffe4a0; font-size: var(--text-xs); opacity: 0; transition: opacity .2s ease; }
|
||
.floating-cooldown.show { opacity: 1; }
|
||
.modal-layer { position: absolute; z-index: 8; inset: 0; display: none; align-items: flex-end; background: rgba(2,6,10,.48); backdrop-filter: blur(6px); }
|
||
.modal-layer.open { display: flex; }
|
||
.sheet { width: 100%; max-height: 74%; overflow: auto; padding: 17px; border-top: 1px solid rgba(213,235,255,.32); border-radius: 24px 24px 0 0; background: rgba(12,21,33,.95); box-shadow: 0 -16px 42px rgba(0,0,0,.4); transform: translateY(20px); animation: rise .18s ease forwards; }
|
||
@keyframes rise { to { transform: translateY(0); } }
|
||
.sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
|
||
.sheet-head h3 { margin: 0; font-size: var(--text-lg); }
|
||
.sheet-title-row { display: flex; align-items: center; gap: 8px; }
|
||
.close-btn { width: 32px; height: 32px; border: 1px solid var(--color-border); border-radius: 50%; background: var(--color-surface-soft); }
|
||
.back-btn { width: 32px; height: 32px; border: 1px solid var(--color-border); border-radius: 50%; background: var(--color-surface-soft); }
|
||
.action-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
|
||
.action-item { min-height: 58px; border: 1px solid rgba(213,235,255,.13); border-radius: 14px; background: rgba(116,185,255,.07); color: var(--color-text); transition: all .15s ease; }
|
||
.action-item:hover { border-color: rgba(116,185,255,.5); background: rgba(116,185,255,.16); transform: translateY(-2px); }
|
||
.action-item b { display: block; font-size: 20px; }
|
||
.action-item span { color: var(--color-text-muted); font-size: 10px; }
|
||
.menu-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
|
||
.menu-item { min-height: 88px; padding: 10px 7px; border: 1px solid rgba(213,235,255,.16); border-radius: 15px; background: linear-gradient(145deg, rgba(116,185,255,.13), rgba(10,16,24,.35)); color: var(--color-text); text-align: center; transition: transform .15s ease, border-color .15s ease, background .15s ease; }
|
||
.menu-item:hover, .menu-item:focus-visible { transform: translateY(-2px); border-color: rgba(255,211,108,.72); background: rgba(116,185,255,.23); outline: none; }
|
||
.menu-item b { display: block; margin-bottom: 5px; color: var(--color-accent); font-size: 25px; line-height: 1; }
|
||
.menu-item span { display: block; font-size: var(--text-sm); }
|
||
.menu-item small { display: block; margin-top: 4px; color: var(--color-text-muted); font-size: 9px; line-height: 1.3; }
|
||
.sheet-note { margin: 10px 0 0; color: var(--color-text-muted); font-size: var(--text-xs); line-height: 1.4; }
|
||
.chat-list { display: grid; gap: 8px; margin-bottom: 10px; }
|
||
.chat-line { padding: 8px 10px; border-radius: 12px; background: rgba(255,255,255,.055); font-size: var(--text-sm); }
|
||
.chat-line strong { color: var(--color-primary); }
|
||
.chat-compose { display: flex; gap: 8px; }
|
||
.chat-compose input { min-width: 0; flex: 1; padding: 10px; border: 1px solid var(--color-border); border-radius: 12px; background: rgba(0,0,0,.25); color: var(--color-text); outline: none; }
|
||
.send-btn { padding: 0 13px; border: 1px solid rgba(101,225,178,.4); border-radius: 12px; background: rgba(101,225,178,.14); color: #adffe1; }
|
||
.annotation-label { position: fixed; z-index: 50; display: none; padding: 5px 7px; pointer-events: none; border: 1px solid rgba(255,211,108,.45); border-radius: 7px; background: #101a27; color: #ffe4a0; font: 11px var(--font-mono); box-shadow: var(--shadow-sm); }
|
||
body.annotate [data-label]:hover { outline: 1px dashed rgba(255,211,108,.7); outline-offset: 3px; }
|
||
.toolbar { position: fixed; z-index: 30; right: 16px; bottom: 16px; display: flex; align-items: center; gap: 7px; padding: 8px 10px; border: 1px solid rgba(255,255,255,.16); border-radius: 12px; background: rgba(5,9,14,.78); color: #fff; font-size: 11px; opacity: .44; transition: opacity .2s ease; backdrop-filter: blur(12px); }
|
||
.toolbar:hover { opacity: 1; }
|
||
.toolbar button, .toolbar select { border: 1px solid rgba(255,255,255,.19); border-radius: 7px; padding: 5px 7px; background: rgba(255,255,255,.08); color: #fff; }
|
||
.toolbar button:hover, .toolbar select:hover { background: rgba(116,185,255,.22); }
|
||
.toast { position: fixed; z-index: 60; left: 50%; bottom: 72px; transform: translate(-50%, 12px); padding: 9px 14px; opacity: 0; border: 1px solid rgba(213,235,255,.28); border-radius: 12px; background: rgba(9,16,25,.93); color: var(--color-text); box-shadow: var(--shadow-md); transition: all .18s ease; pointer-events: none; font-size: var(--text-sm); }
|
||
.toast.show { opacity: 1; transform: translate(-50%, 0); }
|
||
.interaction-section { max-width: 1040px; margin: 54px auto 0; }
|
||
.interaction-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 18px; }
|
||
.interaction-head h2 { margin: 5px 0 6px; font-size: clamp(1.35rem, 2.6vw, 2rem); }
|
||
.interaction-head p { max-width: 720px; margin: 0; color: #c6b399; line-height: 1.55; }
|
||
.interaction-legend { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; max-width: 330px; }
|
||
.legend-chip { display: inline-flex; align-items: center; gap: 5px; padding: 6px 9px; border: 1px solid rgba(224, 181, 105, .26); border-radius: 999px; background: rgba(93, 53, 25, .2); color: #d8bd91; font-size: 10px; white-space: nowrap; }
|
||
.legend-chip i { width: 7px; height: 7px; border-radius: 50%; background: #e0b15e; box-shadow: 0 0 8px rgba(224, 177, 91, .7); }
|
||
.legend-chip.menu i { background: #8f6be8; box-shadow: 0 0 8px rgba(143, 107, 232, .7); }
|
||
.legend-chip.full i { background: #68baa0; box-shadow: 0 0 8px rgba(104, 186, 160, .7); }
|
||
.legend-chip.modal i { background: #e26c5c; box-shadow: 0 0 8px rgba(226, 108, 92, .7); }
|
||
.flow-filter { display: flex; flex-wrap: wrap; gap: 7px; margin: 0 0 14px; }
|
||
.flow-filter button { padding: 7px 12px; border: 1px solid rgba(224, 181, 105, .24); border-radius: 999px; background: rgba(44, 24, 14, .62); color: #c8b18e; font-size: 11px; }
|
||
.flow-filter button.active, .flow-filter button:hover { border-color: rgba(239, 195, 113, .72); background: rgba(163, 100, 44, .28); color: #f5d998; }
|
||
.flow-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
||
.flow-card { min-width: 0; padding: 14px; border: 1px solid rgba(224, 181, 105, .25); border-radius: 16px; background: linear-gradient(145deg, rgba(64, 35, 20, .72), rgba(20, 11, 8, .88)); box-shadow: 0 10px 26px rgba(0,0,0,.18); }
|
||
.flow-card.is-hidden { display: none; }
|
||
.flow-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
|
||
.flow-card-head h3 { margin: 0; color: #f4e0b5; font-size: 14px; }
|
||
.flow-index { color: #d8a758; font: 11px var(--font-mono); letter-spacing: .08em; }
|
||
.flow-scope { color: #a99478; font-size: 10px; }
|
||
.flow-track { display: flex; align-items: stretch; gap: 6px; overflow-x: auto; padding: 2px 1px 5px; scrollbar-width: thin; }
|
||
.flow-node { position: relative; min-width: 104px; min-height: 67px; padding: 9px 8px; border: 1px solid rgba(224, 181, 105, .24); border-radius: 12px; background: rgba(16, 9, 7, .8); color: #f5ead7; text-align: left; transition: transform .15s ease, border-color .15s ease, background .15s ease; }
|
||
.flow-node:hover, .flow-node:focus-visible { transform: translateY(-2px); border-color: rgba(239, 195, 113, .85); background: rgba(117, 68, 32, .36); outline: none; }
|
||
.flow-node b { display: block; margin-bottom: 5px; font-size: 12px; }
|
||
.flow-node small { display: block; color: #bba586; font-size: 10px; line-height: 1.35; }
|
||
.flow-node.menu-node { border-color: rgba(143, 107, 232, .4); }
|
||
.flow-node.full-node { border-color: rgba(104, 186, 160, .4); }
|
||
.flow-node.modal-node { border-color: rgba(226, 108, 92, .42); }
|
||
.flow-arrow { align-self: center; flex: 0 0 auto; color: #d8a758; font-size: 16px; opacity: .78; }
|
||
.flow-detail { margin-top: 14px; min-height: 132px; padding: 16px 18px; border: 1px solid rgba(239, 195, 113, .34); border-radius: 16px; background: rgba(20, 10, 7, .84); box-shadow: 0 15px 32px rgba(0,0,0,.22); }
|
||
.flow-detail.empty { display: grid; place-items: center; color: #bba586; text-align: center; }
|
||
.flow-detail h3 { margin: 4px 0 8px; color: #f4e0b5; font-size: 17px; }
|
||
.detail-kicker { color: #d8a758; font: 10px var(--font-mono); letter-spacing: .14em; text-transform: uppercase; }
|
||
.detail-grid { display: grid; grid-template-columns: 1.1fr 1fr 1fr; gap: 14px; }
|
||
.detail-block strong { display: block; margin-bottom: 4px; color: #d8bd91; font-size: 11px; }
|
||
.detail-block p { margin: 0; color: #c8b18e; font-size: 11px; line-height: 1.5; }
|
||
.detail-block p + p { margin-top: 4px; }
|
||
.flow-note { margin: 12px 0 0; padding-top: 10px; border-top: 1px solid rgba(224, 181, 105, .14); color: #9f8b70; font-size: 10px; line-height: 1.5; }
|
||
.hidden { display: none !important; }
|
||
@media (max-width: 620px) { body { padding-inline: 10px; } .variant-intro { display: block; padding-inline: 4px; } .variant-intro p { margin-top: 4px; } .toolbar { right: 8px; bottom: 8px; } }
|
||
|
||
/* Diablo-inspired ARPG direction: warm bronze frames, dark glass, circular combat controls. */
|
||
body { background: radial-gradient(circle at 50% 0%, #3a2416 0, #170e0b 35rem, #090706 70rem); }
|
||
.page-head p { color: #c6b399; }
|
||
.device { border-color: rgba(224, 181, 105, .72); border-radius: 22px; box-shadow: 0 28px 80px rgba(0,0,0,.7), 0 0 0 6px rgba(204, 147, 64, .08), inset 0 0 0 1px rgba(255, 229, 175, .14); }
|
||
.scene { background: linear-gradient(145deg, #725031, #b98045 40%, #4b2b1d 78%, #1b100c); }
|
||
.scene::before { opacity: .7; background: radial-gradient(ellipse at 34% 40%, rgba(255, 224, 152, .28), transparent 24%), radial-gradient(ellipse at 70% 28%, rgba(42, 16, 13, .4), transparent 27%), repeating-linear-gradient(151deg, rgba(255, 220, 155, .06) 0 2px, transparent 2px 38px); }
|
||
.scene::after { background: linear-gradient(180deg, rgba(12, 7, 5, .54), transparent 20%, transparent 62%, rgba(8, 5, 4, .7)); }
|
||
.terrain { opacity: .62; background: repeating-linear-gradient(164deg, transparent 0 17px, rgba(70, 35, 18, .18) 18px 20px), repeating-linear-gradient(22deg, transparent 0 35px, rgba(255, 218, 152, .16) 36px 38px); }
|
||
.hero { background: linear-gradient(90deg, #1a1210, #d2a85d 43%, #6b3d25 59%, #110b09); box-shadow: 0 0 20px rgba(255, 198, 93, .48); }
|
||
.hero::before { background: radial-gradient(circle at 40% 42%, #ffe0b2 0 18%, #6d3b2b 19% 54%, #160e0c 55%); }
|
||
.hero::after { color: #ffe0a1; text-shadow: 0 0 14px #ef812e; }
|
||
.mob { background: linear-gradient(140deg, #493021, #963f32 45%, #1c1110); box-shadow: 0 0 18px rgba(214, 69, 45, .35); }
|
||
.mob::before { background: #4f1e1b; }
|
||
.mob::after { color: #ffc0a0; }
|
||
.top-status { top: 15px; left: 18px; right: auto; }
|
||
.player-status { display: flex; width: 148px; flex-direction: column; align-items: center; gap: 3px; }
|
||
.player-name { display: flex; width: 148px; align-items: center; justify-content: center; gap: 6px; color: #f4e0b5; font: 600 11px var(--font-mono); text-shadow: 0 2px 4px #000; white-space: nowrap; }
|
||
.player-meters { width: 44px; }
|
||
.party-rail { position: absolute; z-index: 4; top: 112px; left: 18px; display: grid; width: 148px; gap: 5px; }
|
||
.party-member { display: grid; grid-template-columns: 27px minmax(0, 1fr) auto; align-items: center; gap: 6px; min-height: 34px; padding: 4px 6px 4px 4px; border: 1px solid rgba(223, 181, 111, .32); border-radius: 8px; background: rgba(19, 10, 7, .65); color: #f4e0b5; text-align: left; box-shadow: 0 4px 10px rgba(0,0,0,.28); transition: transform .15s ease, border-color .15s ease, background .15s ease; }
|
||
.party-member:hover, .party-member:focus-visible { transform: translateX(2px); border-color: rgba(239, 195, 113, .76); background: rgba(87, 46, 22, .78); outline: none; }
|
||
.party-avatar { display: grid; width: 25px; height: 25px; place-items: center; border: 1px solid rgba(239, 195, 112, .6); border-radius: 50%; background: radial-gradient(circle, #89684e, #291711 68%); color: #f7d58f; font-size: 12px; }
|
||
.party-copy { min-width: 0; }
|
||
.party-copy strong { display: block; overflow: hidden; color: #e9d5ae; font-size: 9px; line-height: 1.15; text-overflow: ellipsis; white-space: nowrap; }
|
||
.party-hp { height: 4px; margin-top: 3px; overflow: hidden; border-radius: 4px; background: rgba(5, 3, 2, .72); }
|
||
.party-hp i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, #8a2525, #e85a46); }
|
||
.party-distance { color: #bfa77f; font: 9px var(--font-mono); }
|
||
.top-right-controls { position: absolute; z-index: 4; top: 14px; right: 14px; display: flex; align-items: flex-start; gap: 7px; }
|
||
.top-right-controls .menu-button { min-width: 42px; width: 42px; height: 42px; flex: 0 0 auto; background: rgba(17, 9, 7, .78); border-color: rgba(224, 177, 91, .5); box-shadow: 0 4px 10px rgba(0,0,0,.42); }
|
||
.avatar { border-color: rgba(239, 195, 112, .92); background: radial-gradient(circle, #99704c, #2b1a13 62%, #0d0907); box-shadow: 0 0 0 3px rgba(13, 8, 6, .7), 0 0 16px rgba(231, 167, 68, .22); }
|
||
.level { color: #f4ca7b; }
|
||
.meter { height: 9px; border-color: rgba(255, 227, 170, .25); background: rgba(11, 6, 5, .82); box-shadow: inset 0 1px 2px rgba(0,0,0,.45); }
|
||
.meter.hp i { background: linear-gradient(90deg, #761b1e, #e2432c 72%, #ff8961); }
|
||
.meter.mp i { background: linear-gradient(90deg, #3c247f, #8454f0 72%, #c58aff); }
|
||
.mini-map { width: 142px; height: 86px; border-radius: 9px; border-color: rgba(223, 187, 119, .72); background: radial-gradient(circle at 43% 58%, rgba(226, 179, 83, .42) 0 7%, transparent 8%), linear-gradient(32deg, #21150e 0 31%, #6a4323 32% 39%, #271711 40% 63%, #80603b 64%); box-shadow: inset 0 0 0 4px rgba(8, 5, 4, .68), 0 6px 14px rgba(0,0,0,.48); }
|
||
.mini-map::before { left: 47%; top: 43%; background: #f8d17e; box-shadow: 0 0 0 4px rgba(255, 205, 106, .2), 16px -20px 0 -2px #d65838; }
|
||
.mini-map::after { content: "荒漠边境"; position: absolute; right: 7px; bottom: 5px; color: rgba(245, 213, 157, .7); font: 10px var(--font-mono); letter-spacing: .08em; }
|
||
.target-card { top: 13px; width: 260px; padding: 4px 12px 6px; border: 0; border-radius: 0; background: rgba(13, 8, 6, .2); box-shadow: none; text-align: center; }
|
||
.target-card strong { color: #f4e0b5; font: 600 15px var(--font-mono); letter-spacing: .1em; text-shadow: 0 2px 4px #000; }
|
||
.target-card small { color: #d0b285; }
|
||
.target-card .meter { height: 11px; margin-top: 5px; border-color: rgba(10, 5, 4, .9); }
|
||
.target-card .meter i { background: linear-gradient(90deg, #6d171a, #d43d2e 75%, #f06d45); }
|
||
.quest-pill { top: 109px; right: 168px; border-color: rgba(224, 177, 91, .38); background: rgba(24, 13, 9, .65); color: #f1d49a; box-shadow: 0 5px 13px rgba(0,0,0,.25); }
|
||
.chat-bubble { top: 57%; background: rgba(17, 9, 7, .72); border-color: rgba(236, 197, 133, .28); color: #f4e6cb; }
|
||
.context-action { right: 235px; bottom: 104px; border-color: rgba(219, 173, 93, .58); background: rgba(25, 12, 8, .74); color: #f6d593; box-shadow: 0 5px 15px rgba(0,0,0,.32); }
|
||
.right-rail { position: absolute; z-index: 4; top: 111px; right: 14px; display: grid; gap: 8px; }
|
||
.right-rail .utility-btn { min-width: 42px; width: 42px; height: 42px; flex: 0 0 auto; background: rgba(17, 9, 7, .64); border-color: rgba(216, 171, 99, .3); box-shadow: 0 4px 10px rgba(0,0,0,.3); }
|
||
.right-rail .utility-btn span { color: #d8bd91; }
|
||
.joystick { left: 25px; bottom: 18px; width: 120px; height: 120px; border-color: rgba(223, 181, 111, .32); background: radial-gradient(circle, rgba(185, 119, 58, .26) 0 28%, rgba(74, 39, 22, .42) 29% 62%, rgba(12, 7, 5, .26) 63%); box-shadow: inset 0 0 0 12px rgba(27, 13, 8, .28), 0 7px 18px rgba(0,0,0,.35); }
|
||
.joystick::before { border-color: rgba(238, 202, 139, .2); }
|
||
.stick { border-color: rgba(236, 194, 117, .58); background: radial-gradient(circle at 35% 28%, rgba(255, 239, 196, .28), rgba(114, 70, 38, .82) 38%, rgba(30, 14, 9, .94)); }
|
||
.combat-cluster { right: 20px; bottom: 15px; width: 190px; height: 190px; }
|
||
.combat-cluster::before { content: ""; position: absolute; inset: 16px -1px -2px 8px; border: 1px solid rgba(185, 132, 68, .3); border-radius: 50%; background: radial-gradient(circle, rgba(21, 10, 8, .56), rgba(12, 6, 5, .12) 68%, transparent 69%); box-shadow: 0 0 0 11px rgba(12, 6, 5, .18); }
|
||
.combat-cluster::after { content: ""; position: absolute; inset: 5px -4px 12px 5px; border: 2px solid rgba(219, 169, 83, .28); border-left-color: transparent; border-bottom-color: transparent; border-radius: 50%; transform: rotate(34deg); pointer-events: none; }
|
||
.skill { z-index: 1; width: 58px; height: 58px; border-color: rgba(232, 191, 115, .58); background: radial-gradient(circle at 35% 26%, rgba(247, 225, 177, .24), rgba(62, 28, 22, .94) 46%, rgba(12, 6, 6, .98)); box-shadow: 0 6px 14px rgba(0,0,0,.6), inset 0 0 0 3px rgba(6, 3, 3, .36); }
|
||
.skill:hover, .skill:focus-visible { border-color: #f4d28d; filter: brightness(1.3); box-shadow: 0 0 0 3px rgba(238, 187, 90, .2), 0 7px 16px rgba(0,0,0,.6); }
|
||
.skill.main { width: 88px; height: 88px; border-color: rgba(234, 196, 123, .86); background: radial-gradient(circle at 35% 25%, #7e5cf1, #321d75 48%, #0e0820 78%); box-shadow: 0 0 0 4px rgba(15, 7, 28, .75), 0 0 18px rgba(107, 65, 220, .6), 0 7px 17px rgba(0,0,0,.65); font-size: 31px; }
|
||
.skill.main:hover, .skill.main:focus-visible { box-shadow: 0 0 0 5px rgba(232, 190, 100, .27), 0 0 24px rgba(138, 92, 255, .78); }
|
||
.skill.s1 { left: 10px; top: 14px; }
|
||
.skill.s2 { left: 62px; top: 70px; }
|
||
.skill.s3 { right: 2px; top: 15px; }
|
||
.skill.s4 { left: 13px; bottom: 2px; }
|
||
#mobile-hud .skill.s4 { left: auto; right: 16px; top: -52px; bottom: auto; border-color: rgba(223, 66, 44, .86); background: radial-gradient(circle at 35% 25%, #f06a40, #7d1f25 45%, #1a080b 78%); }
|
||
.skill em { background: #140907; color: #f2d491; }
|
||
.utility-btn { border-color: rgba(215, 171, 98, .2); border-radius: 7px; background: rgba(124, 76, 40, .16); }
|
||
.utility-btn:hover, .utility-btn.active { border-color: rgba(240, 200, 123, .72); background: rgba(173, 107, 46, .28); }
|
||
.utility-btn span { color: #cdb58d; }
|
||
.modal-layer { background: rgba(7, 3, 2, .6); }
|
||
.sheet { border-top-color: rgba(226, 181, 99, .5); background: rgba(25, 14, 10, .97); }
|
||
.action-item { border-color: rgba(220, 176, 100, .24); background: rgba(139, 82, 40, .12); }
|
||
.action-item:hover { border-color: rgba(239, 195, 113, .7); background: rgba(163, 100, 44, .24); }
|
||
.action-item span, .sheet-note { color: #c8b18e; }
|
||
.menu-item { border-color: rgba(220, 176, 100, .3); background: linear-gradient(145deg, rgba(128, 73, 34, .38), rgba(30, 15, 9, .72)); box-shadow: inset 0 1px 0 rgba(255, 224, 163, .08), 0 6px 14px rgba(0,0,0,.2); }
|
||
.menu-item:hover, .menu-item:focus-visible { border-color: rgba(239, 195, 113, .82); background: linear-gradient(145deg, rgba(164, 95, 40, .52), rgba(44, 20, 10, .82)); }
|
||
.menu-item b { color: #f0c979; }
|
||
.menu-item small { color: #bda887; }
|
||
.send-btn { border-color: rgba(117, 186, 123, .5); background: rgba(75, 122, 73, .2); color: #c3e8b9; }
|
||
.toolbar { background: rgba(10, 6, 4, .88); border-color: rgba(228, 183, 103, .32); }
|
||
.toolbar button:hover, .toolbar select:hover { background: rgba(171, 104, 43, .28); }
|
||
.toast { background: rgba(20, 10, 7, .96); border-color: rgba(224, 178, 98, .42); }
|
||
@media (max-height: 460px) and (orientation: landscape) {
|
||
body { padding-top: 66px; }
|
||
.top-status { top: 10px; }
|
||
.player-status, .player-name { width: 122px; }
|
||
.player-meters { width: 44px; }
|
||
.player-name { font-size: 9px; }
|
||
.party-rail { top: 91px; left: 10px; width: 122px; gap: 4px; }
|
||
.party-member { min-height: 30px; padding-block: 3px; }
|
||
.party-avatar { width: 22px; height: 22px; font-size: 10px; }
|
||
.top-right-controls { top: 9px; right: 9px; }
|
||
.mini-map { width: 108px; height: 64px; }
|
||
.right-rail { top: 82px; }
|
||
.status-copy { flex-basis: 122px; width: 122px; }
|
||
.quest-pill { top: 84px; right: 128px; }
|
||
.target-card { top: 8px; }
|
||
.joystick { width: 96px; height: 96px; left: 18px; bottom: 13px; }
|
||
.combat-cluster { right: 14px; bottom: 10px; transform: scale(.82); transform-origin: bottom right; }
|
||
.context-action { bottom: 88px; }
|
||
}
|
||
@media (max-width: 820px) {
|
||
.interaction-head { display: block; }
|
||
.interaction-legend { justify-content: flex-start; margin-top: 12px; }
|
||
.flow-grid { grid-template-columns: 1fr; }
|
||
.detail-grid { grid-template-columns: 1fr; gap: 9px; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header class="page-head">
|
||
<div class="eyebrow">Mobile ARPG Control HUD / Sketch 001</div>
|
||
<h1>暗黑 ARPG 风格 · 横屏 HUD 草图</h1>
|
||
<p>按 844×390 横屏手机设计,保持世界画面优先,战斗操作触手可达;底部中央保持留白,低频功能统一收纳到右上角菜单。点击首页控件或下方交互图节点,查看完整的移动端 UI 流程。</p>
|
||
</header>
|
||
|
||
<main id="sketch-canvas" class="preview-phone">
|
||
<section id="mobile-hud" class="variant">
|
||
<div class="variant-intro"><h2>暗黑 ARPG 横屏 HUD</h2><p>左上按“名称→头像→HP/MP/资源短条”排列;右上按“背包→小地图→菜单”排列,地图通过点击小地图进入,底部中央保持留白。</p></div>
|
||
<div class="device-wrap"><div class="device" data-label="844 × 390 landscape · 暗黑 ARPG">
|
||
<div class="scene">
|
||
<div class="terrain"></div><div class="hero" data-label="玩家角色"></div><div class="mob"></div>
|
||
<div class="top-status" data-label="玩家状态"><div class="player-status"><div class="player-name"><span>Azure · 暮光骑士</span><span class="level">Lv.42</span></div><button class="avatar demo-btn" data-panel="character" data-label="打开角色状态">♜</button><div class="player-meters"><div class="meter hp" aria-label="生命值"><i></i></div><div class="meter mp" aria-label="法力值"><i></i></div><div class="meter resource" aria-label="职业资源:奥能 68%"><i></i></div></div></div></div>
|
||
<div class="party-rail" data-label="队伍信息:仅组队后显示"><button class="party-member demo-btn" data-panel="party" data-label="队员 Mira · 点击查看或定位"><span class="party-avatar">M</span><span class="party-copy"><strong>Mira · 圣骑士</strong><span class="party-hp"><i style="width: 83%"></i></span></span><span class="party-distance">12m</span></button><button class="party-member demo-btn" data-panel="party" data-label="队员 Ken · 点击查看或定位"><span class="party-avatar">K</span><span class="party-copy"><strong>Ken · 游侠</strong><span class="party-hp"><i style="width: 61%"></i></span></span><span class="party-distance">34m</span></button></div>
|
||
<div class="top-right-controls" data-label="顶部背包、地图与菜单"><button class="utility-btn top-bag demo-btn" data-panel="inventory" data-label="打开背包">▦<span>背包</span></button><button class="mini-map demo-btn" data-panel="map" aria-label="打开地图" data-label="小地图 / 地图"></button><button class="utility-btn menu-button demo-btn" data-panel="more" data-label="打开菜单">☰<span>菜单</span></button></div>
|
||
<button class="target-card demo-btn" data-panel="target" data-label="目标板"><strong>血狼 · Lv.40</strong><small>敌对目标</small><div class="meter"><i></i></div></button>
|
||
<button class="quest-pill demo-btn" data-panel="quest" data-label="任务追踪">◆ 采集狼牙 <b>2/5</b></button>
|
||
<div class="chat-bubble" data-label="头顶聊天气泡">附近:小心精英怪!</div>
|
||
<button class="context-action demo-btn" data-toast="靠近目标后:拾取 / 对话 / 钓鱼 / 进入副本">✦ 交互</button>
|
||
<div class="joystick" data-joystick data-label="虚拟摇杆"><div class="stick"></div></div>
|
||
<div class="combat-cluster" data-label="战斗技能区">
|
||
<button class="skill s1 demo-btn" data-skill="冰刃" data-toast="释放技能:冰刃">❄<em>8</em></button>
|
||
<button class="skill s2 demo-btn" data-skill="冲锋" data-toast="释放技能:冲锋">➤<em>5</em></button>
|
||
<button class="skill s3 demo-btn" data-skill="治疗" data-toast="释放技能:治疗">✚<em>12</em></button>
|
||
<button class="skill s4 demo-btn" data-skill="药水" data-toast="使用物品:红色药水">♥<em>3</em></button>
|
||
<button class="skill main demo-btn" data-skill="普攻" data-toast="普通攻击">⚔</button>
|
||
</div>
|
||
<div class="floating-cooldown" data-cooldown>技能冷却中</div>
|
||
<div class="modal-layer" data-modal><div class="sheet"><div class="sheet-head"><div class="sheet-title-row"><button class="back-btn hidden" data-back aria-label="返回上一级">←</button><h3 data-sheet-title>功能</h3></div><button class="close-btn" data-close>×</button></div><div data-sheet-body></div></div></div>
|
||
</div>
|
||
</div></div>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
<section class="interaction-section" aria-labelledby="interaction-title">
|
||
<div class="interaction-head">
|
||
<div>
|
||
<div class="eyebrow">Interaction map / all screens</div>
|
||
<h2 id="interaction-title">全量 UI 移动端交互图</h2>
|
||
<p>每张图表示一条完整操作路径。点击任意节点,查看它的入口位置、触控方式、页面形态和返回路径;任务始终从任务栏进入,组队信息固定显示在左上玩家头像下方。</p>
|
||
</div>
|
||
<div class="interaction-legend" aria-label="页面形态图例">
|
||
<span class="legend-chip"><i></i>常驻 HUD</span>
|
||
<span class="legend-chip menu"><i></i>右上角菜单</span>
|
||
<span class="legend-chip full"><i></i>全屏面板</span>
|
||
<span class="legend-chip modal"><i></i>场景弹窗</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flow-filter" role="tablist" aria-label="交互图筛选">
|
||
<button class="active" data-flow-filter="all" role="tab" aria-selected="true">全部流程</button>
|
||
<button data-flow-filter="entry" role="tab" aria-selected="false">进入游戏</button>
|
||
<button data-flow-filter="combat" role="tab" aria-selected="false">战斗与任务</button>
|
||
<button data-flow-filter="character" role="tab" aria-selected="false">角色与物品</button>
|
||
<button data-flow-filter="social" role="tab" aria-selected="false">社交与经济</button>
|
||
<button data-flow-filter="system" role="tab" aria-selected="false">系统状态</button>
|
||
</div>
|
||
|
||
<div class="flow-grid" id="flow-grid">
|
||
<article class="flow-card" data-flow-group="entry">
|
||
<div class="flow-card-head"><h3>进入游戏与角色入口</h3><span class="flow-index">01 · ENTRY</span></div>
|
||
<div class="flow-track">
|
||
<button class="flow-node full-node" data-detail="login"><b>登录</b><small>账号密码<br>失败提示</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="server"><b>服务器</b><small>频道选择<br>连接确认</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="character_select"><b>角色列表</b><small>选择 / 创建<br>删除 / 改名</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="loading"><b>加载</b><small>资源加载<br>进入场景</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node" data-detail="hud"><b>首页 HUD</b><small>开始操作</small></button>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="flow-card" data-flow-group="combat">
|
||
<div class="flow-card-head"><h3>首页战斗与掉落</h3><span class="flow-index">02 · COMBAT</span></div>
|
||
<div class="flow-track">
|
||
<button class="flow-node" data-detail="hud"><b>首页 HUD</b><small>左上状态<br>右上入口</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node" data-detail="movement"><b>移动摇杆</b><small>拖动移动<br>松手复位</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node" data-detail="target"><b>锁定目标</b><small>点击目标<br>显示血条</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node" data-detail="combat_action"><b>普攻 / 技能</b><small>点击释放<br>冷却反馈</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="loot"><b>掉落 / 交互</b><small>拾取、对话<br>进入副本</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node" data-detail="death"><b>死亡 / 复活</b><small>战斗失败<br>回城或复活</small></button>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="flow-card" data-flow-group="combat">
|
||
<div class="flow-card-head"><h3>任务、地图与副本</h3><span class="flow-index">03 · QUEST</span></div>
|
||
<div class="flow-track">
|
||
<button class="flow-node" data-detail="quest"><b>任务栏</b><small>首页常驻<br>直接点击</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="quest_log"><b>任务日志</b><small>列表 / 奖励<br>任务详情</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="map"><b>小地图 / 大地图</b><small>点击小地图<br>地图信标</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node" data-detail="navigation"><b>自动寻路</b><small>导航至目标<br>到达提示</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="npc_quest"><b>NPC 对话</b><small>接取 / 完成<br>任务奖励</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="dungeon_result"><b>副本结算</b><small>奖励 / 再次挑战<br>退出副本</small></button>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="flow-card" data-flow-group="character">
|
||
<div class="flow-card-head"><h3>角色、装备与技能</h3><span class="flow-index">04 · CHARACTER</span></div>
|
||
<div class="flow-track">
|
||
<button class="flow-node" data-detail="character_entry"><b>玩家头像</b><small>左上角<br>唯一入口</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="character_status"><b>角色属性</b><small>等级、属性<br>成长信息</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="equipment"><b>装备</b><small>穿戴、替换<br>查看对比</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="skills"><b>技能</b><small>主动、被动<br>坐骑、表情</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="skill_upgrade"><b>技能加点</b><small>查看消耗<br>确认升级</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="inspect"><b>查看玩家</b><small>点击角色<br>查看装备</small></button>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="flow-card" data-flow-group="character">
|
||
<div class="flow-card-head"><h3>背包、物品与仓库</h3><span class="flow-index">05 · ITEMS</span></div>
|
||
<div class="flow-track">
|
||
<button class="flow-node menu-node" data-detail="inventory"><b>背包</b><small>右上快捷入口<br>菜单也可进入</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="item_tooltip"><b>物品详情</b><small>点击选中<br>长按查看</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="item_action"><b>使用 / 装备 / 出售</b><small>按钮操作<br>危险操作确认</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="safebox"><b>仓库</b><small>背包与仓库<br>左右切换</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="select_item"><b>任务物品选择</b><small>选择数量<br>提交确认</small></button>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="flow-card" data-flow-group="social">
|
||
<div class="flow-card-head"><h3>队伍状态、聊天、好友与公会</h3><span class="flow-index">06 · SOCIAL</span></div>
|
||
<div class="flow-track">
|
||
<button class="flow-node" data-detail="party"><b>左侧队伍条</b><small>头像下方<br>成员状态</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="party"><b>队员信息</b><small>查看 / 定位<br>离队设置</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node menu-node" data-detail="social_entry"><b>右上菜单</b><small>社交入口<br>不含队伍</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="chat"><b>聊天</b><small>综合、私聊<br>队伍、公会</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="friend"><b>好友</b><small>申请、私聊<br>查看资料</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="love"><b>情侣 / 爱意</b><small>关系信息<br>互动操作</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="guild"><b>公会</b><small>成员、技能<br>公告、公会战</small></button>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="flow-card" data-flow-group="social">
|
||
<div class="flow-card-head"><h3>商店、交易与制作</h3><span class="flow-index">07 · ECONOMY</span></div>
|
||
<div class="flow-track">
|
||
<button class="flow-node modal-node" data-detail="commerce_entry"><b>NPC / 玩家</b><small>靠近后点击<br>出现交互</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="shop"><b>商店 / 商城</b><small>购买、出售<br>商城物品</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="trade"><b>玩家交易</b><small>拖入物品<br>双方确认</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="private_shop"><b>私人商店</b><small>浏览、购买<br>摆摊管理</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="cube"><b>制作</b><small>放入材料<br>制作确认</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="refine"><b>精炼 / 龙魂</b><small>强化结果<br>失败确认</small></button>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="flow-card" data-flow-group="system">
|
||
<div class="flow-card-head"><h3>系统设置与异常状态</h3><span class="flow-index">08 · SYSTEM</span></div>
|
||
<div class="flow-track">
|
||
<button class="flow-node menu-node" data-detail="system_entry"><b>右上菜单</b><small>系统入口<br>随时可打开</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="options"><b>系统 / 游戏设置</b><small>音量、画面<br>操作、屏蔽</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node full-node" data-detail="help"><b>帮助</b><small>操作说明<br>功能说明</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="character_switch"><b>选择角色</b><small>离开当前角色<br>二次确认</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="logout"><b>登出 / 退出</b><small>保存状态<br>确认离开</small></button><span class="flow-arrow">→</span>
|
||
<button class="flow-node modal-node" data-detail="reconnect"><b>断线重连</b><small>连接恢复<br>重新进入场景</small></button>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
|
||
<aside class="flow-detail empty" id="flow-detail" aria-live="polite">
|
||
<div><div class="detail-kicker">Tap a node</div><p>点击上方任意节点,查看该界面的移动端入口、位置、交互方式和返回路径。</p></div>
|
||
</aside>
|
||
</section>
|
||
|
||
<div class="toolbar" id="sketch-tools" aria-label="草图工具">
|
||
<span>横屏预览</span><button data-viewport="phone">手机</button><button data-viewport="tablet">平板</button><button data-viewport="desktop">桌面</button>
|
||
<select id="theme-switcher" aria-label="主题"><option value="default">暗黑铜金</option></select>
|
||
<button id="annotation-toggle">标注</button>
|
||
</div>
|
||
<div class="toast" id="toast" role="status"></div><div class="annotation-label" id="annotation-label"></div>
|
||
|
||
<script>
|
||
const body = document.body;
|
||
const canvas = document.getElementById('sketch-canvas');
|
||
const toast = document.getElementById('toast');
|
||
let toastTimer;
|
||
const featureCatalog = [
|
||
['♟', '社交', 'social', '聊天 · 好友 · 公会'],
|
||
['✧', '成长', 'growth', '强化 · 制作 · 龙魂'],
|
||
['▣', '活动', 'adventure', '副本 · 钓鱼'],
|
||
['◈', '商业', 'market', '商店 · 交易 · 仓库'],
|
||
['⚙', '系统', 'system', '设置 · 帮助 · 退出']
|
||
];
|
||
const featureCopy = {
|
||
inventory: '<p class="sheet-note">装备 / 腰带 / 物品拖放 · 右侧滑出面板,回到战斗时自动收起。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="拖动红药到快捷栏">♥<span>红药 ×12</span></button><button class="action-item demo-btn" data-toast="查看装备">⚔<span>装备</span></button><button class="action-item demo-btn" data-toast="打开腰带">▤<span>腰带</span></button><button class="action-item demo-btn" data-toast="整理背包">✦<span>整理</span></button></div>',
|
||
character: '<p class="sheet-note">头像入口承载 HP / MP、状态、装备、技能、坐骑和表情动作。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="打开状态页">♥<span>状态</span></button><button class="action-item demo-btn" data-toast="查看装备">⚔<span>装备</span></button><button class="action-item demo-btn" data-panel="skills"><b>✦</b><span>技能</span></button><button class="action-item demo-btn" data-panel="mount"><b>♞</b><span>坐骑</span></button><button class="action-item demo-btn" data-panel="emote"><b>☺</b><span>表情</span></button><button class="action-item demo-btn" data-toast="打开称号页">◆<span>称号</span></button></div>',
|
||
quest: '<p class="sheet-note">任务追踪使用半透明卡片;点击任务行进入日志,地图信标从卡片右上角进入。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="追踪:采集狼牙">◆<span>追踪</span></button><button class="action-item demo-btn" data-toast="打开任务日志">▤<span>日志</span></button><button class="action-item demo-btn" data-toast="显示地图信标">⌖<span>导航</span></button><button class="action-item demo-btn" data-toast="收起任务条">×<span>隐藏</span></button></div>',
|
||
map: '<p class="sheet-note">小地图点击后升起全屏地图,保留副本目的地罗盘和任务信标。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="地图缩放 +">+<span>放大</span></button><button class="action-item demo-btn" data-toast="地图缩放 -">−<span>缩小</span></button><button class="action-item demo-btn" data-toast="查看世界地图">⌖<span>世界地图</span></button><button class="action-item demo-btn" data-toast="回到玩家位置">●<span>定位</span></button></div>',
|
||
target: '<p class="sheet-note">目标板支持切换目标、查看血量和情境动作;按住目标卡可进入更多交互。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="切换目标">⇄<span>切换</span></button><button class="action-item demo-btn" data-toast="开始自动攻击">⚔<span>攻击</span></button><button class="action-item demo-btn" data-toast="打开目标信息">? <span>信息</span></button><button class="action-item demo-btn" data-toast="取消目标">×<span>清除</span></button></div>',
|
||
chat: '<div class="chat-list"><div class="chat-line"><strong>[队伍]</strong> Mira:副本入口在北门。</div><div class="chat-line"><strong>[附近]</strong> 你:收到,马上到。</div><div class="chat-line"><strong>[公会]</strong> Ken:今晚 20:00 公会战。</div></div><div class="chat-compose"><input placeholder="输入消息…"><button class="send-btn" data-send>发送</button></div>',
|
||
party: '<p class="sheet-note">队伍信息从左上玩家头像下方的队员条进入;未组队时该区域自动隐藏。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="定位队员">⌖<span>定位</span></button><button class="action-item demo-btn" data-toast="查看队员资料">♟<span>资料</span></button><button class="action-item demo-btn" data-toast="打开队伍设置">⚙<span>设置</span></button><button class="action-item demo-btn" data-toast="离开队伍确认">×<span>离队</span></button></div>',
|
||
more: '<p class="sheet-note">菜单只保留五个一级入口;角色相关功能点击左上头像进入,背包、小地图和任务仍从首页直接进入。</p><div class="menu-grid">' + featureCatalog.map(([icon, name, key, note]) => `<button class="menu-item demo-btn" data-panel="${key}" data-toast="打开${name}"><b>${icon}</b><span>${name}</span><small>${note}</small></button>`).join('') + '</div>',
|
||
guild: '<p class="sheet-note">公会信息、成员、会徽、公会战和公告从左侧社交轨进入。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="打开公会成员">♟<span>成员</span></button><button class="action-item demo-btn" data-toast="查看公会技能">✧<span>技能</span></button><button class="action-item demo-btn" data-toast="查看公会会徽">✦<span>会徽</span></button><button class="action-item demo-btn" data-toast="查看公会战">⚔<span>公会战</span></button></div>'
|
||
};
|
||
Object.assign(featureCopy, {
|
||
social: '<p class="sheet-note">社交菜单只保留聊天、好友、公会、情侣和观战;队伍状态固定在左上玩家头像下方。</p><div class="action-grid"><button class="action-item demo-btn" data-panel="chat"><b>☵</b><span>聊天</span></button><button class="action-item demo-btn" data-panel="friend"><b>♧</b><span>好友</span></button><button class="action-item demo-btn" data-panel="guild"><b>♜</b><span>公会</span></button><button class="action-item demo-btn" data-panel="love"><b>♥</b><span>情侣</span></button><button class="action-item demo-btn" data-panel="observer"><b>◉</b><span>观战</span></button></div>',
|
||
growth: '<p class="sheet-note">成长功能统一处理角色长期养成;技能、坐骑和表情仍归入角色页面,避免重复入口。</p><div class="action-grid"><button class="action-item demo-btn" data-panel="refine"><b>⚒</b><span>精炼</span></button><button class="action-item demo-btn" data-panel="dragon"><b>✧</b><span>龙魂</span></button><button class="action-item demo-btn" data-panel="cube"><b>▣</b><span>制作</span></button></div>',
|
||
adventure: '<p class="sheet-note">活动通过任务追踪、场景交互或这里进入;地图仍只通过右上小地图打开。</p><div class="action-grid"><button class="action-item demo-btn" data-panel="dungeon"><b>▣</b><span>副本</span></button><button class="action-item demo-btn" data-panel="fishing"><b>♨</b><span>钓鱼</span></button></div>',
|
||
market: '<p class="sheet-note">涉及货币与物品流转的功能统一归入商业;背包仍在首页右上角单独打开。</p><div class="action-grid"><button class="action-item demo-btn" data-panel="shop"><b>▤</b><span>商店</span></button><button class="action-item demo-btn" data-panel="mall"><b>◈</b><span>商城</span></button><button class="action-item demo-btn" data-panel="trade"><b>⇄</b><span>交易</span></button><button class="action-item demo-btn" data-panel="private_shop"><b>▥</b><span>私人商店</span></button><button class="action-item demo-btn" data-panel="safebox"><b>▤</b><span>仓库</span></button><button class="action-item demo-btn" data-panel="exchange"><b>↔</b><span>兑换</span></button></div>',
|
||
friend: '<p class="sheet-note">好友与申请使用统一列表;选择好友后可私聊、查看资料或邀请组队。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="查看好友申请">+<span>申请</span></button><button class="action-item demo-btn" data-toast="打开好友资料">♧<span>资料</span></button><button class="action-item demo-btn" data-toast="发起私聊">☵<span>私聊</span></button><button class="action-item demo-btn" data-toast="邀请组队">♟<span>组队</span></button></div>',
|
||
love: '<p class="sheet-note">情侣与爱意信息放在社交分组内,避免成为首页固定入口。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="查看关系信息">♥<span>关系</span></button><button class="action-item demo-btn" data-toast="查看爱意等级">✦<span>等级</span></button><button class="action-item demo-btn" data-toast="发送互动">☺<span>互动</span></button><button class="action-item demo-btn" data-toast="打开情侣设置">⚙<span>设置</span></button></div>',
|
||
skills: '<p class="sheet-note">技能分为主动、被动、坐骑和表情动作;战斗中的技能按钮由此处配置。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="打开主动技能">❄<span>主动</span></button><button class="action-item demo-btn" data-toast="打开被动技能">✧<span>被动</span></button><button class="action-item demo-btn" data-toast="打开坐骑技能">♞<span>坐骑</span></button><button class="action-item demo-btn" data-toast="打开表情动作">☺<span>表情</span></button></div>',
|
||
shop: '<p class="sheet-note">NPC 商店支持购买和出售;商城使用同一套商品详情与确认交互。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="打开购买列表">+<span>购买</span></button><button class="action-item demo-btn" data-toast="打开出售列表">−<span>出售</span></button><button class="action-item demo-btn" data-toast="查看商品详情">? <span>详情</span></button><button class="action-item demo-btn" data-toast="确认交易金额">✓<span>确认</span></button></div>',
|
||
mall: '<p class="sheet-note">商城从菜单进入,购买前查看价格、限购和获得方式,支付动作使用二次确认。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="浏览商城分类">▤<span>分类</span></button><button class="action-item demo-btn" data-toast="查看商品详情">? <span>详情</span></button><button class="action-item demo-btn" data-toast="加入购物车">+<span>加入</span></button><button class="action-item demo-btn" data-toast="确认购买">✓<span>购买</span></button></div>',
|
||
safebox: '<p class="sheet-note">仓库采用背包与仓库左右切换;长按物品看详情,拖动完成存入或取出。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="存入仓库">↓<span>存入</span></button><button class="action-item demo-btn" data-toast="取出物品">↑<span>取出</span></button><button class="action-item demo-btn" data-toast="整理仓库">✦<span>整理</span></button><button class="action-item demo-btn" data-toast="切换商城仓库">▤<span>商城仓库</span></button></div>',
|
||
trade: '<p class="sheet-note">玩家交易通过点击玩家或交互按钮进入;双方放入物品后分别确认,避免误操作。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="拖入交易物品">⇄<span>放入</span></button><button class="action-item demo-btn" data-toast="查看对方物品">? <span>查看</span></button><button class="action-item demo-btn" data-toast="锁定交易内容">▣<span>锁定</span></button><button class="action-item demo-btn" data-toast="等待对方确认">✓<span>确认</span></button></div>',
|
||
private_shop: '<p class="sheet-note">私人商店通过点击摊位或玩家进入;浏览和摆摊管理共用一个全屏面板。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="浏览私人商店">▤<span>浏览</span></button><button class="action-item demo-btn" data-toast="购买摊位物品">+<span>购买</span></button><button class="action-item demo-btn" data-toast="打开摆摊管理">⚒<span>管理</span></button><button class="action-item demo-btn" data-toast="关闭私人商店">×<span>关闭</span></button></div>',
|
||
exchange: '<p class="sheet-note">兑换界面展示兑换材料、产出和数量;滑动数量后点击兑换并确认。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="选择兑换材料">▥<span>材料</span></button><button class="action-item demo-btn" data-toast="调整兑换数量">↔<span>数量</span></button><button class="action-item demo-btn" data-toast="查看兑换产出">✦<span>产出</span></button><button class="action-item demo-btn" data-toast="确认兑换">✓<span>兑换</span></button></div>',
|
||
cube: '<p class="sheet-note">Cube 制作将材料槽放在中央,底部只保留一个主要制作按钮,制作完成后弹出结果。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="选择制作配方">▤<span>配方</span></button><button class="action-item demo-btn" data-toast="放入制作材料">+<span>材料</span></button><button class="action-item demo-btn" data-toast="查看制作结果">? <span>预览</span></button><button class="action-item demo-btn" data-toast="确认制作">⚒<span>制作</span></button></div>',
|
||
refine: '<p class="sheet-note">精炼和龙魂使用同一套强化确认流程:选择装备、查看成功率和消耗,再确认结果。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="选择强化装备">⚔<span>装备</span></button><button class="action-item demo-btn" data-toast="查看强化材料">▥<span>材料</span></button><button class="action-item demo-btn" data-toast="查看成功率">%<span>成功率</span></button><button class="action-item demo-btn" data-toast="确认强化">✧<span>强化</span></button></div>',
|
||
dragon: '<p class="sheet-note">龙魂属于制作与强化分支,保留独立页面入口但不放在首页常驻 HUD。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="查看龙魂槽位">✧<span>槽位</span></button><button class="action-item demo-btn" data-toast="选择龙魂">◇<span>选择</span></button><button class="action-item demo-btn" data-toast="查看龙魂属性">? <span>属性</span></button><button class="action-item demo-btn" data-toast="确认镶嵌">✓<span>镶嵌</span></button></div>',
|
||
fishing: '<p class="sheet-note">钓鱼是场景情境交互:靠近钓点后出现交互按钮,完成小游戏后返回场景。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="开始钓鱼">♨<span>开始</span></button><button class="action-item demo-btn" data-toast="收杆">↗<span>收杆</span></button><button class="action-item demo-btn" data-toast="查看鱼获">▥<span>鱼获</span></button><button class="action-item demo-btn" data-toast="退出钓鱼">×<span>退出</span></button></div>',
|
||
dungeon: '<p class="sheet-note">副本入口通过任务导航或场景交互按钮进入;副本内显示目标罗盘,完成后进入结算。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="查看副本目标">⌖<span>目标</span></button><button class="action-item demo-btn" data-toast="查看队伍状态">♟<span>队伍</span></button><button class="action-item demo-btn" data-toast="退出副本">×<span>退出</span></button><button class="action-item demo-btn" data-toast="开始副本">▣<span>进入</span></button></div>',
|
||
mount: '<p class="sheet-note">坐骑从技能页面配置,也可在场景中通过情境按钮召唤和收起。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="召唤坐骑">♞<span>召唤</span></button><button class="action-item demo-btn" data-toast="打开坐骑技能">✧<span>技能</span></button><button class="action-item demo-btn" data-toast="更换坐骑">⇄<span>更换</span></button><button class="action-item demo-btn" data-toast="收起坐骑">×<span>收起</span></button></div>',
|
||
observer: '<p class="sheet-note">观战从社交菜单或队员资料进入,观战时隐藏自身战斗操作,保留退出观战按钮。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="选择观战对象">◉<span>对象</span></button><button class="action-item demo-btn" data-toast="切换观战视角">↔<span>视角</span></button><button class="action-item demo-btn" data-toast="查看战斗信息">? <span>信息</span></button><button class="action-item demo-btn" data-toast="退出观战">×<span>退出</span></button></div>',
|
||
emote: '<p class="sheet-note">表情动作从技能菜单配置,战斗中不占常驻按钮;选择后在角色头顶显示反馈。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="播放表情:挥手">☺<span>挥手</span></button><button class="action-item demo-btn" data-toast="播放表情:欢呼">✦<span>欢呼</span></button><button class="action-item demo-btn" data-toast="播放动作:坐下">♟<span>动作</span></button><button class="action-item demo-btn" data-toast="设置快捷表情">+<span>配置</span></button></div>',
|
||
system: '<p class="sheet-note">系统菜单从右上角进入,采用右侧抽屉;设置和帮助进入全屏面板,离开游戏使用确认弹窗。</p><div class="action-grid"><button class="action-item demo-btn" data-panel="options"><b>⚙</b><span>设置</span></button><button class="action-item demo-btn" data-panel="help"><b>?</b><span>帮助</span></button><button class="action-item demo-btn" data-toast="打开角色选择">♜<span>角色</span></button><button class="action-item demo-btn" data-toast="打开退出确认">×<span>退出</span></button></div>',
|
||
options: '<p class="sheet-note">设置分为音频、画面、操作和社交屏蔽;滑动条与开关都在全屏面板中完成。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="调整音乐音量">♫<span>音乐</span></button><button class="action-item demo-btn" data-toast="调整音效音量">♪<span>音效</span></button><button class="action-item demo-btn" data-toast="调整镜头距离">◎<span>镜头</span></button><button class="action-item demo-btn" data-toast="保存设置">✓<span>保存</span></button></div>',
|
||
help: '<p class="sheet-note">帮助按移动、战斗、任务、社交和系统分类,使用短卡片说明,支持上下滚动。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="查看移动说明">↕<span>移动</span></button><button class="action-item demo-btn" data-toast="查看战斗说明">⚔<span>战斗</span></button><button class="action-item demo-btn" data-toast="查看系统说明">⚙<span>系统</span></button><button class="action-item demo-btn" data-toast="查看快捷操作">✦<span>快捷操作</span></button></div>',
|
||
reconnect: '<p class="sheet-note">断线时覆盖场景显示连接状态;恢复成功后自动回到原位置,失败时提供重试或返回角色列表。</p><div class="action-grid"><button class="action-item demo-btn" data-toast="重新连接中">↻<span>重试</span></button><button class="action-item demo-btn" data-toast="查看网络状态">⌁<span>网络</span></button><button class="action-item demo-btn" data-toast="返回角色列表">♜<span>角色列表</span></button><button class="action-item demo-btn" data-toast="关闭提示">×<span>关闭</span></button></div>'
|
||
});
|
||
const titles = { inventory: '背包', character: '角色', social: '社交', growth: '成长', adventure: '活动', market: '商业', skills: '技能', quest: '任务', map: '地图', party: '社交 / 队伍', friend: '好友', love: '情侣 / 爱意', guild: '公会', target: '目标', chat: '聊天', shop: '商店', mall: '商城', safebox: '仓库', trade: '玩家交易', private_shop: '私人商店', exchange: '兑换', cube: 'Cube 制作', refine: '精炼 / 强化', dragon: '龙魂', fishing: '钓鱼', dungeon: '副本', mount: '坐骑', observer: '观战', emote: '表情动作', system: '系统', help: '帮助', options: '设置', more: '功能菜单' };
|
||
|
||
const flowDetails = {
|
||
login: { kind: '全屏入口', title: '登录界面', entry: '启动游戏后全屏显示;账号密码输入区保持在横屏安全区中央。', touch: '点击输入框唤起键盘,点击登录提交;错误信息在表单下方即时提示。', back: '登录成功进入服务器选择;失败留在当前页并保留已输入账号。', note: '不与战斗 HUD 共存。' },
|
||
server: { kind: '全屏入口', title: '服务器 / 频道选择', entry: '登录成功后进入;服务器列表居中,推荐频道置顶。', touch: '点击频道选中,再点击进入;网络状态和人数使用标签显示。', back: '返回登录界面,或进入角色列表。', note: '连接失败直接复用断线重连提示。' },
|
||
character_select: { kind: '全屏入口', title: '角色列表与角色管理', entry: '服务器选择后进入;角色卡横向排列。', touch: '点击角色选中,点击创建、删除、改名;删除和改名必须二次确认。', back: '返回服务器选择或进入加载界面。', note: '阵营、职业和等级放在角色卡内,不进入战斗 HUD。' },
|
||
loading: { kind: '状态弹窗', title: '加载界面', entry: '角色进入场景、切换地图或副本时覆盖全屏。', touch: '无需操作;加载失败显示重试按钮。', back: '加载完成进入首页 HUD,异常时转断线重连。', note: '避免用户在资源未完成时点击世界。' },
|
||
hud: { kind: '常驻 HUD', title: '首页 HUD', entry: '进入场景后的默认页面;世界画面优先。', touch: '左上头像看角色,右上背包/小地图/菜单,任务栏直接进入任务,底部两侧完成移动和战斗。', back: '所有功能面板关闭后回到这里。', note: '名称在头像顶部,HP/MP 条在头像下方且与头像同宽。' },
|
||
movement: { kind: '常驻 HUD', title: '移动摇杆', entry: '首页左下角,仅作为战斗操作控件。', touch: '按住并拖动控制方向,松手复位;支持边缘拖动防止拇指滑出。', back: '没有独立页面,松手即返回待机状态。', note: '底部中央保持空白,不放功能菜单。' },
|
||
target: { kind: '常驻 HUD', title: '目标选择与目标板', entry: '点击敌人、NPC 或目标板触发;目标板位于顶部中央。', touch: '点击切换目标,长按查看信息;普通攻击和技能自动作用于当前目标。', back: '点击空白清除目标,或选择新目标。', note: '目标血条不与玩家血条混淆。' },
|
||
combat_action: { kind: '常驻 HUD', title: '普通攻击与技能', entry: '首页右下角环形战斗盘。', touch: '点击普攻;点击技能释放;长按可预览需要瞄准的技能;冷却用灰度和数字反馈。', back: '释放完成回到战斗状态,技能配置从菜单进入。', note: '药水可作为战斗盘上的物品按钮,不另设底部功能栏。' },
|
||
loot: { kind: '场景弹窗', title: '掉落物与情境交互', entry: '靠近掉落物、NPC、钓点或副本入口时,在角色附近出现交互按钮。', touch: '点击拾取、对话、钓鱼或进入;掉落物名称显示在世界中并支持点击。', back: '动作完成回到场景;物品自动进入背包并给出短暂提示。', note: '不在首页固定显示拾取菜单。' },
|
||
death: { kind: '场景弹窗', title: '死亡与复活', entry: 'HP 归零后覆盖场景中央。', touch: '点击原地复活、回城或等待;危险选项二次确认。', back: '复活后回到首页 HUD,回城后进入加载流程。', note: '死亡时暂时禁用摇杆和技能按钮。' },
|
||
quest: { kind: '常驻 HUD', title: '任务追踪栏', entry: '首页上方常驻显示,不放入右上菜单。', touch: '点击任务行进入日志;点击目标或导航标记进入地图/自动寻路。', back: '关闭任务日志后回到首页,任务进度仍保留。', note: '任务栏是任务系统的唯一首页快捷入口。' },
|
||
quest_log: { kind: '全屏面板', title: '任务日志', entry: '点击任务追踪栏打开;采用列表 + 详情布局。', touch: '点击任务切换详情,滚动查看奖励;点击追踪更新首页任务栏。', back: '关闭后返回首页 HUD,不改变当前追踪任务。', note: '任务地图标记从详情页进入。' },
|
||
map: { kind: '全屏面板', title: '小地图与大地图', entry: '点击右上小地图进入;没有独立地图按钮。', touch: '双指缩放、拖动地图、点击信标导航,点击定位回到玩家位置。', back: '点击关闭或系统返回回到首页 HUD。', note: '背包已替代原地图快捷按钮。' },
|
||
navigation: { kind: '常驻 + 场景', title: '自动寻路', entry: '从任务详情、地图信标或 NPC 目标触发。', touch: '点击导航开始;到达后显示交互按钮;移动摇杆可随时接管。', back: '手动移动、点击停止或到达目的地后结束。', note: '不额外占用常驻 HUD 按钮。' },
|
||
npc_quest: { kind: '场景弹窗', title: 'NPC 对话与任务', entry: '靠近 NPC 后点击角色或情境交互按钮。', touch: '点击对话选项;接取/完成任务使用明确的主按钮。', back: '关闭对话回到场景;完成后刷新任务栏和奖励提示。', note: '商店、仓库和任务可以在同一 NPC 对话入口分流。' },
|
||
dungeon_result: { kind: '场景弹窗', title: '副本结算', entry: '副本完成或失败后自动弹出。', touch: '滚动查看奖励,点击再次挑战或退出;奖励领取使用主按钮。', back: '退出回到场景,或再次挑战进入加载界面。', note: '副本内保留目标罗盘和队伍状态。' },
|
||
character_entry: { kind: '头像入口', title: '角色功能入口', entry: '只点击左上角玩家头像进入。', touch: '点击头像进入角色页,在其中切换属性、装备、技能、坐骑和外观。', back: '关闭角色面板回到首页 HUD。', note: '角色不出现在右上菜单。' },
|
||
character_status: { kind: '全屏面板', title: '角色属性', entry: '左上头像 → 角色属性。', touch: '左右切换属性分类,滚动查看等级、属性、经验和资源。', back: '返回角色入口,再返回首页。', note: '战斗中只展示精简状态条。' },
|
||
equipment: { kind: '全屏面板', title: '装备界面', entry: '左上头像 → 角色 → 装备。', touch: '点击装备槽查看,长按物品详情,拖动穿戴或替换。', back: '关闭装备页返回角色或首页。', note: '物品对比使用上下对照卡片。' },
|
||
skills: { kind: '全屏面板', title: '技能与快捷栏配置', entry: '左上头像 → 角色 → 技能。', touch: '点击技能查看说明,长按查看数值,拖动到首页技能槽。', back: '保存配置后回到首页,技能按钮即时更新。', note: '主动、被动、坐骑、表情分标签显示。' },
|
||
skill_upgrade: { kind: '场景弹窗', title: '技能升级 / 加点', entry: '技能详情页点击升级。', touch: '点击加点预览消耗,再点击确认;资源不足显示原因。', back: '确认后刷新技能等级,取消回到技能详情。', note: '升级不可误触,必须二次确认。' },
|
||
inspect: { kind: '场景弹窗', title: '查看其他玩家装备', entry: '点击场景玩家后选择查看,或从队伍/好友资料进入。', touch: '点击玩家资料页签查看装备、等级和公会;不可修改对方数据。', back: '关闭资料卡回到场景或社交列表。', note: '交易、私聊、组队使用同一上下文操作栏。' },
|
||
inventory: { kind: '全屏面板', title: '背包', entry: '右上背包快捷按钮或菜单 → 背包。', touch: '点击选中,长按详情,拖动整理/装备/放入快捷栏;使用和出售用明确按钮。', back: '关闭返回首页,物品操作结果用 toast 提示。', note: '腰带、装备栏、任务物品作为背包内页。' },
|
||
item_tooltip: { kind: '场景弹窗', title: '物品详情提示', entry: '背包、仓库、商店或掉落物点击/长按。', touch: '点击物品查看详情;长按保持详情卡,点击操作按钮执行动作。', back: '点空白或返回关闭详情卡。', note: '详情卡不遮挡关键操作区域。' },
|
||
item_action: { kind: '场景弹窗', title: '使用、装备、出售', entry: '物品详情卡底部操作区。', touch: '点击主操作,数量类动作弹出数量选择;出售和稀有物品使用二次确认。', back: '完成后刷新背包,取消回到详情卡。', note: '拖放和点击操作同时支持。' },
|
||
safebox: { kind: '全屏面板', title: '仓库与扩展物品栏', entry: '菜单 → 背包 → 仓库,或靠近仓库 NPC 后进入。', touch: '左右切换背包/仓库/商城仓库;拖动物品存入或取出。', back: '关闭面板返回 NPC 对话或首页。', note: '私人商店背包沿用同一物品组件。' },
|
||
select_item: { kind: '场景弹窗', title: '任务物品选择', entry: '任务奖励、提交材料或任务详情中的选择按钮。', touch: '点击物品,滑动或加减调整数量,提交前显示所需数量。', back: '确认后回到任务流程,取消不消耗物品。', note: '数量选择不使用难操作的小型输入框。' },
|
||
social_entry: { kind: '右上角菜单', title: '社交功能入口', entry: '右上菜单 → 社交;队伍不出现在社交菜单。', touch: '点击聊天、好友、情侣、公会或观战进入对应页面。', back: '关闭社交页面回到首页 HUD。', note: '组队信息固定显示在左上玩家头像下方。' },
|
||
chat: { kind: '全屏面板', title: '聊天与战斗日志', entry: '菜单 → 社交 → 聊天;新消息以短暂提示或气泡显示。', touch: '点击频道切换,点击输入框唤起键盘,长按消息进行复制/私聊。', back: '关闭回到首页,未读数显示在菜单角标。', note: '综合、私聊、系统、战斗、队伍、公会统一在频道中。' },
|
||
party: { kind: '左侧 HUD', title: '队伍信息', entry: '组队后显示在左上玩家头像下方;未组队时自动隐藏。', touch: '点击队员查看资料或定位,长按打开队伍设置;邀请通过好友或玩家交互触发。', back: '关闭队员卡回到首页,队伍血量和距离继续常驻显示。', note: '队伍不出现在社交菜单,也不设置独立首页按钮。' },
|
||
friend: { kind: '全屏面板', title: '好友与好友申请', entry: '菜单 → 社交 → 好友,或点击玩家资料。', touch: '点击申请、同意、私聊、查看资料;列表上下滚动。', back: '返回社交菜单或首页。', note: '好友申请通过临时弹窗提醒。' },
|
||
love: { kind: '全屏面板', title: '情侣 / 爱意', entry: '菜单 → 社交 → 情侣 / 爱意。', touch: '点击关系资料和互动动作;关键关系操作使用确认。', back: '关闭返回社交或首页。', note: '低频关系信息不占用首页 HUD。' },
|
||
guild: { kind: '全屏面板', title: '公会', entry: '菜单 → 社交 → 公会。', touch: '顶部标签切换成员、技能、公告、公会战和会徽;列表支持滚动。', back: '返回社交菜单或首页。', note: '公会邀请通过临时确认弹窗进入。' },
|
||
commerce_entry: { kind: '场景弹窗', title: 'NPC / 玩家情境入口', entry: '靠近 NPC、玩家、摊位或制作设施后显示交互按钮。', touch: '点击交互按钮,从上下文菜单选择对话、商店、交易、仓库或制作。', back: '关闭上下文菜单返回场景。', note: '只在附近有可交互对象时出现。' },
|
||
shop: { kind: '全屏面板', title: 'NPC 商店与商城', entry: 'NPC 交互 → 商店,或菜单 → 商店 / 商城。', touch: '点击商品查看详情,数量选择后购买/出售;支付前二次确认。', back: '返回 NPC 对话或首页。', note: '商城使用同一套物品详情和确认组件。' },
|
||
trade: { kind: '全屏面板', title: '玩家交易', entry: '点击玩家 → 交易,或场景交互菜单进入。', touch: '拖动物品到交易栏,双方锁定后分别确认;内容变化时重新确认。', back: '取消交易返回场景,已锁定物品自动退回。', note: '交易金额和物品变化必须明显反馈。' },
|
||
private_shop: { kind: '全屏面板', title: '私人商店', entry: '点击玩家摊位进入浏览;自己的摊位从菜单管理。', touch: '点击商品购买,管理页拖动物品上架;上架/下架有确认提示。', back: '关闭返回场景,摊位状态保留。', note: '使用背包的物品组件,减少学习成本。' },
|
||
cube: { kind: '全屏面板', title: 'Cube 制作', entry: '菜单 → 交易与制作 → Cube,或靠近制作设施。', touch: '选择配方,拖入材料,查看产出预览,点击制作。', back: '结果弹窗关闭后回到制作页或首页。', note: '制作按钮放在面板底部,不占用首页底部。' },
|
||
refine: { kind: '全屏 + 弹窗', title: '精炼 / 强化 / 龙魂', entry: '菜单 → 交易与制作 → 精炼,龙魂作为同组页签。', touch: '选择装备、查看材料和成功率,确认强化;结果用中央弹窗反馈。', back: '返回制作菜单或首页,失败也明确显示消耗。', note: '龙魂当前代码入口需单独开启后再接入正式菜单。' },
|
||
system_entry: { kind: '右上角菜单', title: '系统入口', entry: '右上角菜单最外侧按钮。', touch: '点击菜单打开右侧抽屉,点击遮罩或关闭按钮收起。', back: '回到首页 HUD,世界输入恢复。', note: '菜单打开时暂停战斗点击,防止误操作。' },
|
||
options: { kind: '全屏面板', title: '系统设置与游戏设置', entry: '菜单 → 系统 → 设置。', touch: '滑动音量、镜头距离等,点击开关控制 PK、名称、伤害数字和屏蔽项。', back: '即时保存后返回菜单或首页。', note: '设置项按音频、画面、操作、社交分组。' },
|
||
help: { kind: '全屏面板', title: '帮助界面', entry: '菜单 → 系统 → 帮助。', touch: '点击分类卡片,上下滚动查看说明;可从快捷入口直接跳转。', back: '返回系统菜单或首页。', note: '帮助文案与实际移动端手势保持一致。' },
|
||
character_switch: { kind: '全屏 + 弹窗', title: '选择角色', entry: '菜单 → 系统 → 选择角色。', touch: '点击后先保存并弹出确认,再回到角色列表。', back: '取消确认继续当前角色。', note: '切换角色触发加载流程。' },
|
||
logout: { kind: '场景弹窗', title: '登出 / 退出游戏', entry: '菜单 → 系统 → 登出或退出。', touch: '点击后弹出确认,显示未保存状态;确认后返回登录或关闭游戏。', back: '取消后回到系统菜单。', note: '属于高风险操作,必须二次确认。' },
|
||
reconnect: { kind: '状态弹窗', title: '断线重连', entry: '网络中断时覆盖当前页面,不清除当前 HUD 状态。', touch: '自动重试;用户可点击重试、查看网络或返回角色列表。', back: '连接成功恢复原场景,失败则进入角色列表。', note: '恢复后保留任务追踪、目标和队伍状态。' }
|
||
};
|
||
|
||
function showToast(message) {
|
||
toast.textContent = message;
|
||
toast.classList.add('show');
|
||
clearTimeout(toastTimer);
|
||
toastTimer = setTimeout(() => toast.classList.remove('show'), 1400);
|
||
}
|
||
function currentVariantRoot(el) { return el.closest('.variant'); }
|
||
function renderPanel(root, key, history = []) {
|
||
const modal = root.querySelector('[data-modal]');
|
||
const title = root.querySelector('[data-sheet-title]');
|
||
const bodyNode = root.querySelector('[data-sheet-body]');
|
||
const back = root.querySelector('[data-back]');
|
||
title.textContent = titles[key] || key;
|
||
bodyNode.innerHTML = featureCopy[key] || `<p class="sheet-note">${titles[key] || key} 面板草图。</p>`;
|
||
modal.dataset.current = key;
|
||
modal.dataset.history = JSON.stringify(history);
|
||
back.classList.toggle('hidden', history.length === 0);
|
||
bindDynamic(bodyNode);
|
||
}
|
||
function openPanel(trigger, key) {
|
||
const root = currentVariantRoot(trigger);
|
||
const modal = root.querySelector('[data-modal]');
|
||
const history = modal.classList.contains('open') && modal.dataset.current ? JSON.parse(modal.dataset.history || '[]') : [];
|
||
if (modal.classList.contains('open') && modal.dataset.current && modal.dataset.current !== key) history.push(modal.dataset.current);
|
||
renderPanel(root, key, history);
|
||
modal.classList.add('open');
|
||
}
|
||
function closePanel(trigger) {
|
||
const modal = trigger.closest('[data-modal]');
|
||
modal.classList.remove('open');
|
||
modal.dataset.current = '';
|
||
modal.dataset.history = '[]';
|
||
}
|
||
function backPanel(trigger) {
|
||
const modal = trigger.closest('[data-modal]');
|
||
const history = JSON.parse(modal.dataset.history || '[]');
|
||
const key = history.pop();
|
||
if (!key) return;
|
||
renderPanel(trigger.closest('.variant'), key, history);
|
||
}
|
||
function bindDynamic(scope = document) {
|
||
scope.querySelectorAll('[data-toast]').forEach(btn => {
|
||
if (btn.dataset.bound) return;
|
||
btn.dataset.bound = '1';
|
||
btn.addEventListener('click', () => showToast(btn.dataset.toast));
|
||
});
|
||
const send = scope.querySelector('[data-send]');
|
||
if (send && !send.dataset.bound) {
|
||
send.dataset.bound = '1';
|
||
send.addEventListener('click', () => {
|
||
const input = scope.querySelector('input');
|
||
if (!input.value.trim()) { showToast('请输入聊天内容'); return; }
|
||
showToast('消息已发送'); input.value = '';
|
||
});
|
||
}
|
||
}
|
||
const flowDetail = document.getElementById('flow-detail');
|
||
function renderFlowDetail(key) {
|
||
const detail = flowDetails[key];
|
||
if (!detail) return;
|
||
flowDetail.classList.remove('empty');
|
||
flowDetail.innerHTML = `<div class="detail-kicker">${detail.kind}</div><h3>${detail.title}</h3><div class="detail-grid"><div class="detail-block"><strong>入口 / 所在位置</strong><p>${detail.entry}</p></div><div class="detail-block"><strong>移动端触控</strong><p>${detail.touch}</p></div><div class="detail-block"><strong>返回路径</strong><p>${detail.back}</p></div></div><p class="flow-note">设计备注:${detail.note}</p>`;
|
||
flowDetail.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||
}
|
||
document.querySelectorAll('[data-detail]').forEach(node => node.addEventListener('click', () => renderFlowDetail(node.dataset.detail)));
|
||
document.querySelectorAll('[data-flow-filter]').forEach(filter => filter.addEventListener('click', () => {
|
||
const value = filter.dataset.flowFilter;
|
||
document.querySelectorAll('[data-flow-filter]').forEach(item => {
|
||
const active = item === filter;
|
||
item.classList.toggle('active', active);
|
||
item.setAttribute('aria-selected', active ? 'true' : 'false');
|
||
});
|
||
document.querySelectorAll('.flow-card').forEach(card => card.classList.toggle('is-hidden', value !== 'all' && card.dataset.flowGroup !== value));
|
||
showToast(value === 'all' ? '显示全部交互流程' : '已筛选交互流程');
|
||
}));
|
||
document.addEventListener('click', event => {
|
||
const btn = event.target.closest('.demo-btn');
|
||
if (btn) {
|
||
if (btn.dataset.panel) openPanel(btn, btn.dataset.panel);
|
||
if (btn.dataset.skill) {
|
||
showToast(btn.dataset.toast || ('触发:' + btn.dataset.skill));
|
||
if (btn.dataset.skill !== '普攻') {
|
||
btn.classList.add('cooling');
|
||
const badge = btn.querySelector('em');
|
||
if (badge) badge.textContent = '3';
|
||
setTimeout(() => { btn.classList.remove('cooling'); if (badge) badge.textContent = ''; }, 900);
|
||
}
|
||
}
|
||
}
|
||
const close = event.target.closest('[data-close]');
|
||
if (close) closePanel(close);
|
||
const back = event.target.closest('[data-back]');
|
||
if (back) backPanel(back);
|
||
if (event.target.matches('[data-modal]')) closePanel(event.target.querySelector('[data-close]'));
|
||
});
|
||
document.querySelectorAll('[data-viewport]').forEach(btn => btn.addEventListener('click', () => {
|
||
canvas.className = 'preview-' + btn.dataset.viewport;
|
||
showToast('预览尺寸:' + btn.textContent);
|
||
}));
|
||
document.getElementById('annotation-toggle').addEventListener('click', event => {
|
||
body.classList.toggle('annotate');
|
||
event.currentTarget.textContent = body.classList.contains('annotate') ? '关闭标注' : '标注';
|
||
showToast(body.classList.contains('annotate') ? '标注模式已开启' : '标注模式已关闭');
|
||
});
|
||
const annotation = document.getElementById('annotation-label');
|
||
document.addEventListener('mousemove', event => {
|
||
if (!body.classList.contains('annotate')) return;
|
||
const el = event.target.closest('[data-label]');
|
||
if (!el) { annotation.style.display = 'none'; return; }
|
||
annotation.textContent = el.dataset.label;
|
||
annotation.style.left = Math.min(window.innerWidth - 180, event.clientX + 12) + 'px';
|
||
annotation.style.top = Math.min(window.innerHeight - 40, event.clientY + 12) + 'px';
|
||
annotation.style.display = 'block';
|
||
});
|
||
document.querySelectorAll('[data-joystick]').forEach(joystick => {
|
||
let active = false;
|
||
const stick = joystick.querySelector('.stick');
|
||
const move = event => {
|
||
if (!active) return;
|
||
const rect = joystick.getBoundingClientRect();
|
||
const x = (event.clientX ?? event.touches?.[0]?.clientX) - (rect.left + rect.width / 2);
|
||
const y = (event.clientY ?? event.touches?.[0]?.clientY) - (rect.top + rect.height / 2);
|
||
const limit = 26, length = Math.max(1, Math.hypot(x, y)), scale = Math.min(1, limit / length);
|
||
stick.style.transform = `translate(calc(-50% + ${x * scale}px), calc(-50% + ${y * scale}px))`;
|
||
};
|
||
const release = () => { active = false; joystick.classList.remove('is-active'); stick.style.transform = 'translate(-50%, -50%)'; showToast('移动摇杆已复位'); };
|
||
joystick.addEventListener('pointerdown', event => { active = true; joystick.classList.add('is-active'); joystick.setPointerCapture(event.pointerId); move(event); });
|
||
joystick.addEventListener('pointermove', move); joystick.addEventListener('pointerup', release); joystick.addEventListener('pointercancel', release);
|
||
});
|
||
bindDynamic();
|
||
</script>
|
||
</body>
|
||
</html>
|