From bc8cb59e6b99befb9035dd67742bd25090b55896 Mon Sep 17 00:00:00 2001 From: Neko Ayaka Date: Mon, 25 Aug 2025 01:28:35 +0800 Subject: [PATCH] fix(stage-*): model not loading when entering main stage --- .../stage-web/src/pages/devtools/polaroid.vue | 5 + .../Settings/ModelSettings/index.vue | 18 +- .../stage-ui/src/components/Scenes/Stage.vue | 29 +- .../PoppinText/PoppinMarkdown.web.story.vue | 252 ------------------ .../Widgets/PoppinText/PoppinMarkdown.web.vue | 212 --------------- .../stage-ui/src/stores/display-models.ts | 4 +- packages/stage-ui/src/stores/settings.ts | 24 +- 7 files changed, 61 insertions(+), 483 deletions(-) delete mode 100644 packages/stage-ui/src/components/Widgets/PoppinText/PoppinMarkdown.web.story.vue delete mode 100644 packages/stage-ui/src/components/Widgets/PoppinText/PoppinMarkdown.web.vue diff --git a/apps/stage-web/src/pages/devtools/polaroid.vue b/apps/stage-web/src/pages/devtools/polaroid.vue index a581f91ac..202a1eeb5 100644 --- a/apps/stage-web/src/pages/devtools/polaroid.vue +++ b/apps/stage-web/src/pages/devtools/polaroid.vue @@ -1,11 +1,15 @@ diff --git a/packages/stage-ui/src/components/Scenes/Stage.vue b/packages/stage-ui/src/components/Scenes/Stage.vue index a4c859fe1..52796ba25 100644 --- a/packages/stage-ui/src/components/Scenes/Stage.vue +++ b/packages/stage-ui/src/components/Scenes/Stage.vue @@ -27,6 +27,7 @@ import { useLive2d } from '../../stores/live2d' import { useSpeechStore } from '../../stores/modules/speech' import { useProvidersStore } from '../../stores/providers' import { useSettings } from '../../stores/settings' +import { useVRM } from '../../stores/vrm' withDefaults(defineProps<{ paused?: boolean @@ -41,12 +42,34 @@ const db = ref() const vrmViewerRef = ref<{ setExpression: (expression: string) => void }>() -const { stageModelRenderer, stageViewControlsEnabled, live2dDisableFocus, stageModelSelectedUrl } = storeToRefs(useSettings()) +const settingsStore = useSettings() +const { stageModelRenderer, stageViewControlsEnabled, live2dDisableFocus, stageModelSelectedUrl } = storeToRefs(settingsStore) const { mouthOpenSize } = storeToRefs(useSpeakingStore()) const { audioContext, calculateVolume } = useAudioContext() const { onBeforeMessageComposed, onBeforeSend, onTokenLiteral, onTokenSpecial, onStreamEnd, onAssistantResponseEnd } = useChatStore() const providersStore = useProvidersStore() +const live2dStore = useLive2d() +const vrmStore = useVRM() + +const showStage = ref(true) + +live2dStore.onShouldUpdateView(async () => { + showStage.value = false + await settingsStore.updateStageModel() + setTimeout(() => { + showStage.value = true + }, 100) +}) + +vrmStore.onShouldUpdateView(async () => { + showStage.value = false + await settingsStore.updateStageModel() + setTimeout(() => { + showStage.value = true + }, 100) +}) + const audioAnalyser = ref() const nowSpeaking = ref(false) const lipSyncStarted = ref(false) @@ -229,7 +252,7 @@ onMounted(async () => {
{ :disable-focus-at="live2dDisableFocus" /> -import { FieldRange } from '@proj-airi/ui' -import { ref } from 'vue' - -import PoppinMarkdown from './PoppinMarkdown.web.vue' - -import { - createCutePopupAnimator, - createFadeAnimator, - createFloatAnimator, - createPopupAnimator, - createStackAnimator, -} from './animators' - -const duration = ref(750) - -// Sample markdown content -const markdownText = ref(`# Hello World - -This is **bold text** and *italic text*. - -Here's a list: -- Item 1 -- Item 2 -- Item 3 - -\`\`\`javascript -console.log('Hello, world!'); -\`\`\` - -> This is a blockquote with some **bold** content. - -And here's a [link](https://example.com) and some inline \`code\`.`) - -const chatMarkdown = ref(`Hi! I can help you with **markdown**. Here are some examples: - -- *Italics* and **bold** text -- \`inline code\` snippets -- Even [links](https://example.com) - -\`\`\`typescript -function greet(name: string) { - console.log(\`Hello, \${name}!\`); -} -\`\`\` - -What would you like to know?`) - -function createMarkdownStream(text: string) { - return new ReadableStream({ - start(controller) { - const bytes = new TextEncoder().encode(text) - let index = 0 - const interval = setInterval(() => { - if (index < bytes.length) { - controller.enqueue(bytes.subarray(index, index + 1)) - index++ - } - else { - clearInterval(interval) - controller.close() - } - }, 30 + 50 * Math.random()) // Faster for better demo - }, - }) -} - -const streamingMarkdown = createMarkdownStream(`# Streaming Markdown Demo - -This text is being **streamed** character by character! - -## Features - -- Real-time *markdown* rendering -- **Character-by-character** animation -- Support for \`code\` and other elements - -\`\`\`javascript -// Code blocks appear as complete units -const message = "Hello from streaming markdown!"; -console.log(message); -\`\`\` - -> Blockquotes work too with **mixed** formatting. - -Pretty cool, right?`) - -const chatStreamingMarkdown = createMarkdownStream(`🤖 **AI Assistant**: Hello! I can help you with various tasks. - -Here's what I can do: -- Answer questions about **programming** -- Help with \`code debugging\` -- Explain *technical concepts* - -\`\`\`python -# Example: Python function -def greet_user(name): - return f"Hello, {name}! How can I help?" - -print(greet_user("Developer")) -\`\`\` - -> 💡 **Tip**: I stream my responses in real-time for a better experience! - -What would you like to work on today?`) - - - diff --git a/packages/stage-ui/src/components/Widgets/PoppinText/PoppinMarkdown.web.vue b/packages/stage-ui/src/components/Widgets/PoppinText/PoppinMarkdown.web.vue deleted file mode 100644 index d9e10b0ab..000000000 --- a/packages/stage-ui/src/components/Widgets/PoppinText/PoppinMarkdown.web.vue +++ /dev/null @@ -1,212 +0,0 @@ - - - - diff --git a/packages/stage-ui/src/stores/display-models.ts b/packages/stage-ui/src/stores/display-models.ts index ec183141a..bf2ec71e6 100644 --- a/packages/stage-ui/src/stores/display-models.ts +++ b/packages/stage-ui/src/stores/display-models.ts @@ -39,8 +39,8 @@ export interface DisplayModelURL { } const displayModelsPresets: DisplayModel[] = [ - { id: 'preset-live2d-1', format: DisplayModelFormat.Live2dZip, type: 'url', url: '/assets/live2d/models/hiyori_pro_zh.zip', name: 'Hiyori (Pro)', previewImage: '/assets/live2d/models/hiyori_free_zh/avatar.png', importedAt: 1733113886840 }, - { id: 'preset-live2d-2', format: DisplayModelFormat.Live2dZip, type: 'url', url: '/assets/live2d/models/hiyori_free_zh.zip', name: 'Hiyori (Free)', previewImage: '/assets/live2d/models/hiyori_free_zh/avatar.png', importedAt: 1733113886840 }, + { id: 'preset-live2d-1', format: DisplayModelFormat.Live2dZip, type: 'url', url: '/assets/live2d/models/hiyori_pro_zh.zip', name: 'Hiyori (Pro)', previewImage: '/assets/live2d/models/hiyori_pro_zh/avatar.png', importedAt: 1733113886840 }, + { id: 'preset-live2d-2', format: DisplayModelFormat.Live2dZip, type: 'url', url: '/assets/live2d/models/hiyori_free_zh.zip', name: 'Hiyori (Free)', previewImage: '/assets/live2d/models/hiyori_pro_zh/avatar.png', importedAt: 1733113886840 }, ] export const useDisplayModelsStore = defineStore('display-models', () => { diff --git a/packages/stage-ui/src/stores/settings.ts b/packages/stage-ui/src/stores/settings.ts index 277062643..ca941d26c 100644 --- a/packages/stage-ui/src/stores/settings.ts +++ b/packages/stage-ui/src/stores/settings.ts @@ -35,7 +35,7 @@ export const useSettings = defineStore('settings', () => { const language = useLocalStorage('settings/language', '') - const stageModelSelected = useLocalStorage('settings/stage/model', undefined) + const stageModelSelected = useLocalStorage('settings/stage/model', 'preset-live2d-1') const stageModelSelectedDisplayModel = ref() const stageModelSelectedUrl = ref() const stageModelRenderer = ref<'live2d' | 'vrm' | 'disabled'>() @@ -56,17 +56,6 @@ export const useSettings = defineStore('settings', () => { return } - if (model.type === 'file') { - if (stageModelSelectedUrl.value) { - URL.revokeObjectURL(stageModelSelectedUrl.value) - } - - stageModelSelectedUrl.value = URL.createObjectURL(model.file) - } - else { - stageModelSelectedUrl.value = model.url - } - switch (model.format) { case DisplayModelFormat.Live2dZip: stageModelRenderer.value = 'live2d' @@ -79,6 +68,17 @@ export const useSettings = defineStore('settings', () => { break } + if (model.type === 'file') { + if (stageModelSelectedUrl.value) { + URL.revokeObjectURL(stageModelSelectedUrl.value) + } + + stageModelSelectedUrl.value = URL.createObjectURL(model.file) + } + else { + stageModelSelectedUrl.value = model.url + } + stageModelSelectedDisplayModel.value = model }