feat: add Minecraft launch transition animation (cover/logo phases)
This commit is contained in:
1
apps/app-frontend/public/mojang-logo.svg
Normal file
1
apps/app-frontend/public/mojang-logo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg height="388" width="2500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 375.103901073386 57.671"><path d="M57.355.316H16.519C7.396.316 0 7.713 0 16.834V57.671h40.836c9.124 0 16.519-7.396 16.519-16.518V7.38z" fill="#db1f29"/><path d="M13.772 48.104c-4.892 0-4.892-4.892-4.892-4.892V18.746c0-4.893 4.892-4.893 4.892-4.893h9.786c4.894 0 9.786 4.893 9.786 4.893s4.894 0 0 0c0-14.251 4.501 5.285 9.786 0 3.46-3.459 4.893 17.125 4.893 17.125l-4.893-2.444s0-4.894-7.339-9.786c-9.104-6.071-19.572-2.071-19.572 7.338 0 19.196 31.804 12.233 31.804 12.233s0 4.892-4.893 4.892H13.772z" fill="#fff"/><path d="M38.238 13.854c0-1.35 1.095-7.34 2.445-7.34 1.352 0 2.446 5.99 2.446 7.34a2.445 2.445 0 1 1-4.891 0z" fill="#fff"/><path d="M105.714 56.675V21.379L93.342 39.77H87.85L75.479 21.379v35.296h-9.85V.996h7.899l17.109 25.186L107.747.996h7.745v55.679zM149.727 57.671c-7.744 0-14.943-3.021-20.271-8.507-5.375-5.545-8.333-12.763-8.333-20.325 0-7.57 2.959-14.788 8.333-20.325C134.783 3.101 142.169 0 149.727 0c7.636 0 14.858 3.02 20.337 8.502 5.384 5.549 8.343 12.767 8.343 20.336 0 7.562-2.958 14.781-8.332 20.325-5.412 5.489-12.636 8.508-20.348 8.508zm0-47.666c-4.919 0-9.567 1.979-13.088 5.574-3.56 3.484-5.512 8.188-5.512 13.26 0 5.069 1.952 9.77 5.496 13.237 3.531 3.61 8.179 5.59 13.104 5.59 4.947 0 9.774-2.031 13.242-5.573 3.506-3.51 5.433-8.215 5.433-13.254 0-5.042-1.927-9.75-5.426-13.252-3.48-3.55-8.307-5.582-13.249-5.582zM180.215 56.675v-9.396h1.062c16.254 0 19.52-5.682 19.52-14.848V10.236h-20.582V1.071h30.432v31.36c0 16.993-8.783 24.243-29.369 24.243h-1.063zM253.239 56.675l-5.128-13.543h-20.26l-5.204 13.543h-10.633L234.354.312h7.106l22.34 56.363zm-8.762-22.931l-6.491-17.066-6.491 17.066zM301.564 56.675l-24.237-35.068v35.068h-9.853V.996h7.588l24.467 35.376V.996h9.776v55.679zM343.234 57.671c-7.744 0-14.943-3.021-20.271-8.506-5.375-5.546-8.334-12.764-8.334-20.326 0-7.57 2.959-14.788 8.332-20.325C328.29 3.101 335.677 0 343.234 0c7.634 0 14.857 3.02 20.337 8.502a29.986 29.986 0 0 1 4.891 6.671l.842 1.566h-11.782l-.501-.563a12.058 12.058 0 0 0-.539-.591c-3.479-3.549-8.305-5.58-13.247-5.58-4.919 0-9.567 1.979-13.089 5.574-3.559 3.484-5.511 8.188-5.511 13.26 0 5.069 1.952 9.77 5.496 13.237 3.53 3.61 8.179 5.59 13.104 5.59 4.947 0 9.773-2.031 13.24-5.573a18.397 18.397 0 0 0 4.85-8.598h-20.991V23.49h31.095l.14.899c.229 1.469.347 2.965.347 4.45 0 7.562-2.959 14.78-8.331 20.325-5.415 5.488-12.639 8.507-20.351 8.507z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@ -373,6 +373,12 @@ let allowWindowClose = false
|
||||
let unlistenCloseRequested: (() => void) | undefined
|
||||
let unlistenLightweightModeError: (() => void) | undefined
|
||||
let unlistenSystemAccentColor: (() => void) | undefined
|
||||
let unlistenMcTransitionFadeout: (() => void) | undefined
|
||||
let unlistenMcTransitionFocus: (() => void) | undefined
|
||||
let unlistenMcTransitionCover: (() => void) | undefined
|
||||
let unlistenMcTransitionLogoIn: (() => void) | undefined
|
||||
let unlistenMcTransitionLogoOut: (() => void) | undefined
|
||||
let unlistenMcTransitionReset: (() => void) | undefined
|
||||
let maximizedStateTimer: ReturnType<typeof setTimeout> | undefined
|
||||
let unlistenWindowResize: (() => void) | undefined
|
||||
const minecraftCrashModal = ref()
|
||||
@ -491,6 +497,104 @@ onMounted(async () => {
|
||||
checkUpdates()
|
||||
void warnIfRunningElevated()
|
||||
startDirectLinkSync()
|
||||
unlistenMcTransitionFadeout = await listen('mc-transition-fadeout', async () => {
|
||||
// 游戏窗口已就位、启动器已缩放到同尺寸。这里做 0.5s CSS 淡出,
|
||||
// 完成后回调 Rust,由后端执行聚焦游戏 + 最小化启动器。
|
||||
const root = document.getElementById('app')
|
||||
if (root) {
|
||||
root.style.transition = 'opacity 500ms ease-out'
|
||||
root.style.opacity = '0'
|
||||
}
|
||||
window.setTimeout(() => {
|
||||
void invoke('mc_transition_fade_done').catch(() => {})
|
||||
}, 510)
|
||||
})
|
||||
|
||||
// 窗口恢复可见时,清掉残留的淡出透明度,避免再次打开时全透明。
|
||||
const resetLauncherOpacity = () => {
|
||||
const root = document.getElementById('app')
|
||||
if (root) {
|
||||
root.style.transition = 'none'
|
||||
root.style.opacity = ''
|
||||
void root.offsetHeight
|
||||
}
|
||||
}
|
||||
window.addEventListener('focus', resetLauncherOpacity)
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible') resetLauncherOpacity()
|
||||
})
|
||||
unlistenMcTransitionFocus = await getCurrentWindow().onFocusChanged(({ payload: focused }) => {
|
||||
if (focused) resetLauncherOpacity()
|
||||
})
|
||||
|
||||
// ============ 启动过渡遮罩(三阶段) ============
|
||||
// 阶段1:纯色遮罩(主题色,无图)—— 盖住放大抖动
|
||||
// 阶段2:全屏后渐显 SVG logo
|
||||
// 阶段3:缩小前背景变 Mojang 红 + 渐隐 logo
|
||||
let mcCoverEl = null
|
||||
let mcCoverImg = null
|
||||
|
||||
unlistenMcTransitionCover = await listen('mc-transition-cover-show', () => {
|
||||
const app = document.getElementById('app')
|
||||
if (!app) return
|
||||
if (!mcCoverEl) {
|
||||
mcCoverEl = document.createElement('div')
|
||||
mcCoverEl.id = 'mc-transition-cover'
|
||||
mcCoverEl.style.cssText = [
|
||||
'position: fixed',
|
||||
'inset: 0',
|
||||
'z-index: 999999',
|
||||
'display: flex',
|
||||
'align-items: center',
|
||||
'justify-content: center',
|
||||
'background: var(--color-brand, #db1f29)',
|
||||
'transition: background-color 500ms ease, opacity 300ms ease-out',
|
||||
'opacity: 0',
|
||||
'pointer-events: none',
|
||||
].join(';')
|
||||
mcCoverImg = document.createElement('img')
|
||||
mcCoverImg.src = '/mojang-logo.svg'
|
||||
mcCoverImg.alt = ''
|
||||
mcCoverImg.style.cssText =
|
||||
'width: 42%; max-width: 640px; height: auto; opacity: 0; transition: opacity 500ms ease-out;'
|
||||
mcCoverEl.appendChild(mcCoverImg)
|
||||
app.appendChild(mcCoverEl)
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
mcCoverEl.style.opacity = '1'
|
||||
})
|
||||
window.setTimeout(() => {
|
||||
void invoke('mc_transition_cover_ready').catch(() => {})
|
||||
}, 320)
|
||||
})
|
||||
|
||||
unlistenMcTransitionLogoIn = await listen('mc-transition-logo-in', () => {
|
||||
if (mcCoverImg) mcCoverImg.style.opacity = '1'
|
||||
window.setTimeout(() => {
|
||||
void invoke('mc_transition_logo_in_done').catch(() => {})
|
||||
}, 520)
|
||||
})
|
||||
|
||||
unlistenMcTransitionLogoOut = await listen('mc-transition-logo-out', () => {
|
||||
if (mcCoverEl) mcCoverEl.style.backgroundColor = '#db1f29'
|
||||
if (mcCoverImg) mcCoverImg.style.opacity = '0'
|
||||
window.setTimeout(() => {
|
||||
void invoke('mc_transition_logo_out_done').catch(() => {})
|
||||
}, 520)
|
||||
})
|
||||
|
||||
unlistenMcTransitionReset = await listen('mc-transition-reset-opacity', () => {
|
||||
const app = document.getElementById('app')
|
||||
if (app) {
|
||||
app.style.transition = 'none'
|
||||
app.style.opacity = ''
|
||||
}
|
||||
if (mcCoverEl) {
|
||||
mcCoverEl.remove()
|
||||
mcCoverEl = null
|
||||
mcCoverImg = null
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
let directLinkSync: (() => Promise<void>) | undefined
|
||||
@ -567,6 +671,12 @@ onUnmounted(async () => {
|
||||
window.removeEventListener('keydown', handleGlobalKeydown, true)
|
||||
unlistenCloseRequested?.()
|
||||
unlistenLightweightModeError?.()
|
||||
unlistenMcTransitionFadeout?.()
|
||||
unlistenMcTransitionFocus?.()
|
||||
unlistenMcTransitionCover?.()
|
||||
unlistenMcTransitionLogoIn?.()
|
||||
unlistenMcTransitionLogoOut?.()
|
||||
unlistenMcTransitionReset?.()
|
||||
unlistenSystemAccentColor?.()
|
||||
document.querySelector('body').removeEventListener('click', handleClick)
|
||||
document.querySelector('body').removeEventListener('auxclick', handleAuxClick)
|
||||
|
||||
Reference in New Issue
Block a user