说明文档更新

This commit is contained in:
2026-09-07 21:23:47 +08:00
parent 4f7667a3b4
commit c1bff483e6
12 changed files with 390 additions and 199 deletions
+299
View File
@@ -0,0 +1,299 @@
<template>
<div v-if="show" class="help-overlay" role="presentation" @click.self="close">
<section class="help-dialog" role="dialog" aria-modal="true" aria-labelledby="help-title">
<header class="help-head">
<div>
<h2 id="help-title">使用说明</h2>
<p>从创建粒子到保存导出的快速入门</p>
</div>
<button class="help-close" aria-label="关闭使用说明" title="关闭 (Esc)" @click="close"></button>
</header>
<div class="help-body">
<section class="help-section help-start">
<h3>快速开始</h3>
<ol>
<li><b>创建对象</b>在左侧场景对象中用 粒子 / 碰撞 / 路径 / Spine 添加场景对象</li>
<li><b>编辑粒子</b>选中某个粒子系统依次调整发射模式 发射器形状 粒子属性 外观与资源 修改器</li>
<li><b>查看效果</b>底部时间轴可播放暂停逐帧或拖动修改任意参数后会自动重新计算</li>
<li><b>保存与导出</b>保存配置保留工程导出 Spine Json / images / .spine 输出成品</li>
</ol>
<p class="help-note">每个模块组标题右侧的重置可把该组参数恢复默认系统设置会自动保存在当前浏览器</p>
</section>
<div class="help-grid">
<section class="help-section">
<h3>常用操作</h3>
<dl class="help-list">
<div><dt>小眼睛</dt><dd>单独显示/隐藏对象隐藏的粒子系统不会被导出</dd></div>
<div><dt>+Copy</dt><dd>完整复制当前选中对象方便对比不同参数</dd></div>
<div><dt>背景图</dt><dd>上传参考图并调整位置和透明度只用于画布预览</dd></div>
<div><dt>系统设置</dt><dd>管理界面布局辅助显示刻度等自动存入浏览器</dd></div>
<div><dt>撤销/重做</dt><dd>Ctrl+Z 撤回一步可达成的步数在系统设置中调整</dd></div>
<div><dt>Spine 骨骼</dt><dd>在层级树搜索并选择骨骼可用于粒子发射器跟随</dd></div>
</dl>
</section>
<section class="help-section">
<h3>快捷键</h3>
<div class="shortcut-list">
<div><kbd>Ctrl/</kbd><span>+</span><kbd>Z</kbd><em>撤回上一步</em></div>
<div><kbd>Ctrl/</kbd><span>+</span><kbd>S</kbd><em>保存配置</em></div>
<div><kbd>Q</kbd><em>拖动画布</em></div>
<div><kbd>W</kbd><em>位移工具</em></div>
<div><kbd>E</kbd><em>旋转工具</em></div>
<div><kbd>R</kbd><em>缩放工具</em></div>
<div><kbd>D</kbd><em>播放 / 暂停</em></div>
<div><kbd>S</kbd><em>回到第一帧</em></div>
</div>
<p class="help-note">Q / W / E / R 需先点击画布光标位于输入框时单键快捷键不会触发</p>
</section>
</div>
<div class="help-doc-title">功能模块详解</div>
<section class="help-section help-module" :class="{ open: openModules[0] }">
<button type="button" class="help-module-head" :aria-expanded="openModules[0] ? 'true' : 'false'" @click="openModules[0] = !openModules[0]">
<span class="mnum">1</span><span class="mtitle">配置管理</span><span class="caret">{{ openModules[0] ? '▾' : '▸' }}</span>
</button>
<div v-show="openModules[0]" class="help-module-body">
<dl class="help-list">
<div><dt>保存配置</dt><dd>把当前全部场景对象和参数保存为工程 JSON 文件也支持 Ctrl+S</dd></div>
<div><dt>加载配置</dt><dd>选择本地配置文件恢复完整工程</dd></div>
<div><dt>预设</dt><dd>从下拉中选择已保存的预设快速套用点击下拉即可刷新列表</dd></div>
<div><dt>范围</dt><dd>配置只含对象与参数不含系统设置系统设置单独存于浏览器</dd></div>
</dl>
</div>
</section>
<section class="help-section help-module" :class="{ open: openModules[1] }">
<button type="button" class="help-module-head" :aria-expanded="openModules[1] ? 'true' : 'false'" @click="openModules[1] = !openModules[1]">
<span class="mnum">2</span><span class="mtitle">场景对象</span><span class="caret">{{ openModules[1] ? '▾' : '▸' }}</span>
</button>
<div v-show="openModules[1]" class="help-module-body">
<dl class="help-list">
<div><dt>粒子</dt><dd>核心对象可设名称位置 X/Y偏移旋转缩放 X/Y以及随机种子相同种子可精确复现同一次效果</dd></div>
<div><dt>碰撞</dt><dd>圆形/椭圆/矩形/多边形/自定义启用开关碰撞响应物理弹跳/暂停/销毁弹性与摩擦还可沿某条路径移动并带进度曲线</dd></div>
<div><dt>路径</dt><dd>贝塞尔路径可双击新建/删除锚点拖手柄调曲线内置圆//多边形/星形预设支持闭合与颜色</dd></div>
<div><dt>Spine</dt><dd>加载 .json+.atlas+.png 预览骨骼动画可查看/搜索骨骼层级树用于粒子发射器跟随</dd></div>
<div><dt>通用</dt><dd>每个对象都有小眼睛显隐+Copy可以复制当前对象隐藏的粒子系统不会进入导出</dd></div>
</dl>
</div>
</section>
<section class="help-section help-module" :class="{ open: openModules[2] }">
<button type="button" class="help-module-head" :aria-expanded="openModules[2] ? 'true' : 'false'" @click="openModules[2] = !openModules[2]">
<span class="mnum">3</span><span class="mtitle">发射模式</span><span class="caret">{{ openModules[2] ? '▾' : '▸' }}</span>
</button>
<div v-show="openModules[2]" class="help-module-body">
<dl class="help-list">
<div><dt>持续</dt><dd>每秒发射数量持续喷射再分常规持续发射时长循环持续三段式开始循环 / 纯循环 / 结束循环可自动或自定义帧长做到无缝衔接</dd></div>
<div><dt>爆发</dt><dd>一次性发射单次数量颗粒子</dd></div>
<div><dt>延迟时间</dt><dd>粒子条左端位置表示发射开始前的等待时间</dd></div>
<div><dt>注意</dt><dd>循环持续模式不支持骨骼跟随和路径跟随开关时会把跟随设置恢复默认</dd></div>
</dl>
</div>
</section>
<section class="help-section help-module" :class="{ open: openModules[3] }">
<button type="button" class="help-module-head" :aria-expanded="openModules[3] ? 'true' : 'false'" @click="openModules[3] = !openModules[3]">
<span class="mnum">4</span><span class="mtitle">发射器形状</span><span class="caret">{{ openModules[3] ? '▾' : '▸' }}</span>
</button>
<div v-show="openModules[3]" class="help-module-body">
<dl class="help-list">
<div><dt>形状</dt><dd> / 圆形 / 矩形 / 锥形 / 路径</dd></div>
<div><dt>·</dt><dd>内半径与外半径形成环形或锥形发射区锥形额外有锥形朝向开口角度</dd></div>
<div><dt>矩形</dt><dd>外框 内框形成环带可分别设置内外宽高</dd></div>
<div><dt>路径</dt><dd>选一条场景路径作为出生线出生分布可选等距固定或随机</dd></div>
<div><dt>发射角度</dt><dd>固定 / 随机基准角度 + 随机范围/ 径向锥中心向外/ 垂直于路径 / 沿路径方向</dd></div>
</dl>
</div>
</section>
<section class="help-section help-module" :class="{ open: openModules[4] }">
<button type="button" class="help-module-head" :aria-expanded="openModules[4] ? 'true' : 'false'" @click="openModules[4] = !openModules[4]">
<span class="mnum">5</span><span class="mtitle">粒子属性</span><span class="caret">{{ openModules[4] ? '▾' : '▸' }}</span>
</button>
<div v-show="openModules[4]" class="help-module-body">
<dl class="help-list">
<div><dt>初始参数</dt><dd>生命周期速度缩放统一或 X/Y 分离初始旋转可跟随发射方向每个属性支持固定 / 随机 / 曲线三种取值</dd></div>
<div><dt>生命周期变化</dt><dd>速度倍率缩放倍率统一/分离旋转速度均可用生命周期 倍率曲线控制</dd></div>
<div><dt>曲线含义</dt><dd>横轴为粒子生命周期 01纵轴为倍率或对应数值</dd></div>
</dl>
</div>
</section>
<section class="help-section help-module" :class="{ open: openModules[5] }">
<button type="button" class="help-module-head" :aria-expanded="openModules[5] ? 'true' : 'false'" @click="openModules[5] = !openModules[5]">
<span class="mnum">6</span><span class="mtitle">外观与资源</span><span class="caret">{{ openModules[5] ? '▾' : '▸' }}</span>
</button>
<div v-show="openModules[5]" class="help-module-body">
<dl class="help-list">
<div><dt>透明度</dt><dd>曲线或固定曲线模式可选跟随导出 / 线性 / 贝塞尔</dd></div>
<div><dt>图片资源</dt><dd>新增可上传单图或序列帧多张图片按权重随机每张可调缩放轴心颜色固定/随机/生命周期渐变混合模式正常/相加/相乘/滤色独立透明度/固定/曲线</dd></div>
<div><dt>序列帧</dt><dd>播放方式单次隐藏 / 单次定格 / 正向循环 / 反向循环可设每秒帧数</dd></div>
</dl>
</div>
</section>
<section class="help-section help-module" :class="{ open: openModules[6] }">
<button type="button" class="help-module-head" :aria-expanded="openModules[6] ? 'true' : 'false'" @click="openModules[6] = !openModules[6]">
<span class="mnum">7</span><span class="mtitle">修改器</span><span class="caret">{{ openModules[6] ? '▾' : '▸' }}</span>
</button>
<div v-show="openModules[6]" class="help-module-body">
<dl class="help-list">
<div><dt>移动噪声</dt><dd>强度波动范围时间流速让粒子轨迹产生抖动</dd></div>
<div><dt>重力 / 风力</dt><dd>固定或随机强度方向以及生命周期内强度曲线</dd></div>
<div><dt>力场</dt><dd>中心 X/Y强度正吸负斥半径衰减恒定/线性/反比</dd></div>
<div><dt>吸附</dt><dd>延迟后把粒子吸到指定点到达范围即死亡可直线或曲线</dd></div>
<div><dt>拖尾</dt><dd>独立拖尾图片多资源按权重旋转拖尾骨骼数拖尾比例长度/宽度可固定或随机并支持放大可加生命周期长度曲线与形状曲线颜色/透明度可跟随粒子固定或曲线</dd></div>
<div><dt>发射器跟随</dt><dd>跟随某条路径局部/世界/反向进度曲线或跟随 Spine 骨骼选中的骨骼 + 偏移</dd></div>
<div><dt>碰撞 + 阻尼</dt><dd>选择场景中已启用的碰撞对象参与并设置速度阻尼</dd></div>
</dl>
</div>
</section>
<section class="help-section help-module" :class="{ open: openModules[7] }">
<button type="button" class="help-module-head" :aria-expanded="openModules[7] ? 'true' : 'false'" @click="openModules[7] = !openModules[7]">
<span class="mnum">8</span><span class="mtitle">导出设置</span><span class="caret">{{ openModules[7] ? '▾' : '▸' }}</span>
</button>
<div v-show="openModules[7]" class="help-module-body">
<dl class="help-list">
<div><dt>图片路径</dt><dd>写入 Spine images 路径例如 ./images/</dd></div>
<div><dt>Spine 版本</dt><dd>3.8 / 4.0 / 4.1 / 4.2 / 4.3</dd></div>
<div><dt>关键帧曲线</dt><dd>线性或平滑贝塞尔出生死亡突变仍使用阶跃关键帧</dd></div>
<div><dt>导出 FPS</dt><dd>修改 FPS 会保持动画实际秒数不变不写 fps只省略元数据</dd></div>
<div><dt>其它</dt><dd>整数帧对齐骨骼对象池排除无内容动画</dd></div>
<div><dt>导出按钮</dt><dd>导出 Spine Json生成骨骼动画文件导出 images 单独下载图片 ZIP导出 .spine 需要连接器</dd></div>
</dl>
</div>
</section>
<section class="help-section help-module help-connector" :class="{ open: openModules[8] }">
<button type="button" class="help-module-head" :aria-expanded="openModules[8] ? 'true' : 'false'" @click="openModules[8] = !openModules[8]">
<span class="mnum">9</span><span class="mtitle">连接器Spine 连接器使用说明</span><span class="caret">{{ openModules[8] ? '▾' : '▸' }}</span>
</button>
<div v-show="openModules[8]" class="help-module-body">
<p class="connector-intro">连接器用于把网页生成的 JSON 和图片调用你电脑上<b>已安装并激活</b> Spine转换成可编辑的 <b>.spine</b> 工程</p>
<dl class="help-list">
<div><dt>前置</dt><dd>电脑已安装并激活 Spine并已启动桌面版连接器APP</dd></div>
<div><dt>下载</dt><dd>
<a class="dl-link" href="/downloads/connector/SpineParticleConnector-windows-x64.exe" download>Windows <br><small>SpineParticleConnector-windows-x64.exe</small></a>
<a class="dl-link" href="/downloads/connector/SpineParticleConnector-macos-arm64.zip" download>macOS <br><small>SpineParticleConnector-macos-arm64.zip</small></a>
</dd></div>
<div><dt>网页端</dt><dd>导出区状态显示连接器可用 · Spine 已就绪点击导出 .spine </dd></div>
<div><dt>首次授权</dt><dd>生产网站首次连接会显示授权当前网站点击后在本机确认页核对完整来源协议 + 域名 + 端口再点允许此网站授权一次后本机会保存白名单本地 127.0.0.1:5173 默认允许</dd></div>
<div><dt>路径设置</dt><dd>连接器自动检测 Spine 安装位置检测不到时可在桌面窗口手动指定Windows Spine.commacOS Spine.app/Contents/MacOS/Spine</dd></div>
<div><dt>下载结果</dt><dd>得到 ZIP 内含 .spine 工程和图片目录 images/star.png</dd></div>
<div><dt>版本</dt><dd>连接器按请求与 JSON 内的版本自动匹配 3.84.3使用最新可用补丁</dd></div>
<div><dt>安全</dt><dd>仅监听本机 127.0.0.1:27843授权与白名单保存在连接器里文件在临时目录转换后清理并有大小限制</dd></div>
</dl>
</div>
</section>
<section class="help-section help-export">
<h3>配置与导出有什么区别</h3>
<p><b>保存配置</b>会保存编辑器中的全部对象和参数之后可以继续修改<b>导出 Spine Json</b>只导出显示中的粒子系统并把跟随碰撞和拖尾结果烘焙为独立动画数据</p>
</section>
</div>
</section>
</div>
</template>
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue'
defineProps<{ show: boolean }>()
const emit = defineEmits<{ (event: 'close'): void }>()
// 功能模块详解:默认全部收起,点击标题栏展开/收起单个模块。
const openModules = ref<boolean[]>(Array.from({ length: 9 }, () => false))
function close() {
emit('close')
}
function onKeydown(event: KeyboardEvent) {
if (event.key === 'Escape') close()
}
onMounted(() => window.addEventListener('keydown', onKeydown))
onBeforeUnmount(() => window.removeEventListener('keydown', onKeydown))
</script>
<style scoped>
.help-overlay {
position: absolute; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center; padding: 72px 24px 28px;
box-sizing: border-box; background: rgba(5, 8, 15, .72); backdrop-filter: blur(3px);
}
.help-dialog {
width: min(820px, 100%); max-height: 100%; display: flex; flex-direction: column; overflow: hidden;
border: 1px solid #3a4864; border-radius: 14px; background: #141a27; color: #b8c3d8;
box-shadow: 0 22px 70px rgba(0, 0, 0, .62);
}
.help-head {
display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; padding: 18px 20px 15px;
border-bottom: 1px solid #2b354a; background: linear-gradient(135deg, #202942, #181e2d);
}
.help-head h2 { margin: 0; color: #eef2ff; font-size: 19px; }
.help-head p { margin: 5px 0 0; color: #7786a3; font-size: 11px; }
.help-close {
width: 28px; height: 28px; flex: 0 0 28px; border: 1px solid #43516b; border-radius: 6px;
background: #273249; color: #ccd7ed; cursor: pointer;
}
.help-close:hover { border-color: #7774ff; background: #3b4670; color: #fff; }
.help-body { min-height: 0; overflow: auto; padding: 18px 20px 21px; }
.help-section { padding: 14px 15px; border: 1px solid #2c3850; border-radius: 10px; background: #181f2e; }
.help-section h3 { margin: 0 0 11px; color: #9fb2ff; font-size: 13px; }
.help-start ol { margin: 0; padding-left: 21px; color: #aab6cc; font-size: 12px; line-height: 1.75; }
.help-start li::marker { color: #7774ff; font-weight: 700; }
.help-section b { color: #dce4f7; }
.help-grid { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(250px, .85fr); gap: 12px; margin-top: 12px; }
.help-list { display: grid; gap: 0; margin: 0; }
.help-list > div { display: grid; grid-template-columns: 78px 1fr; gap: 9px; padding: 7px 0; border-bottom: 1px solid #263146; }
.help-list > div:last-child { border-bottom: 0; }
.help-list dt { color: #d3dcf0; font-size: 11px; font-weight: 700; }
.help-list dd { margin: 0; color: #8795ae; font-size: 11px; line-height: 1.5; }
.shortcut-list { display: grid; gap: 7px; }
.shortcut-list > div { display: flex; align-items: center; min-height: 25px; gap: 5px; }
.shortcut-list kbd {
min-width: 24px; box-sizing: border-box; padding: 3px 6px; border: 1px solid #465470; border-bottom-width: 2px;
border-radius: 5px; background: #101623; color: #e0e7f6; font: 10px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; text-align: center;
}
.shortcut-list span { color: #65728b; font-size: 10px; }
.shortcut-list em { margin-left: auto; color: #9ca9c1; font-size: 11px; font-style: normal; }
.help-note { margin: 11px 0 0; padding-top: 9px; border-top: 1px solid #2a3549; color: #697791; font-size: 10px; line-height: 1.55; }
.help-export { margin-top: 12px; }
.help-export p { margin: 0; color: #8997b0; font-size: 11px; line-height: 1.65; }
.help-doc-title { margin: 16px 2px 2px; color: #9fb2ff; font-size: 13px; font-weight: 700; letter-spacing: .5px; }
.help-module { margin-top: 12px; }
.help-module-head {
display: flex; align-items: center; gap: 8px; width: 100%; padding: 0; border: 0; background: transparent;
color: #9fb2ff; font: inherit; font-size: 13px; font-weight: 700; text-align: left; cursor: pointer;
}
.help-module-head:hover { color: #fff; }
.help-module-head .mtitle { flex: 1; min-width: 0; }
.help-module-head .caret { flex: 0 0 auto; color: #7b86a2; font-size: 12px; }
.help-module.open .help-module-head { color: #fff; }
.help-module.open .help-module-head .caret { color: #9fb2ff; }
.help-module .mnum {
flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
width: 22px; height: 22px; border-radius: 6px;
background: linear-gradient(135deg, #4a53b8, #6a5fd0); color: #fff; font-size: 12px; font-weight: 700;
}
.help-module.help-connector { border-color: #4a4f8a; background: linear-gradient(135deg, #1d2442, #181d2f); }
.help-module.help-connector .help-module-head { color: #b8c2ff; }
.help-module .connector-intro { margin: 0 0 10px; color: #9aa8c4; font-size: 11px; line-height: 1.6; }
.help-module .connector-intro b { color: #dce4f7; }
.help-module .dl-link {
display: inline-flex; flex-direction: column; align-items: flex-start; gap: 2px; margin: 0 10px 6px 0; padding: 6px 12px;
border: 1px solid #5652b5; border-radius: 6px; background: #4540a0; color: #fff; font-size: 12px; font-weight: 700; text-decoration: none;
}
.help-module .dl-link:hover { border-color: #8982ff; background: #554dc2; }
.help-module .dl-link small { color: #cfe0ff; font-weight: 500; font-size: 9px; }
.help-module-body { padding-top: 10px; }
@media (max-width: 760px) {
.help-overlay { padding: 66px 12px 14px; }
.help-grid { grid-template-columns: 1fr; }
}
</style>
+2 -110
View File
@@ -119,63 +119,7 @@
<div class="sp-cache-note">整个系统设置会自动保存到当前浏览器</div>
</div>
<div v-if="showHelp" class="help-overlay" role="presentation" @click.self="showHelp = false">
<section class="help-dialog" role="dialog" aria-modal="true" aria-labelledby="help-title">
<header class="help-head">
<div>
<h2 id="help-title">使用说明</h2>
<p>从创建粒子到保存导出的快速入门</p>
</div>
<button class="help-close" aria-label="关闭使用说明" title="关闭 (Esc)" @click="showHelp = false"></button>
</header>
<div class="help-body">
<section class="help-section help-start">
<h3>快速开始</h3>
<ol>
<li><b>创建对象</b>在左侧场景对象中添加粒子碰撞路径或 Spine</li>
<li><b>编辑粒子</b>选中粒子系统依次调整发射形状属性外观资源和修改器</li>
<li><b>查看效果</b>使用底部时间轴播放暂停或拖动到指定帧修改参数后会自动重新计算</li>
<li><b>保存成果</b>配置文件用于继续编辑导出 Spine Json支持 Spine 3.84.04.14.2 4.3</li>
</ol>
</section>
<div class="help-grid">
<section class="help-section">
<h3>常用功能</h3>
<dl class="help-list">
<div><dt>小眼睛</dt><dd>单独显示或隐藏场景对象隐藏的粒子系统不会导出</dd></div>
<div><dt>+Copy</dt><dd>完整复制当前选中对象方便对比不同参数效果</dd></div>
<div><dt>背景图</dt><dd>上传参考图并调整位置和透明度只用于画布预览</dd></div>
<div><dt>系统设置</dt><dd>管理界面与辅助显示并自动保存在当前浏览器中</dd></div>
<div><dt>配置管理</dt><dd>保存当前项目数据加载配置或直接使用预设文件不包含系统设置</dd></div>
<div><dt>Spine 骨骼</dt><dd>在层级树搜索并选择骨骼可用于粒子发射器跟随</dd></div>
</dl>
</section>
<section class="help-section">
<h3>快捷键</h3>
<div class="shortcut-list">
<div><kbd>Ctrl/</kbd><span>+</span><kbd>Z</kbd><em>撤回上一步</em></div>
<div><kbd>Ctrl/</kbd><span>+</span><kbd>S</kbd><em>保存配置</em></div>
<div><kbd>Q</kbd><em>拖动画布</em></div>
<div><kbd>W</kbd><em>位移工具</em></div>
<div><kbd>E</kbd><em>旋转工具</em></div>
<div><kbd>R</kbd><em>缩放工具</em></div>
<div><kbd>D</kbd><em>播放 / 暂停</em></div>
<div><kbd>S</kbd><em>回到第一帧</em></div>
</div>
<p class="help-note">Q / W / E / R 需要先点击画布光标位于输入框时单键快捷键不会触发</p>
</section>
</div>
<section class="help-section help-export">
<h3>配置与导出有什么区别</h3>
<p><b>保存配置</b>会保存编辑器中的全部对象和参数之后可以继续修改<b>导出 Spine Json</b>只导出显示中的粒子系统并把跟随碰撞和拖尾结果烘焙为独立动画数据</p>
</section>
</div>
</section>
</div>
<HelpDialog :show="showHelp" @close="showHelp = false" />
<div class="hud" v-if="info">
系统: <b class="hud-number hud-system-count">{{ info.systems }}</b> · 粒子(骨骼): <b class="hud-number hud-particle-count">{{ info.particles }}</b> · 根骨骼: <b>root</b>
@@ -198,6 +142,7 @@ import { editorHistoryState, installEditorHistory, setUndoLimit, undoLastOperati
import { useEditorShortcuts } from '../editor/useEditorShortcuts'
import { fileToDataUrl } from '../spine/spineSourceBundle'
import { downloadEditorConfig } from '../editor/editorConfig'
import HelpDialog from './HelpDialog.vue'
const store = useParticleStore()
const holder = ref<HTMLElement | null>(null)
@@ -329,10 +274,6 @@ function openHelp() {
showBackgroundMenu.value = false
}
function onHelpKeydown(event: KeyboardEvent) {
if (event.key === 'Escape' && showHelp.value) showHelp.value = false
}
function toggleSettings() {
showSettings.value = !showSettings.value
if (showSettings.value) showBackgroundMenu.value = false
@@ -1711,7 +1652,6 @@ function loop() {
}
onMounted(async () => {
window.addEventListener('keydown', onHelpKeydown)
const el = holder.value!
app = new Application({ width: el.clientWidth || 800, height: el.clientHeight || 600, backgroundAlpha: 0, antialias: true })
el.appendChild(app.view as unknown as HTMLCanvasElement)
@@ -1765,7 +1705,6 @@ onMounted(async () => {
})
onUnmounted(() => {
window.removeEventListener('keydown', onHelpKeydown)
cancelAnimationFrame(raf)
spineRuntime?.destroy()
spineRuntime = null
@@ -1843,53 +1782,6 @@ onUnmounted(() => {
}
.help-btn:hover, .help-btn.on { border-color: #7774ff; background: #343b63; color: #fff; }
.zoom-pct { margin-left: 0; font-variant-numeric: tabular-nums; color: #9aa; min-width: 44px; text-align: center; }
.help-overlay {
position: absolute; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center; padding: 72px 24px 28px;
box-sizing: border-box; background: rgba(5, 8, 15, .72); backdrop-filter: blur(3px);
}
.help-dialog {
width: min(820px, 100%); max-height: 100%; display: flex; flex-direction: column; overflow: hidden;
border: 1px solid #3a4864; border-radius: 14px; background: #141a27; color: #b8c3d8;
box-shadow: 0 22px 70px rgba(0, 0, 0, .62);
}
.help-head {
display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; padding: 18px 20px 15px;
border-bottom: 1px solid #2b354a; background: linear-gradient(135deg, #202942, #181e2d);
}
.help-head h2 { margin: 0; color: #eef2ff; font-size: 19px; }
.help-head p { margin: 5px 0 0; color: #7786a3; font-size: 11px; }
.help-close {
width: 28px; height: 28px; flex: 0 0 28px; border: 1px solid #43516b; border-radius: 6px;
background: #273249; color: #ccd7ed; cursor: pointer;
}
.help-close:hover { border-color: #7774ff; background: #3b4670; color: #fff; }
.help-body { min-height: 0; overflow: auto; padding: 18px 20px 21px; }
.help-section { padding: 14px 15px; border: 1px solid #2c3850; border-radius: 10px; background: #181f2e; }
.help-section h3 { margin: 0 0 11px; color: #9fb2ff; font-size: 13px; }
.help-start ol { margin: 0; padding-left: 21px; color: #aab6cc; font-size: 12px; line-height: 1.75; }
.help-start li::marker { color: #7774ff; font-weight: 700; }
.help-section b { color: #dce4f7; }
.help-grid { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(250px, .85fr); gap: 12px; margin-top: 12px; }
.help-list { display: grid; gap: 0; margin: 0; }
.help-list > div { display: grid; grid-template-columns: 78px 1fr; gap: 9px; padding: 7px 0; border-bottom: 1px solid #263146; }
.help-list > div:last-child { border-bottom: 0; }
.help-list dt { color: #d3dcf0; font-size: 11px; font-weight: 700; }
.help-list dd { margin: 0; color: #8795ae; font-size: 11px; line-height: 1.5; }
.shortcut-list { display: grid; gap: 7px; }
.shortcut-list > div { display: flex; align-items: center; min-height: 25px; gap: 5px; }
.shortcut-list kbd {
min-width: 24px; box-sizing: border-box; padding: 3px 6px; border: 1px solid #465470; border-bottom-width: 2px;
border-radius: 5px; background: #101623; color: #e0e7f6; font: 10px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; text-align: center;
}
.shortcut-list span { color: #65728b; font-size: 10px; }
.shortcut-list em { margin-left: auto; color: #9ca9c1; font-size: 11px; font-style: normal; }
.help-note { margin: 11px 0 0; padding-top: 9px; border-top: 1px solid #2a3549; color: #697791; font-size: 10px; line-height: 1.55; }
.help-export { margin-top: 12px; }
.help-export p { margin: 0; color: #8997b0; font-size: 11px; line-height: 1.65; }
@media (max-width: 760px) {
.help-overlay { padding: 66px 12px 14px; }
.help-grid { grid-template-columns: 1fr; }
}
.hud { position: absolute; bottom: 12px; left: 12px; padding: 8px 12px; background: rgba(20,20,32,0.75); border-radius: 8px; font-size: 12px; color: #a0a8cc; }
.hud-number { display: inline-block; box-sizing: border-box; text-align: right; font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }
.hud-system-count { width: 3ch; }