From c3e39e7d9a91b2116ae5aeb0633f9859e50d599a Mon Sep 17 00:00:00 2001 From: Wind-Explorer Date: Sat, 7 Mar 2026 01:56:41 +0800 Subject: [PATCH] nuked svelte pets system, starting from scratch --- src/routes/scene/+page.svelte | 271 +----------------- src/routes/scene/components/DesktopPet.svelte | 204 ------------- .../scene/components/FullscreenModal.svelte | 66 ----- src/routes/scene/components/PetMenu.svelte | 124 -------- src/routes/scene/components/debug-bar.svelte | 102 +++++++ 5 files changed, 112 insertions(+), 655 deletions(-) delete mode 100644 src/routes/scene/components/DesktopPet.svelte delete mode 100644 src/routes/scene/components/FullscreenModal.svelte delete mode 100644 src/routes/scene/components/PetMenu.svelte create mode 100644 src/routes/scene/components/debug-bar.svelte diff --git a/src/routes/scene/+page.svelte b/src/routes/scene/+page.svelte index ea1e7be..a1bbe05 100644 --- a/src/routes/scene/+page.svelte +++ b/src/routes/scene/+page.svelte @@ -2,7 +2,6 @@ import { cursorPositionOnScreen, friendsCursorPositions, - friendsActiveDolls, } from "../../events/cursor"; import { appData } from "../../events/app-data"; import { sceneInteractive } from "../../events/scene-interactive"; @@ -11,168 +10,17 @@ type UserStatus, } from "../../events/user-status"; import { invoke } from "@tauri-apps/api/core"; - import DesktopPet from "./components/DesktopPet.svelte"; - import FullscreenModal from "./components/FullscreenModal.svelte"; - import { - receivedInteractions, - clearInteraction, - } from "$lib/stores/interaction-store"; - import { INTERACTION_TYPE_HEADPAT } from "$lib/constants/interaction"; import { listen } from "@tauri-apps/api/event"; import { AppEvents } from "../../types/bindings/AppEventsConstants"; - import { getSpriteSheetUrl } from "$lib/utils/sprite-utils"; import { onMount } from "svelte"; import type { PresenceStatus } from "../../types/bindings/PresenceStatus"; - import type { DollDto } from "../../types/bindings/DollDto"; + import DebugBar from "./components/debug-bar.svelte"; let innerWidth = $state(0); let innerHeight = $state(0); let isInteractive = $derived($sceneInteractive); - // Fullscreen modal state for headpats - let showFullscreenModal = $state(false); - let fullscreenImageSrc = $state(""); - let headpatSenderSpriteUrl = $state(""); - let headpatSenderId = $state(null); - let headpatTimer: ReturnType | null = null; - - // Queue for pending headpats (when modal is already showing) - let headpatQueue = $state>([]); - let headpatSpriteToken = 0; - - // Process next headpat in queue - function processNextHeadpat() { - if (headpatQueue.length > 0) { - const next = headpatQueue.shift()!; - clearInteraction(next.userId); - headpatSenderId = next.userId; - void loadHeadpatSprites(next.userId); - showFullscreenModal = true; - scheduleHeadpatDismiss(); - } else { - fullscreenImageSrc = ""; - headpatSenderSpriteUrl = ""; - headpatSenderId = null; - } - } - - async function loadHeadpatSprites(senderId: string) { - const token = ++headpatSpriteToken; - const senderDoll = getFriendDoll(senderId); - const userDoll = getUserDoll(); - - let userPetpetGif = ""; - if (userDoll) { - try { - const gifBase64 = await invoke("encode_pet_doll_gif_base64", { - doll: userDoll, - }); - userPetpetGif = `data:image/gif;base64,${gifBase64}`; - } catch (e) { - console.error("Failed to generate user petpet:", e); - } - } - - const senderSpriteUrl = senderDoll - ? await getSpriteSheetUrl({ - bodyColor: senderDoll.configuration.colorScheme.body, - outlineColor: senderDoll.configuration.colorScheme.outline, - }) - : await getSpriteSheetUrl(); - - if (token !== headpatSpriteToken) return; - fullscreenImageSrc = userPetpetGif; - headpatSenderSpriteUrl = senderSpriteUrl; - } - - function scheduleHeadpatDismiss() { - if (headpatTimer) { - clearTimeout(headpatTimer); - } - headpatTimer = setTimeout(() => { - showFullscreenModal = false; - headpatTimer = null; - }, 3000); - } - - function getHeadpatSenderName(userId: string | null): string { - if (!userId) return ""; - const friend = getFriendById(userId); - return friend?.name ?? ""; - } - - // Watch for headpat interactions and show fullscreen modal - $effect(() => { - for (const [userId, interaction] of $receivedInteractions) { - if (interaction.type === INTERACTION_TYPE_HEADPAT) { - if (showFullscreenModal) { - // Queue the headpat for later (deduplicate by replacing existing from same user) - const existingIndex = headpatQueue.findIndex( - (h) => h.userId === userId, - ); - if (existingIndex >= 0) { - headpatQueue[existingIndex] = { - userId, - content: interaction.content, - }; - } else { - headpatQueue.push({ userId, content: interaction.content }); - } - scheduleHeadpatDismiss(); - } else { - // Show immediately and clear from store - clearInteraction(userId); - headpatSenderId = userId; - void loadHeadpatSprites(userId); - showFullscreenModal = true; - scheduleHeadpatDismiss(); - } - } - } - }); - - // When modal closes, process next headpat in queue - $effect(() => { - if (!showFullscreenModal && headpatSenderId) { - headpatSenderId = null; - processNextHeadpat(); - } - }); - - $effect(() => { - return () => { - if (headpatTimer) { - clearTimeout(headpatTimer); - headpatTimer = null; - } - }; - }); - - function getFriendById(userId: string) { - const friend = $appData?.friends?.find((f) => f.friend?.id === userId); - return friend?.friend; - } - - function getFriendDoll(userId: string) { - if (userId in $friendsActiveDolls) { - return $friendsActiveDolls[userId]; - } - - const friend = $appData?.friends?.find((f) => f.friend?.id === userId); - return friend?.friend?.activeDoll; - } - - function getFriendStatus(userId: string) { - return $friendsUserStatuses[userId]; - } - - function getUserDoll(): DollDto | undefined { - const user = $appData?.user; - if (!user || !user.activeDollId) return undefined; - return $appData?.dolls?.find((d) => d.id === user.activeDollId); - } - let presenceStatus: PresenceStatus | null = $state(null); onMount(() => { @@ -203,114 +51,15 @@ }}> 
-
-
- - - Intercepting cursor events - -
- - - ({$cursorPositionOnScreen.mapped.x.toFixed(3)}, {$cursorPositionOnScreen.mapped.y.toFixed( - 3, - )}) - - - - {#if presenceStatus?.graphicsB64} - Active app icon - {/if} - {presenceStatus?.title} - - - {#if Object.keys($friendsCursorPositions).length > 0} -
-
- {#each Object.entries($friendsCursorPositions) as [userId, position]} - {@const status = getFriendStatus(userId)} -
- {getFriendById(userId)?.name} -
- - ({position.mapped.x.toFixed(3)}, {position.mapped.y.toFixed( - 3, - )}) - - {#if status} - - {status.state} in - {#if status.presenceStatus.graphicsB64} - Friend's active app icon - {/if} - {status.presenceStatus.title || - status.presenceStatus.subtitle} - - {/if} -
-
- {/each} -
-
- {/if} -
+
- -
- {#if Object.keys($friendsCursorPositions).length > 0} - {#each Object.entries($friendsCursorPositions) as [userId, position]} - {@const doll = getFriendDoll(userId)} - {@const friend = getFriendById(userId)} - {#if doll && friend} - - {/if} - {/each} - {/if} - {#if $appData?.user && getUserDoll()} - - {/if} -
- - diff --git a/src/routes/scene/components/DesktopPet.svelte b/src/routes/scene/components/DesktopPet.svelte deleted file mode 100644 index fd2aa09..0000000 --- a/src/routes/scene/components/DesktopPet.svelte +++ /dev/null @@ -1,204 +0,0 @@ - - -
- {#if isPetMenuOpen} - - {/if} - {#if userStatus} -
- {#if userStatus.presenceStatus.graphicsB64} - Friend's active app icon - {/if} -
- {/if} - - - - {doll?.name} - -
- - diff --git a/src/routes/scene/components/FullscreenModal.svelte b/src/routes/scene/components/FullscreenModal.svelte deleted file mode 100644 index 163c99a..0000000 --- a/src/routes/scene/components/FullscreenModal.svelte +++ /dev/null @@ -1,66 +0,0 @@ - - -{#if visible} -
- {#if senderName} -
{senderName} gave you a headpat!
- {/if} -
- {#if senderSpriteUrl} -
-
- -
-
- {/if} - Headpat -
-
-{/if} diff --git a/src/routes/scene/components/PetMenu.svelte b/src/routes/scene/components/PetMenu.svelte deleted file mode 100644 index 4928305..0000000 --- a/src/routes/scene/components/PetMenu.svelte +++ /dev/null @@ -1,124 +0,0 @@ - - -
-
-
-

{doll.name}

-

From {user.name}

-
- {#if userStatus} -
- {#if userStatus.presenceStatus.graphicsB64} - Friend's active app icon - {/if} -

- {userStatus.presenceStatus.title} -

-
- {/if} - - {#if receivedInteraction && receivedInteraction.type !== INTERACTION_TYPE_HEADPAT} -
-
- {receivedInteraction.content} -
-
- {:else if showMessageInput} -
- -
- - -
-
- {:else} -
- - -
-
- - -
- {/if} -
-
diff --git a/src/routes/scene/components/debug-bar.svelte b/src/routes/scene/components/debug-bar.svelte new file mode 100644 index 0000000..3726a9e --- /dev/null +++ b/src/routes/scene/components/debug-bar.svelte @@ -0,0 +1,102 @@ + + +
+
+
+ + + Interactive + +
+ + + {cursorPosition.mapped.x.toFixed(3)}, {cursorPosition.mapped.y.toFixed(3)} + + + {#if presenceStatus} + + {#if presenceStatus.graphicsB64} + Active app icon + {/if} + {presenceStatus.title} + + {/if} + + {#if Object.keys(friendsCursorPositions).length > 0} +
+
+ {#each Object.entries(friendsCursorPositions) as [userId, position]} + {@const status = getFriendStatus(userId)} +
+ {getFriendById(userId)?.name} +
+ + {position.mapped.x.toFixed(3)}, {position.mapped.y.toFixed(3)} + + {#if status} + + {status.state} in + {#if status.presenceStatus.graphicsB64} + Friend's active app icon + {/if} + {status.presenceStatus.title || + status.presenceStatus.subtitle} + + {/if} +
+
+ {/each} +
+
+ {/if} +
+