doll active state <-> doll visibility toggle
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import {
|
||||
cursorPositionOnScreen,
|
||||
friendsCursorPositions,
|
||||
friendsActiveDolls,
|
||||
} from "../../events/cursor";
|
||||
import { appData } from "../../events/app-data";
|
||||
|
||||
@@ -14,6 +15,18 @@
|
||||
const friend = $appData?.friends?.find((f) => f.friend.id === userId);
|
||||
return friend ? friend.friend.name : userId.slice(0, 8) + "...";
|
||||
}
|
||||
|
||||
function getFriendDollConfig(userId: string) {
|
||||
// 1. Try to get from real-time store (most up-to-date)
|
||||
// Check if key exists to distinguish between "unknown" (undefined) and "no doll" (null)
|
||||
if (userId in $friendsActiveDolls) {
|
||||
return $friendsActiveDolls[userId]?.configuration;
|
||||
}
|
||||
|
||||
// 2. Fallback to initial app data (snapshot on load)
|
||||
const friend = $appData?.friends?.find((f) => f.friend.id === userId);
|
||||
return friend?.friend.activeDoll?.configuration;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerWidth bind:innerHeight />
|
||||
@@ -66,11 +79,16 @@
|
||||
<div class="absolute inset-0 size-full">
|
||||
{#if Object.keys($friendsCursorPositions).length > 0}
|
||||
{#each Object.entries($friendsCursorPositions) as [userId, position]}
|
||||
<DesktopPet
|
||||
targetX={position.mapped.x * innerWidth}
|
||||
targetY={position.mapped.y * innerHeight}
|
||||
name={getFriendName(userId)}
|
||||
/>
|
||||
{@const config = getFriendDollConfig(userId)}
|
||||
{#if config}
|
||||
<DesktopPet
|
||||
targetX={position.mapped.x * innerWidth}
|
||||
targetY={position.mapped.y * innerHeight}
|
||||
name={getFriendName(userId)}
|
||||
bodyColor={config?.colorScheme?.body}
|
||||
outlineColor={config?.colorScheme?.outline}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import onekoGif from "../../assets/oneko/oneko.gif";
|
||||
|
||||
export let targetX = 0;
|
||||
export let targetY = 0;
|
||||
export let name = "";
|
||||
export let bodyColor: string | undefined = undefined;
|
||||
export let outlineColor: string | undefined = undefined;
|
||||
|
||||
let nekoPosX = 32;
|
||||
let nekoPosY = 32;
|
||||
@@ -18,6 +21,35 @@
|
||||
let animationFrameId: number;
|
||||
let lastFrameTimestamp: number;
|
||||
|
||||
let spriteSheetUrl = onekoGif; // Default to standard GIF
|
||||
let isCustomSprite = false;
|
||||
|
||||
// Watch for color changes to regenerate sprite
|
||||
$: if (bodyColor && outlineColor) {
|
||||
updateSpriteSheet(bodyColor, outlineColor);
|
||||
} else {
|
||||
// Revert to default if colors are missing
|
||||
spriteSheetUrl = onekoGif;
|
||||
isCustomSprite = false;
|
||||
}
|
||||
|
||||
async function updateSpriteSheet(body: string, outline: string) {
|
||||
try {
|
||||
const result = await invoke<string>("recolor_gif_base64", {
|
||||
whiteColorHex: body,
|
||||
blackColorHex: outline,
|
||||
applyTexture: true,
|
||||
});
|
||||
spriteSheetUrl = `data:image/gif;base64,${result}`;
|
||||
isCustomSprite = true;
|
||||
} catch (e) {
|
||||
console.error("Failed to recolor sprite:", e);
|
||||
// Fallback
|
||||
spriteSheetUrl = onekoGif;
|
||||
isCustomSprite = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Sprite constants from oneko.js
|
||||
const spriteSets: Record<string, [number, number][]> = {
|
||||
idle: [[-3, -3]],
|
||||
@@ -231,7 +263,7 @@
|
||||
style="
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-image: url({onekoGif});
|
||||
background-image: url('{spriteSheetUrl}');
|
||||
background-position: {currentSprite.x}px {currentSprite.y}px;
|
||||
"
|
||||
></div>
|
||||
|
||||
Reference in New Issue
Block a user