2026-09-13 10:51:00 +08:00

Starlight Launcher Logo

Starlight Launcher

次世代 Minecraft 桌面客户端,全能、美观、全平台覆盖。

Repository Releases Stars License

官方网站 下载最新版 参与贡献 行为准则

关于 The Land of StarLight (TLSL)

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 桌面启动器。


Starlight Launcher星光启动器 是一款免费、开源、跨平台的 Minecraft Java 版第三方启动器,支持在一个客户端中搜索、安装和更新来自 Modrinth 与 CurseForge 的模组、整合包、资源包和光影,并提供实例管理、多种账户认证与个性化外观。

本项目基于 Modrinth App 构建,并在其基础上由 Axolotl 启动器 修改而来,移除了不适用于本项目的商业化模块,专注于提供纯净、无广告的桌面启动体验。

(注:本项目是调用 Modrinth 公开 API 的独立客户端,与 Rinth, Inc. 无任何关联。)

核心优势

  • 真跨平台体验:告别繁琐的环境配置,原生支持 Windows、macOS完美兼容 Intel 与 Apple Silicon及各类主流 Linux 发行版。
  • 现代化内容生态:集成 Modrinth 和 CurseForge可在启动器中一键浏览。游戏实例、整合包、模组、资源包及光影均可一键安装与升级彻底告别手动管理依赖的痛苦。
  • 高度定制化:无论是主题色调、背景图片,还是离线皮肤,核心功能与视觉展现均由你自由支配。
  • All in one 全新体验:启动器内置 “实验室” 功能,囊括种子地图、投影工坊等海量使用工具,带来全新原生轮椅体验。

下载与安装

请前往 Releases 下载适合你操作系统的最新安装包。 已安装的用户每次均可通过内置的 Tauri 签名校验机制,自动在后台完成更新,无需手动下载安装更新。

系统平台 推荐下载文件
Windows (10/11 x64) 下载 .exe (NSIS) 安装程序
macOS 下载 通用 .dmg 镜像文件
Linux (x64) 提供 .AppImage.deb.rpm 多种格式

参与项目开发

Starlight Launcher 的进步离不开社区的反馈与贡献。 如果遇到 Bug 或有新的功能点子,欢迎提交 Issue。如需搭建本地开发环境或查阅打包发布规范请阅读详细的 贡献指南 (CONTRIBUTING.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)→ 聚焦游戏窗口 → 启动器最小化
      ↓
进入轻量模式(隐藏到系统托盘)

设计要点

  • 遮罩提前:纯色遮罩在放大之前就出现,所以放大和缩小时的窗口抖动都被盖住,用户看不到。
  • 缩放与淡出串行:先缩放完成,再淡出,不再同步进行(早期版本两者同步,观感差)。
  • 动画放慢:缩放 0.4s(早期 0.2s 太快),淡出 0.5s。
  • 修复重开透明:最小化后重置窗口透明度,并且恢复时用轻量模式重建全新窗口,彻底杜绝「重新打开启动器一片透明、需要点击/拖动才恢复」的问题。
  • 轻量模式接管:过渡动画结束后,统一进入轻量模式(隐藏到托盘),不再分别判断用户的「轻量模式 / 启动后隐藏」设置,避免冲突。

二、改动文件总览

文件 改动类型 说明
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 复制,提供编译期环境变量(非功能改动)

三、各文件详细说明

1. apps/app/src/mc_transition.rs(新建 · 核心)

搜索定位关键词:mc_transition

关键常量

常量 含义
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 等待前端淡出的超时兜底

静态变量(跨 await 传信号)

  • FADE_DONE — 等前端淡出完成
  • COVER_DONE — 等纯色遮罩出现
  • LOGO_IN_DONE — 等 logo 渐显完成
  • LOGO_OUT_DONE — 等 logo 渐隐 + 变红完成

关键函数

函数 关键词 作用
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 渐隐完成回调

⚠️ 三个关键设计约束(改代码前必读)

  1. HWND 不能跨 await 持有HWND 是裸指针,非 Send,一旦跨 await 持有async 块就不是 Send,无法被 tauri::async_runtime::spawn。 → 因此全程用 usize 保存窗口句柄(变量 mc_raw),只在同步的 win32 调用里通过 to_hwnd() 临时转回。 搜索关键词:to_hwndFOUND_HWND

  2. BOOL 的导入路径windows crate 0.61 中,BOOL 位于 windows::core::BOOL不在 Win32::Foundation。 搜索关键词:use windows::core::BOOL

  3. 窗口尺寸过滤阈值find_cb 里只认宽高都 > 50 的可见窗口,用来排除工具窗口 / 0 尺寸窗口。

⚠️ 调试代码仍在(上线前需清理)

  • fn dbg(msg) —— 把日志直接写入 %USERPROFILE%\mc_transition_debug.log,绕过 tracing 配置
  • 全文件多处 dbg(...) 调用
  • 等待窗口期间每 2 秒调用一次 dump_pid_windows
  • 搜索关键词:fn dbg(mc_transition_debug.logdump_pid_windows

2. apps/app/src/main.rs

  • 第 25 行附近:mod mc_transition;
  • invoke_handlergenerate_handler! 宏内注册 4 个命令:
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_transitionmc_transition_fade_done

3. apps/app/src/lightweight_mode.rs

process_eventNone 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_launchsettings.hide_on_process_start 的逻辑
  • 搜索关键词:crate::mc_transition::runlaunchedenter lightweight mode after transition

执行顺序

maximize_minecraft_window若用户勾选最大化
  → mc_transition::run完整过渡动画
  → state.enter()(隐藏到托盘)

4. apps/app/Cargo.toml

[target."cfg(windows)".dependencies.windows] 的 features 中新增:

"Win32_Graphics_Gdi",

原因:GetMonitorInfoW / MonitorFromWindow / MONITORINFO 属于 GDI 模块,不加会编译失败。

  • 搜索关键词:Win32_Graphics_Gdi

5. apps/app-frontend/src/App.vue

变量声明(约 376~381 行):

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 #appopacity: 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 透明度 + 移除遮罩

透明度重置(修复重开透明)——三重兜底:

  • windowfocus 事件
  • documentvisibilitychange 事件
  • Tauri 的 getCurrentWindow().onFocusChanged

任一触发即调用 resetLauncherOpacity(),把 #app 的 opacity 清空。

onUnmounted 内清理(约 674 行起6 个 unlistenMcTransition*.?.()

  • 搜索关键词:unlistenMcTransitionFadeoutmc-transition-fadeoutmc_transition_fade_donemcCoverElresetLauncherOpacity

遮罩实现细节

遮罩是运行时动态创建的 DOM不是 Vue template避免改动庞大的 template 结构:

mcCoverEl = document.createElement('div')   // 固定定位、铺满、主题色背景、最高 z-index
mcCoverImg = document.createElement('img')  // /mojang-logo.svg初始 opacity 0
  • 遮罩 idmc-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

前置准备

:: 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/"

构建

:: 前端
pnpm install
pnpm --filter @modrinth/app-frontend run build

:: 后端 debug产物 target/debug/theseus_gui.exe约 155 MB
cargo build -p theseus_gui

:: 后端 release产物 target/release/theseus_gui.exe约 75 MB
cargo build -p theseus_gui --release

已知坑

现象 解决
子模块缺失 build.rs panicBlockbench 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_windowfind_cb
全屏判定 covers_monitor
缩放动画 animate_resizeANIM_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_readymc_transition_logo_in_donemc_transition_logo_out_donemc_transition_fade_done
接入点 crate::mc_transition::run
透明度重置函数 resetLauncherOpacity
遮罩 DOM mc-transition-covermcCoverEl
调试日志(待删) fn dbg(mc_transition_debug.log
调试日志文件 %USERPROFILE%\mc_transition_debug.log
windows feature Win32_Graphics_Gdi
数据库冲突 previously applied but is missing

文档结束。功能已跑通,上线前记得清理调试代码喵。

Description
实例启动动画
Readme 115 MiB
Languages
JavaScript 54.8%
Rust 20.3%
Vue 12.3%
TypeScript 8.4%
HTML 1.8%
Other 2.2%