From 383a83d0c5c401386863e07209278f9a5dca2e63 Mon Sep 17 00:00:00 2001 From: s3d-i Date: Mon, 24 Nov 2025 02:39:56 +0800 Subject: [PATCH] fix(stage-ui): early return for Live2D drop-shadow update hook (#758) * fix(live2d): - Short-circuited the Live2D drop-shadow updater so it only computes/applies filters and runs the animation loop when the shadow setting is enabled - Default live2dShadowEnabled to true * [autofix.ci] apply automated fixes * Update packages/stage-ui/src/components/scenes/live2d/Model.vue * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Neko --- .../src/main/windows/main/index.ts | 2 +- .../main/windows/main/rpc/index.electron.ts | 2 +- .../src/components/scenes/live2d/Model.vue | 28 +++++++++++-------- packages/stage-ui/src/stores/settings.ts | 2 +- .../ui/src/composables/use-deferred-mount.ts | 2 +- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/apps/stage-tamagotchi/src/main/windows/main/index.ts b/apps/stage-tamagotchi/src/main/windows/main/index.ts index 38a7dc49f..585536ecb 100644 --- a/apps/stage-tamagotchi/src/main/windows/main/index.ts +++ b/apps/stage-tamagotchi/src/main/windows/main/index.ts @@ -1,7 +1,7 @@ import type { BrowserWindowConstructorOptions, Rectangle } from 'electron' -import type { WidgetsWindowManager } from '../widgets' import type { NoticeWindowManager } from '../notice' +import type { WidgetsWindowManager } from '../widgets' import { dirname, join, resolve } from 'node:path' import { env } from 'node:process' diff --git a/apps/stage-tamagotchi/src/main/windows/main/rpc/index.electron.ts b/apps/stage-tamagotchi/src/main/windows/main/rpc/index.electron.ts index 7da3d3dba..ac2030f36 100644 --- a/apps/stage-tamagotchi/src/main/windows/main/rpc/index.electron.ts +++ b/apps/stage-tamagotchi/src/main/windows/main/rpc/index.electron.ts @@ -33,5 +33,5 @@ export function setupMainWindowElectronInvokes(params: { defineInvokeHandler(context, electronOpenMainDevtools, () => params.window.webContents.openDevTools({ mode: 'detach' })) defineInvokeHandler(context, electronOpenSettings, async () => toggleWindowShow(await params.settingsWindow())) defineInvokeHandler(context, electronOpenChat, async () => toggleWindowShow(await params.chatWindow())) - defineInvokeHandler(context, noticeWindowEventa.openWindow, (payload) => params.noticeWindow.open(payload)) + defineInvokeHandler(context, noticeWindowEventa.openWindow, payload => params.noticeWindow.open(payload)) } diff --git a/packages/stage-ui/src/components/scenes/live2d/Model.vue b/packages/stage-ui/src/components/scenes/live2d/Model.vue index c018c983f..6627a7069 100644 --- a/packages/stage-ui/src/components/scenes/live2d/Model.vue +++ b/packages/stage-ui/src/components/scenes/live2d/Model.vue @@ -460,16 +460,17 @@ const dropShadowColorComputer = ref() const dropShadowAnimationId = ref(0) function updateDropShadowFilter() { - if (model.value) { - const color = getComputedStyle(dropShadowColorComputer.value!).backgroundColor - dropShadowFilter.value.color = Number(formatHex(color)!.replace('#', '0x')) - if (live2dShadowEnabled.value) { - model.value.filters = [dropShadowFilter.value] - } - else { - model.value.filters = [] - } + if (!model.value) + return + + if (!live2dShadowEnabled.value) { + model.value.filters = [] + return } + + const color = getComputedStyle(dropShadowColorComputer.value!).backgroundColor + dropShadowFilter.value.color = Number(formatHex(color)!.replace('#', '0x')) + model.value.filters = [dropShadowFilter.value] } watch([() => props.width, () => props.height], () => handleResize()) @@ -483,11 +484,16 @@ watch(() => props.scale, setScaleAndPosition) // TODO: This is hacky! function updateDropShadowFilterLoop() { updateDropShadowFilter() + if (!live2dShadowEnabled.value) { + dropShadowAnimationId.value = 0 + return + } + dropShadowAnimationId.value = requestAnimationFrame(updateDropShadowFilterLoop) } -watch(themeColorsHueDynamic, () => { - if (themeColorsHueDynamic.value) { +watch([themeColorsHueDynamic, live2dShadowEnabled], ([dynamic, shadowEnabled]) => { + if (dynamic && shadowEnabled) { dropShadowAnimationId.value = requestAnimationFrame(updateDropShadowFilterLoop) } else { diff --git a/packages/stage-ui/src/stores/settings.ts b/packages/stage-ui/src/stores/settings.ts index f1189ac1b..a927ad0e0 100644 --- a/packages/stage-ui/src/stores/settings.ts +++ b/packages/stage-ui/src/stores/settings.ts @@ -102,7 +102,7 @@ export const useSettings = defineStore('settings', () => { const live2dDisableFocus = useLocalStorage('settings/live2d/disable-focus', false) const live2dIdleAnimationEnabled = useLocalStorage('settings/live2d/idle-animation-enabled', true) const live2dAutoBlinkEnabled = useLocalStorage('settings/live2d/auto-blink-enabled', true) - const live2dShadowEnabled = useLocalStorage('settings/live2d/shadow-enabled', false) + const live2dShadowEnabled = useLocalStorage('settings/live2d/shadow-enabled', true) const disableTransitions = useLocalStorage('settings/disable-transitions', true) const usePageSpecificTransitions = useLocalStorage('settings/use-page-specific-transitions', true) diff --git a/packages/ui/src/composables/use-deferred-mount.ts b/packages/ui/src/composables/use-deferred-mount.ts index 883f046a7..94a9f40d9 100644 --- a/packages/ui/src/composables/use-deferred-mount.ts +++ b/packages/ui/src/composables/use-deferred-mount.ts @@ -5,7 +5,7 @@ export function useDeferredMount() { onMounted(() => { // NOTICE: yield the main thread to the browser to paint. - // Other approaches work too, e.g. double RAF like here, or a setTimeout 0, or Suspense with async component, etc. + // Other approaches work too, e.g. double RAF like here, or a setTimeout 0, or Suspense with async component, etc. // Virtualization somewhat helps, however, virtual list may break Ctrl-F and Ctrl-A. requestAnimationFrame(() => { requestAnimationFrame(() => {