perf: 优化实例启动性能并修复过渡动画对齐

依赖校验戳缓存(18.6s→0.1s)、并发化库/资产校验、启动计时埋点、过渡动画200ms、窗口客户区精确对齐、遮罩即时显示、debug构建写文件日志。
This commit is contained in:
Xiao-no-love
2026-09-16 13:10:37 +08:00
parent 776f621436
commit ccb921f4bd
7 changed files with 457 additions and 535 deletions

411
README.md
View File

@ -1,381 +1,98 @@
<div align="center">
<img src="./apps/app/icons/128x128.png" width="128" height="128" alt="Starlight Launcher Logo" />
<h1>Starlight Launcher</h1>
<p><strong>次世代 Minecraft 桌面客户端,全能、美观、全平台覆盖。</strong></p>
# Starlight Launcher — 实例启动性能优化记录
<p>
<a href="https://git.starlight.cool/AxTps/Starlight_Lancher/actions">
<img src="https://img.shields.io/badge/Repo-git.starlight.cool-blue?style=for-the-badge&logo=git" alt="Repository" />
</a>
<a href="https://git.starlight.cool/AxTps/Starlight_Lancher/releases">
<img src="https://img.shields.io/badge/Releases-Download-green?style=for-the-badge&logo=github" alt="Releases" />
</a>
<a href="https://git.starlight.cool/AxTps/Starlight_Lancher/stargazers">
<img src="https://img.shields.io/badge/Stars-★-ffb800?style=for-the-badge&logo=github" alt="Stars" />
</a>
<a href="COPYING.md">
<img src="https://img.shields.io/badge/License-GPL_3.0-blue.svg?style=for-the-badge" alt="License" />
</a>
</p>
> 内部文档,非上线说明。本分支聚焦「实例启动慢」问题的定位与修复。
<p>
<a href="https://skin.starlight.cool/">官方网站</a>
<a href="https://git.starlight.cool/AxTps/Starlight_Lancher/releases/latest">下载最新版</a>
<a href="CONTRIBUTING.md">参与贡献</a>
<a href="CODE_OF_CONDUCT.md">行为准则</a>
</p>
</div>
<details open>
<summary><strong>关于 The Land of StarLight (TLSL)</strong></summary>
## 背景
**The Land Of StarLight**(中文全称**星光领域**,英文简称 **TLSL**)成立于 2014 年,是一个主营 Minecraft 相关内容的综合性平台。平台主要负责人为 **Disy**(因名称常被抢注,在多数平台以 **Disy920** 出现)
用户反馈:点击实例启动后,要等很久才看到游戏窗口
TLSL 的前身可追溯至 2012 年初建立的凋灵服务器TWS。经过多次重组与模式调整于 2014 年 10 月定名为**星光服务器StarLight-Server简称 SLS**。2020 年初随着运营模式改变与业务扩展TLSL 正式成立SLS 成为其主营子项目
经实测定位,问题由多个独立环节叠加造成,本分支逐项修复
如今 TLSL 旗下拥有 Minecraft 服务器 **StarLight-ServerSLS**、面向 Fabric 端的领地模组 **Enclosure** 等项目,致力于打造一个完善的 Minecraft 交流与开发平台。
## 改动清单
**Starlight Launcher** 即是面向 **SLS星光服务器** 打造的 Minecraft 桌面启动器。
### 1. 依赖校验戳缓存(`packages/app-lib/src/launcher/direct_ensure.rs`
</details>
**问题**PCL/HMCL 直连实例每次启动都要对全部库文件与资产对象重算 SHA1。
实测某整合包118 个库 + 3911 个资产对象,合计约 670 MB机械硬盘顺序读仅
27.8 MB/s串行校验耗时约 **17.7 秒**,占整个启动准备阶段的 97%。
---
**方案**新增持久化「已验证」戳缓存key 为文件绝对路径value 为
`(size, mtime)``file_is_current` 先做 stat命中戳则跳过 SHA1 读取;
文件被替换或修改size/mtime 变化)时自动回退到完整 SHA1 校验,**不弱化
损坏检测**。
**Starlight Launcher星光启动器** 是一款免费、开源、跨平台的 Minecraft Java 版第三方启动器,支持在一个客户端中搜索、安装和更新来自 Modrinth 与 CurseForge 的模组、整合包、资源包和光影,并提供实例管理、多种账户认证与个性化外观。
- 缓存文件:`<caches>/linked-verify-stamps.json`(存 Axolotl 自己的缓存目录,
不污染直连安装目录)
- 首次启动建立缓存仍走完整校验;后续启动(含跨进程重启)直接命中
本项目基于 [Modrinth App](https://github.com/modrinth/code) 构建,并在其基础上由 [Axolotl 启动器](https://github.com/Mystic-Stars/Axolotl) 修改而来,移除了不适用于本项目的商业化模块,专注于提供纯净、无广告的桌面启动体验
**效果**`asset_scan` 15788ms → 62ms`ensure_deps` 整体 18.6s → 0.1s
_(注:本项目是调用 Modrinth 公开 API 的独立客户端,与 Rinth, Inc. 无任何关联。)_
### 2. 库/资产校验并发化(`packages/app-lib/src/launcher/direct_ensure.rs`
## 核心优势
在戳缓存基础上,把库扫描与资产扫描从串行 `for` 循环改为
`try_for_each_concurrent`(并发度与下载器一致,`task_concurrency_limit * 2`)。
首次建缓存时也能吃到并发收益。
- **真跨平台体验**:告别繁琐的环境配置,原生支持 Windows、macOS完美兼容 Intel 与 Apple Silicon及各类主流 Linux 发行版。
- **现代化内容生态**:集成 Modrinth 和 CurseForge可在启动器中一键浏览。游戏实例、整合包、模组、资源包及光影均可一键安装与升级彻底告别手动管理依赖的痛苦
- **高度定制化**:无论是主题色调、背景图片,还是离线皮肤,核心功能与视觉展现均由你自由支配。
- **All in one 全新体验**:启动器内置 “实验室” 功能,囊括种子地图、投影工坊等海量使用工具,带来全新原生轮椅体验。
> 并发对机械硬盘的随机小文件读取提升有限IOPS 瓶颈),真正的
> 数量级提升来自上面的戳缓存
## 下载与安装
### 3. 启动阶段计时埋点(`packages/app-lib/src/api/instance/run.rs`、`packages/app-lib/src/launcher/mod.rs`
请前往 [Releases](https://git.starlight.cool/AxTps/Starlight_Lancher/releases/latest) 下载适合你操作系统的最新安装包。
已安装的用户每次均可通过内置的 Tauri 签名校验机制,自动在后台完成更新,无需手动下载安装更新。
| 系统平台 | 推荐下载文件 |
| ----------------------- | ----------------------------------------- |
| **Windows** (10/11 x64) | 下载 `.exe` (NSIS) 安装程序 |
| **macOS** | 下载 `通用 .dmg` 镜像文件 |
| **Linux** (x64) | 提供 `.AppImage``.deb``.rpm` 多种格式 |
## 参与项目开发
Starlight Launcher 的进步离不开社区的反馈与贡献。
如果遇到 Bug 或有新的功能点子,欢迎提交 Issue。如需搭建本地开发环境或查阅打包发布规范请阅读详细的 [贡献指南 (CONTRIBUTING.md)](CONTRIBUTING.md)。
参与社区和贡献代码前,也请先阅读[行为准则 (CODE_OF_CONDUCT.md)](CODE_OF_CONDUCT.md)。
---
# 🌟 启动过渡动画(本次改动)
> 本节记录「游戏启动时窗口平滑过渡」功能的完整实现,供后续维护、移植与继续开发使用。
> **生效平台:仅 Windows**(其他平台为空实现,行为与改动前一致)。
## 一、功能目标
消除「点击启动 → MC 游戏窗口突然弹出 → 把启动器挤走」的割裂感,用一套完整的窗口动画把这段过渡变得顺滑。
启动一个实例后,会经历以下动画序列:
```
点击「启动实例」
① 纯色遮罩出现(启动器主题色,无图)—— 立刻盖住后续所有抖动
② 启动器放大到全屏0.4s 动画,全程置顶 + 聚焦)
③ 全屏后,遮罩上渐显 Mojang SVG logo0.5s
④ 等待 MC 游戏窗口出现(最多 60 秒,期间遮罩一直盖着)
⑤ 缩小前:遮罩背景色 → Mojang 红 (#db1f29) + 渐隐 logo0.5s
⑥ 启动器缩放到 MC 窗口的位置和大小0.4s
⑦ 等待 1 秒(让游戏稳定,遮罩仍在)
⑧ 整体淡出透明0.5s)→ 聚焦游戏窗口 → 启动器最小化
进入轻量模式(隐藏到系统托盘)
```
在启动链路插入 `[launch-timing]` 前缀的计时日志,覆盖:
`hosted_prepare_launch` / `hosted_java_arguments` / `resolve_version_info` /
`resolve_java` / `resolve_gc` / `assemble_client` / `ensure_deps`(细分
`dep_lib_scan` / `asset_scan` / `dep_assets` / `dep_log_config`/
`remove_old_natives` / `extract_linked_natives` / `process_spawn`
**设计要点**
用于定位瓶颈grep `[launch-timing]` 即可。
- **遮罩提前**:纯色遮罩在放大**之前**就出现,所以放大和缩小时的窗口抖动都被盖住,用户看不到。
- **缩放与淡出串行**:先缩放完成,再淡出,不再同步进行(早期版本两者同步,观感差)。
- **动画放慢**:缩放 0.4s(早期 0.2s 太快),淡出 0.5s。
- **修复重开透明**:最小化后重置窗口透明度,并且恢复时用轻量模式**重建全新窗口**,彻底杜绝「重新打开启动器一片透明、需要点击/拖动才恢复」的问题。
- **轻量模式接管**:过渡动画结束后,统一进入轻量模式(隐藏到托盘),不再分别判断用户的「轻量模式 / 启动后隐藏」设置,避免冲突。
### 4. 启动过渡动画优化(`apps/app/src/mc_transition.rs`
## 二、改动文件总览
**a. 动画时长**400ms → 200ms帧数 50 → 25。缓解卡顿。
| 文件 | 改动类型 | 说明 |
|---|---|---|
| `apps/app/src/mc_transition.rs` | **新建** | 核心模块(约 470 行),负责窗口查找、四段动画、遮罩/淡出协调 |
| `apps/app/src/main.rs` | 修改 | 声明模块 + 注册 4 个 Tauri 命令 |
| `apps/app/src/lightweight_mode.rs` | 修改 | `launched` 分支接入过渡,并统一进轻量模式 |
| `apps/app/Cargo.toml` | 修改 | windows crate 增加 `Win32_Graphics_Gdi` feature |
| `apps/app-frontend/src/App.vue` | 修改 | 遮罩三阶段、淡出、透明度重置等前端逻辑 |
| `apps/app-frontend/public/mojang-logo.svg` | 新建 | 过渡遮罩上显示的 Mojang logo |
| `packages/app-lib/.env` | 新建 | 从 `.env.prod` 复制,提供编译期环境变量(非功能改动) |
**b. 窗口对齐修复**:全屏放大与缩回游戏窗口时,左侧留缝、整体偏右。
根因是无边框窗口的不可见 resize border实测窗口比目标大 16×9px
可见内容从 (8, 4.5) 才开始)。改用 `set_client_rect`,通过
`GetWindowRect` / `GetClientRect` 计算边框并补偿,让**可见客户区**精确
落在目标矩形。
## 三、各文件详细说明
**c. 单次 SetWindowPos**:每帧从两次调用(`set_position` + `set_size`
改为单次 `SetWindowPos`,减少重绘。
### 1. `apps/app/src/mc_transition.rs`(新建 · 核心)
**d. 恢复可见**:动画前先 `show()` + `unminimize()`,避免轻量模式遗留
导致遮罩建了却不可见。
> 搜索定位关键词:`mc_transition`
### 5. 遮罩即时显示(`apps/app/src/lightweight_mode.rs`
**关键常量**
**问题**:点击启动后遮罩要等约 10 秒才出现。
| 常量 | 值 | 含义 |
|---|---|---|
| `FIND_RETRIES` | 120 | 等待 MC 窗口的最大轮询次数 |
| `FIND_INTERVAL_MS` | 500 | 每次轮询间隔120 × 500ms = 60 秒) |
| `ANIM_DURATION_MS` | 400 | 放大/缩小动画时长0.4s |
| `ANIM_STEPS` | 50 | 动画帧数400ms / 50 = 8ms 一帧) |
| `FADE_TIMEOUT_MS` | 700 | 等待前端淡出的超时兜底 |
**根因**:收到 `launched` 事件后,代码先 `await maximize_minecraft_window`
(最多轮询 5 秒等游戏窗口),跑完才启动遮罩动画。
**静态变量(跨 await 传信号)**
**方案**:把最大化游戏窗口丢到独立任务,遮罩动画立即启动,两者并行。
- `FADE_DONE` — 等前端淡出完成
- `COVER_DONE` — 等纯色遮罩出现
- `LOGO_IN_DONE` — 等 logo 渐显完成
- `LOGO_OUT_DONE` — 等 logo 渐隐 + 变红完成
### 6. debug 构建写文件日志(`packages/app-lib/src/logger.rs`
**关键函数**
| 函数 | 关键词 | 作用 |
|---|---|---|
| `pub async fn run(app, pid, maximize)` | `run() invoked` | 主入口,串联全部 8 步 |
| `async fn animate_resize(...)` | `animate_resize` | 分帧移动 + 缩放窗口 |
| `fn ease_in_out(t)` | `ease_in_out` | 缓入缓出曲线 |
| `win_impl::find_window(pid)` | `find_cb` / `FOUND_HWND` | 按 pid 枚举顶层窗口 |
| `win_impl::covers_monitor(raw)` | `covers_monitor` | 判断窗口是否铺满显示器 |
| `win_impl::get_rect(raw)` | `get_rect` | 取窗口矩形 |
| `win_impl::focus(raw)` | `SetForegroundWindow` | 把焦点交给游戏 |
| `win_impl::dump_pid_windows(pid)` | `dump_pid_windows` | **调试用**:列出 pid 下所有窗口 |
| `#[tauri::command] mc_transition_fade_done` | — | 前端淡出完成回调 |
| `#[tauri::command] mc_transition_cover_ready` | — | 遮罩出现完成回调 |
| `#[tauri::command] mc_transition_logo_in_done` | — | logo 渐显完成回调 |
| `#[tauri::command] mc_transition_logo_out_done` | — | logo 渐隐完成回调 |
**问题**debug 构建的 `start_logger` 只输出到控制台、不落盘GUI 进程
关闭后无法回溯日志,导致性能计时无法采集。
**⚠️ 三个关键设计约束(改代码前必读)**
**方案**debug 版 logger 增加一层文件输出,写入与 release 相同的
`launcher_logs` 目录,文件名带 `session_debug_` 前缀。
1. **HWND 不能跨 await 持有**
`HWND` 是裸指针,非 `Send`,一旦跨 `await` 持有async 块就不是 `Send`,无法被 `tauri::async_runtime::spawn`
→ 因此全程用 `usize` 保存窗口句柄(变量 `mc_raw`),只在同步的 win32 调用里通过 `to_hwnd()` 临时转回。
搜索关键词:`to_hwnd``FOUND_HWND`
## 结论与边界
2. **`BOOL` 的导入路径**
`windows` crate 0.61 中,`BOOL` 位于 `windows::core::BOOL`**不在** `Win32::Foundation`
搜索关键词:`use windows::core::BOOL`
- **启动器侧**:准备阶段已从 18.6s 优化到约 0.1s,拉起进程约 0.6s,已到极限
- **游戏侧**:窗口出现前约 11s、完整加载约 45.8s230 mod 的 NeoForge 整合包),
属整合包固有成本,任何启动器无法缩短。
- 曾尝试开启 NeoForge 早期窗口(`fml.toml``earlyWindowControl`
该整合包下与 mod 冲突导致更慢11s → 30s**已回滚**。
3. **窗口尺寸过滤阈值**
`find_cb` 里只认宽高都 > 50 的可见窗口,用来排除工具窗口 / 0 尺寸窗口。
## 构建
**⚠️ 调试代码仍在(上线前需清理)**
- `fn dbg(msg)` —— 把日志直接写入 `%USERPROFILE%\mc_transition_debug.log`,绕过 tracing 配置
- 全文件多处 `dbg(...)` 调用
- 等待窗口期间每 2 秒调用一次 `dump_pid_windows`
- 搜索关键词:`fn dbg(``mc_transition_debug.log``dump_pid_windows`
### 2. `apps/app/src/main.rs`
- 第 25 行附近:`mod mc_transition;`
- `invoke_handler``generate_handler!` 宏内注册 4 个命令:
```rust
mc_transition::mc_transition_fade_done,
mc_transition::mc_transition_cover_ready,
mc_transition::mc_transition_logo_in_done,
mc_transition::mc_transition_logo_out_done,
```
- 搜索关键词:`mod mc_transition``mc_transition_fade_done`
### 3. `apps/app/src/lightweight_mode.rs`
`process_event``None if payload.event == "launched"` 分支(约 250 行起):
- 新增调用:`crate::mc_transition::run(&app, payload.pid, payload.maximize_window).await;`
- 过渡完成后**统一**进入轻量模式:`state.enter(&app)`
- **删除**了原来分别判断 `settings.enter_lightweight_mode_on_game_launch``settings.hide_on_process_start` 的逻辑
- 搜索关键词:`crate::mc_transition::run``launched``enter lightweight mode after transition`
**执行顺序**
```
maximize_minecraft_window若用户勾选最大化
→ mc_transition::run完整过渡动画
→ state.enter()(隐藏到托盘)
```
### 4. `apps/app/Cargo.toml`
`[target."cfg(windows)".dependencies.windows]` 的 features 中新增:
```toml
"Win32_Graphics_Gdi",
```
> 原因:`GetMonitorInfoW` / `MonitorFromWindow` / `MONITORINFO` 属于 GDI 模块,不加会编译失败。
- 搜索关键词:`Win32_Graphics_Gdi`
### 5. `apps/app-frontend/src/App.vue`
**变量声明**(约 376~381 行):
```ts
let unlistenMcTransitionFadeout: (() => void) | undefined
let unlistenMcTransitionFocus: (() => void) | undefined
let unlistenMcTransitionCover: (() => void) | undefined
let unlistenMcTransitionLogoIn: (() => void) | undefined
let unlistenMcTransitionLogoOut: (() => void) | undefined
let unlistenMcTransitionReset: (() => void) | undefined
```
**`onMounted` 内注册的监听**(约 500 行起):
| 监听事件 | 作用 |
|---|---|
| `mc-transition-fadeout` | `#app``opacity: 0` + 500ms 过渡510ms 后回调 `mc_transition_fade_done` |
| `mc-transition-cover-show` | 动态创建遮罩 div主题色背景 + 隐藏的 logo渐显后回调 `mc_transition_cover_ready` |
| `mc-transition-logo-in` | logo 渐显opacity 0→1520ms 后回调 `mc_transition_logo_in_done` |
| `mc-transition-logo-out` | 遮罩背景 → `#db1f29` + logo 渐隐520ms 后回调 `mc_transition_logo_out_done` |
| `mc-transition-reset-opacity` | 重置 `#app` 透明度 + 移除遮罩 |
**透明度重置(修复重开透明)**——三重兜底:
- `window``focus` 事件
- `document``visibilitychange` 事件
- Tauri 的 `getCurrentWindow().onFocusChanged`
任一触发即调用 `resetLauncherOpacity()`,把 `#app` 的 opacity 清空。
**`onUnmounted` 内清理**(约 674 行起6 个 `unlistenMcTransition*.?.()`
- 搜索关键词:`unlistenMcTransitionFadeout``mc-transition-fadeout``mc_transition_fade_done``mcCoverEl``resetLauncherOpacity`
**遮罩实现细节**
遮罩是**运行时动态创建**的 DOM不是 Vue template避免改动庞大的 template 结构:
```ts
mcCoverEl = document.createElement('div') // 固定定位、铺满、主题色背景、最高 z-index
mcCoverImg = document.createElement('img') // /mojang-logo.svg初始 opacity 0
```
- 遮罩 id`mc-transition-cover`
- 背景色:`var(--color-brand, #db1f29)`(跟随启动器主题色)
- logo 宽度42%,最大 640px
### 6. `apps/app-frontend/public/mojang-logo.svg`(新建)
过渡遮罩上显示的 Mojang 官方 logo矢量图
## 四、实测记录
调试日志 `%USERPROFILE%\mc_transition_debug.log` 中的一次完整流程实录:
```
run() invoked pid=3088 maximize=false
try#0 ... try#38 candidates: [] <- MC 窗口约 20 秒后才出现
FOUND hwnd=0x3b03da try#40 covers=false
...
```
**关键发现**
- **MC 窗口需要约 20 秒才出现**(带 mod 的实例更慢),所以等待轮询必须足够长(当前 60s
- 早期版本只等 5 秒,导致「启动器毫无变化」的假象——实际是超时静默放弃了。
## 五、编译与运行Windows
### 前置准备
```bat
:: 1. 子模块(本项目不是 git 仓库,需手动 clone
git clone https://github.com/Cubitect/cubiomes.git apps/app/vendor/cubiomes
git clone https://github.com/Axolotl-Launcher/blockbench-skin-standalone.git third-party/blockbench
:: 2. 环境变量(或把 .env.prod 复制为 packages/app-lib/.env
set "PATH=%USERPROFILE%\.cargo\bin;%PATH%"
set "MODRINTH_URL=https://modrinth.com/"
set "MODRINTH_API_BASE_URL=https://api.modrinth.com/"
set "MODRINTH_ARCHON_BASE_URL=https://archon.modrinth.com/"
set "MODRINTH_API_URL=https://api.modrinth.com/v2/"
set "MODRINTH_API_URL_V3=https://api.modrinth.com/v3/"
set "MODRINTH_SOCKET_URL=wss://api.modrinth.com/"
set "MODRINTH_LAUNCHER_META_URL=https://launcher-meta.modrinth.com/"
```
### 构建
```bat
:: 前端
pnpm install
pnpm --filter @modrinth/app-frontend run build
:: 后端 debug产物 target/debug/theseus_gui.exe约 155 MB
```bash
# debug含计时埋点、文件日志
cargo build -p theseus_gui
:: 后端 release产物 target/release/theseus_gui.exe约 75 MB
cargo build -p theseus_gui --release
```
### 已知坑
| 坑 | 现象 | 解决 |
|---|---|---|
| 子模块缺失 | `build.rs` panic`Blockbench skin editor submodule is missing` | 手动 clone 两个子模块 |
| 资源路径校验 | `resource path resources\blockbench-skin doesn't exist` | 构建会自动生成;若报错手动建空目录 |
| 环境变量缺失 | `environment variable MODRINTH_API_URL not defined` | 见上方环境变量,或复制 `.env` |
| 数据库迁移冲突 | `migration ... was previously applied but is missing` | 删除 `%APPDATA%\cool.starlight.launcher\release\app.db` 后重启 |
| exe 被占用 | `failed to remove file ...theseus_gui.exe`(拒绝访问) | `taskkill /F /IM theseus_gui.exe` 后重编 |
| `pnpm app:build` 失败 | 找不到 cargo | 那会走完整 `tauri build` 打包;只构建前端请用 `--filter @modrinth/app-frontend` |
## 六、待办 / TODO
| # | 事项 | 优先级 | 关键词 |
|---|---|---|---|
| 1 | **清理调试代码**:删 `fn dbg` + 所有 `dbg(...)` + `dump_pid_windows` 调用 | 高 | `fn dbg(``mc_transition_debug.log` |
| 2 | 等待窗口超时60s可做成可配置 / 事件驱动 | 中 | `FIND_RETRIES` |
| 3 | 多显示器场景未充分测试(已按窗口所在屏取显示器) | 中 | `monitor_rect` |
| 4 | 前端淡出若卡顿靠 700ms 兜底 | 低 | `FADE_TIMEOUT_MS` |
| 5 | `SetForegroundWindow` 可能被系统拒绝,未做失败重试 | 低 | `focus` |
| 6 | 未来若做 macOS / Linux 支持:需 `CGWindowListCopyWindowInfo` / X11Wayland 基本不可行) | 低 | `#[cfg(target_os]` |
## 七、快速搜索索引
| 想找什么 | 搜这个关键词 |
|---|---|
| 核心模块 | `mc_transition` |
| 过渡主流程 | `pub async fn run(app` |
| 八步流程标记 | `step 1` ~ `step 8` |
| 找 MC 窗口 | `find_window``find_cb` |
| 全屏判定 | `covers_monitor` |
| 缩放动画 | `animate_resize``ANIM_DURATION_MS` |
| 缓动曲线 | `ease_in_out` |
| 纯色遮罩事件 | `mc-transition-cover-show` |
| logo 渐显事件 | `mc-transition-logo-in` |
| logo 渐隐/变红事件 | `mc-transition-logo-out` |
| 淡出事件 | `mc-transition-fadeout` |
| 透明度重置事件 | `mc-transition-reset-opacity` |
| 前端回调命令 | `mc_transition_cover_ready``mc_transition_logo_in_done``mc_transition_logo_out_done``mc_transition_fade_done` |
| 接入点 | `crate::mc_transition::run` |
| 透明度重置函数 | `resetLauncherOpacity` |
| 遮罩 DOM | `mc-transition-cover``mcCoverEl` |
| 调试日志(待删) | `fn dbg(``mc_transition_debug.log` |
| 调试日志文件 | `%USERPROFILE%\mc_transition_debug.log` |
| windows feature | `Win32_Graphics_Gdi` |
| 数据库冲突 | `previously applied but is missing` |
---
_文档结束。功能已跑通上线前记得清理调试代码喵。_
# release
cargo build --release -p theseus_gui
```