Merge branch 'main' of http://gitlab.yeomai.site/Yeomai/SpineParticlesWeb
This commit is contained in:
Vendored
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
+72
-72
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Vendored
+2
-2
@@ -8,8 +8,8 @@
|
|||||||
html, body { margin: 0; padding: 0; background: #111; color: #eee; font-family: system-ui, -apple-system, sans-serif; }
|
html, body { margin: 0; padding: 0; background: #111; color: #eee; font-family: system-ui, -apple-system, sans-serif; }
|
||||||
#app { display: flex; flex-direction: column; height: 100vh; }
|
#app { display: flex; flex-direction: column; height: 100vh; }
|
||||||
</style>
|
</style>
|
||||||
<script type="module" crossorigin src="/assets/index-CQJ6qUg9.js"></script>
|
<script type="module" crossorigin src="/assets/index-D08n0lXm.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CheycJh3.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-Acs2Q5qJ.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>␍
|
<div id="app"></div>␍
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -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>横轴为粒子生命周期 0→1,纵轴为倍率或对应数值。</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.com,macOS 选 Spine.app/Contents/MacOS/Spine。</dd></div>
|
||||||
|
<div><dt>下载结果</dt><dd>得到 ZIP 包,内含 .spine 工程和图片目录(如 images/star.png)。</dd></div>
|
||||||
|
<div><dt>版本</dt><dd>连接器按请求与 JSON 内的版本自动匹配 3.8~4.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
@@ -119,63 +119,7 @@
|
|||||||
<div class="sp-cache-note">整个系统设置会自动保存到当前浏览器</div>
|
<div class="sp-cache-note">整个系统设置会自动保存到当前浏览器</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="showHelp" class="help-overlay" role="presentation" @click.self="showHelp = false">
|
<HelpDialog :show="showHelp" @close="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.8、4.0、4.1、4.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>
|
|
||||||
|
|
||||||
<div class="hud" v-if="info">
|
<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>
|
系统: <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 { useEditorShortcuts } from '../editor/useEditorShortcuts'
|
||||||
import { fileToDataUrl } from '../spine/spineSourceBundle'
|
import { fileToDataUrl } from '../spine/spineSourceBundle'
|
||||||
import { downloadEditorConfig } from '../editor/editorConfig'
|
import { downloadEditorConfig } from '../editor/editorConfig'
|
||||||
|
import HelpDialog from './HelpDialog.vue'
|
||||||
|
|
||||||
const store = useParticleStore()
|
const store = useParticleStore()
|
||||||
const holder = ref<HTMLElement | null>(null)
|
const holder = ref<HTMLElement | null>(null)
|
||||||
@@ -329,10 +274,6 @@ function openHelp() {
|
|||||||
showBackgroundMenu.value = false
|
showBackgroundMenu.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function onHelpKeydown(event: KeyboardEvent) {
|
|
||||||
if (event.key === 'Escape' && showHelp.value) showHelp.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleSettings() {
|
function toggleSettings() {
|
||||||
showSettings.value = !showSettings.value
|
showSettings.value = !showSettings.value
|
||||||
if (showSettings.value) showBackgroundMenu.value = false
|
if (showSettings.value) showBackgroundMenu.value = false
|
||||||
@@ -1711,7 +1652,6 @@ function loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
window.addEventListener('keydown', onHelpKeydown)
|
|
||||||
const el = holder.value!
|
const el = holder.value!
|
||||||
app = new Application({ width: el.clientWidth || 800, height: el.clientHeight || 600, backgroundAlpha: 0, antialias: true })
|
app = new Application({ width: el.clientWidth || 800, height: el.clientHeight || 600, backgroundAlpha: 0, antialias: true })
|
||||||
el.appendChild(app.view as unknown as HTMLCanvasElement)
|
el.appendChild(app.view as unknown as HTMLCanvasElement)
|
||||||
@@ -1765,7 +1705,6 @@ onMounted(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('keydown', onHelpKeydown)
|
|
||||||
cancelAnimationFrame(raf)
|
cancelAnimationFrame(raf)
|
||||||
spineRuntime?.destroy()
|
spineRuntime?.destroy()
|
||||||
spineRuntime = null
|
spineRuntime = null
|
||||||
@@ -1843,53 +1782,6 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
.help-btn:hover, .help-btn.on { border-color: #7774ff; background: #343b63; color: #fff; }
|
.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; }
|
.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 { 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-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; }
|
.hud-system-count { width: 3ch; }
|
||||||
|
|||||||
Reference in New Issue
Block a user