diff --git a/src/assets/animals/cat/zardaloo_idle_8fps.gif b/src/assets/animals/cat/zardaloo_idle_8fps.gif deleted file mode 100644 index 72a08438..00000000 Binary files a/src/assets/animals/cat/zardaloo_idle_8fps.gif and /dev/null differ diff --git a/src/assets/animals/cat/zardaloo_idle_8fps.webp b/src/assets/animals/cat/zardaloo_idle_8fps.webp new file mode 100644 index 00000000..e5657df7 Binary files /dev/null and b/src/assets/animals/cat/zardaloo_idle_8fps.webp differ diff --git a/src/assets/animals/cat/zardaloo_lie_8fps.gif b/src/assets/animals/cat/zardaloo_lie_8fps.gif deleted file mode 100644 index cca6536c..00000000 Binary files a/src/assets/animals/cat/zardaloo_lie_8fps.gif and /dev/null differ diff --git a/src/assets/animals/cat/zardaloo_lie_8fps.webp b/src/assets/animals/cat/zardaloo_lie_8fps.webp new file mode 100644 index 00000000..e7070049 Binary files /dev/null and b/src/assets/animals/cat/zardaloo_lie_8fps.webp differ diff --git a/src/assets/animals/cat/zardaloo_run_8fps.gif b/src/assets/animals/cat/zardaloo_run_8fps.gif deleted file mode 100644 index b1ec32f0..00000000 Binary files a/src/assets/animals/cat/zardaloo_run_8fps.gif and /dev/null differ diff --git a/src/assets/animals/cat/zardaloo_run_8fps.webp b/src/assets/animals/cat/zardaloo_run_8fps.webp new file mode 100644 index 00000000..1f652a42 Binary files /dev/null and b/src/assets/animals/cat/zardaloo_run_8fps.webp differ diff --git a/src/assets/animals/cat/zardaloo_swipe_8fps.gif b/src/assets/animals/cat/zardaloo_swipe_8fps.gif deleted file mode 100644 index 864d453d..00000000 Binary files a/src/assets/animals/cat/zardaloo_swipe_8fps.gif and /dev/null differ diff --git a/src/assets/animals/cat/zardaloo_swipe_8fps.webp b/src/assets/animals/cat/zardaloo_swipe_8fps.webp new file mode 100644 index 00000000..0080863c Binary files /dev/null and b/src/assets/animals/cat/zardaloo_swipe_8fps.webp differ diff --git a/src/assets/animals/cat/zardaloo_walk_fast_8fps.gif b/src/assets/animals/cat/zardaloo_walk_fast_8fps.gif deleted file mode 100644 index b1ce5a39..00000000 Binary files a/src/assets/animals/cat/zardaloo_walk_fast_8fps.gif and /dev/null differ diff --git a/src/assets/animals/cat/zardaloo_walk_fast_8fps.webp b/src/assets/animals/cat/zardaloo_walk_fast_8fps.webp new file mode 100644 index 00000000..f87d1811 Binary files /dev/null and b/src/assets/animals/cat/zardaloo_walk_fast_8fps.webp differ diff --git a/src/assets/animals/chicken/white_idle_8fps.gif b/src/assets/animals/chicken/white_idle_8fps.gif deleted file mode 100644 index 3cdfc7ad..00000000 Binary files a/src/assets/animals/chicken/white_idle_8fps.gif and /dev/null differ diff --git a/src/assets/animals/chicken/white_idle_8fps.webp b/src/assets/animals/chicken/white_idle_8fps.webp new file mode 100644 index 00000000..e4be7dec Binary files /dev/null and b/src/assets/animals/chicken/white_idle_8fps.webp differ diff --git a/src/assets/animals/chicken/white_run_8fps.gif b/src/assets/animals/chicken/white_run_8fps.gif deleted file mode 100644 index c5250ec4..00000000 Binary files a/src/assets/animals/chicken/white_run_8fps.gif and /dev/null differ diff --git a/src/assets/animals/chicken/white_run_8fps.webp b/src/assets/animals/chicken/white_run_8fps.webp new file mode 100644 index 00000000..ef463569 Binary files /dev/null and b/src/assets/animals/chicken/white_run_8fps.webp differ diff --git a/src/assets/animals/chicken/white_swipe_8fps.gif b/src/assets/animals/chicken/white_swipe_8fps.gif deleted file mode 100644 index 19b65a3c..00000000 Binary files a/src/assets/animals/chicken/white_swipe_8fps.gif and /dev/null differ diff --git a/src/assets/animals/chicken/white_swipe_8fps.webp b/src/assets/animals/chicken/white_swipe_8fps.webp new file mode 100644 index 00000000..67978256 Binary files /dev/null and b/src/assets/animals/chicken/white_swipe_8fps.webp differ diff --git a/src/assets/animals/chicken/white_walk_8fps.gif b/src/assets/animals/chicken/white_walk_8fps.gif deleted file mode 100644 index 7c0b6fc9..00000000 Binary files a/src/assets/animals/chicken/white_walk_8fps.gif and /dev/null differ diff --git a/src/assets/animals/chicken/white_walk_8fps.webp b/src/assets/animals/chicken/white_walk_8fps.webp new file mode 100644 index 00000000..301af3a4 Binary files /dev/null and b/src/assets/animals/chicken/white_walk_8fps.webp differ diff --git a/src/assets/animals/chicken/white_walk_fast_8fps.gif b/src/assets/animals/chicken/white_walk_fast_8fps.gif deleted file mode 100644 index c5250ec4..00000000 Binary files a/src/assets/animals/chicken/white_walk_fast_8fps.gif and /dev/null differ diff --git a/src/assets/animals/chicken/white_walk_fast_8fps.webp b/src/assets/animals/chicken/white_walk_fast_8fps.webp new file mode 100644 index 00000000..ef463569 Binary files /dev/null and b/src/assets/animals/chicken/white_walk_fast_8fps.webp differ diff --git a/src/assets/animals/crab/red_idle_8fps.gif b/src/assets/animals/crab/red_idle_8fps.gif deleted file mode 100644 index 28f26797..00000000 Binary files a/src/assets/animals/crab/red_idle_8fps.gif and /dev/null differ diff --git a/src/assets/animals/crab/red_idle_8fps.webp b/src/assets/animals/crab/red_idle_8fps.webp new file mode 100644 index 00000000..08b6b8df Binary files /dev/null and b/src/assets/animals/crab/red_idle_8fps.webp differ diff --git a/src/assets/animals/crab/red_run_8fps.gif b/src/assets/animals/crab/red_run_8fps.gif deleted file mode 100644 index 07891d20..00000000 Binary files a/src/assets/animals/crab/red_run_8fps.gif and /dev/null differ diff --git a/src/assets/animals/crab/red_run_8fps.webp b/src/assets/animals/crab/red_run_8fps.webp new file mode 100644 index 00000000..f2017c51 Binary files /dev/null and b/src/assets/animals/crab/red_run_8fps.webp differ diff --git a/src/assets/animals/crab/red_swipe_8fps.gif b/src/assets/animals/crab/red_swipe_8fps.gif deleted file mode 100644 index 34dcdcb6..00000000 Binary files a/src/assets/animals/crab/red_swipe_8fps.gif and /dev/null differ diff --git a/src/assets/animals/crab/red_swipe_8fps.webp b/src/assets/animals/crab/red_swipe_8fps.webp new file mode 100644 index 00000000..c04487e6 Binary files /dev/null and b/src/assets/animals/crab/red_swipe_8fps.webp differ diff --git a/src/assets/animals/crab/red_walk_8fps.gif b/src/assets/animals/crab/red_walk_8fps.gif deleted file mode 100644 index afe47f1b..00000000 Binary files a/src/assets/animals/crab/red_walk_8fps.gif and /dev/null differ diff --git a/src/assets/animals/crab/red_walk_8fps.webp b/src/assets/animals/crab/red_walk_8fps.webp new file mode 100644 index 00000000..4e6af9f9 Binary files /dev/null and b/src/assets/animals/crab/red_walk_8fps.webp differ diff --git a/src/assets/animals/crab/red_walk_fast_8fps.gif b/src/assets/animals/crab/red_walk_fast_8fps.gif deleted file mode 100644 index 07891d20..00000000 Binary files a/src/assets/animals/crab/red_walk_fast_8fps.gif and /dev/null differ diff --git a/src/assets/animals/crab/red_walk_fast_8fps.webp b/src/assets/animals/crab/red_walk_fast_8fps.webp new file mode 100644 index 00000000..f2017c51 Binary files /dev/null and b/src/assets/animals/crab/red_walk_fast_8fps.webp differ diff --git a/src/assets/animals/dog/akita_idle_8fps.gif b/src/assets/animals/dog/akita_idle_8fps.gif deleted file mode 100644 index d8154e3b..00000000 Binary files a/src/assets/animals/dog/akita_idle_8fps.gif and /dev/null differ diff --git a/src/assets/animals/dog/akita_idle_8fps.webp b/src/assets/animals/dog/akita_idle_8fps.webp new file mode 100644 index 00000000..0a5f84e6 Binary files /dev/null and b/src/assets/animals/dog/akita_idle_8fps.webp differ diff --git a/src/assets/animals/dog/akita_lie_8fps.gif b/src/assets/animals/dog/akita_lie_8fps.gif deleted file mode 100644 index 33a23104..00000000 Binary files a/src/assets/animals/dog/akita_lie_8fps.gif and /dev/null differ diff --git a/src/assets/animals/dog/akita_lie_8fps.webp b/src/assets/animals/dog/akita_lie_8fps.webp new file mode 100644 index 00000000..0675cd0f Binary files /dev/null and b/src/assets/animals/dog/akita_lie_8fps.webp differ diff --git a/src/assets/animals/dog/akita_run_8fps.gif b/src/assets/animals/dog/akita_run_8fps.gif deleted file mode 100644 index 18d0e17d..00000000 Binary files a/src/assets/animals/dog/akita_run_8fps.gif and /dev/null differ diff --git a/src/assets/animals/dog/akita_run_8fps.webp b/src/assets/animals/dog/akita_run_8fps.webp new file mode 100644 index 00000000..59f7de22 Binary files /dev/null and b/src/assets/animals/dog/akita_run_8fps.webp differ diff --git a/src/assets/animals/dog/akita_swipe_8fps.gif b/src/assets/animals/dog/akita_swipe_8fps.gif deleted file mode 100644 index c21df770..00000000 Binary files a/src/assets/animals/dog/akita_swipe_8fps.gif and /dev/null differ diff --git a/src/assets/animals/dog/akita_swipe_8fps.webp b/src/assets/animals/dog/akita_swipe_8fps.webp new file mode 100644 index 00000000..de197d3f Binary files /dev/null and b/src/assets/animals/dog/akita_swipe_8fps.webp differ diff --git a/src/assets/animals/dog/akita_walk_fast_8fps.gif b/src/assets/animals/dog/akita_walk_fast_8fps.gif deleted file mode 100644 index 60541011..00000000 Binary files a/src/assets/animals/dog/akita_walk_fast_8fps.gif and /dev/null differ diff --git a/src/assets/animals/dog/akita_walk_fast_8fps.webp b/src/assets/animals/dog/akita_walk_fast_8fps.webp new file mode 100644 index 00000000..b3859e8c Binary files /dev/null and b/src/assets/animals/dog/akita_walk_fast_8fps.webp differ diff --git a/src/assets/animals/dog/akita_with_ball_8fps.gif b/src/assets/animals/dog/akita_with_ball_8fps.gif deleted file mode 100644 index 8a995c2a..00000000 Binary files a/src/assets/animals/dog/akita_with_ball_8fps.gif and /dev/null differ diff --git a/src/assets/animals/dog/akita_with_ball_8fps.webp b/src/assets/animals/dog/akita_with_ball_8fps.webp new file mode 100644 index 00000000..7ffa9e4c Binary files /dev/null and b/src/assets/animals/dog/akita_with_ball_8fps.webp differ diff --git a/src/assets/animals/frog/ghoori_idle_8fps.gif b/src/assets/animals/frog/ghoori_idle_8fps.gif deleted file mode 100644 index 0a0bc543..00000000 Binary files a/src/assets/animals/frog/ghoori_idle_8fps.gif and /dev/null differ diff --git a/src/assets/animals/frog/ghoori_idle_8fps.webp b/src/assets/animals/frog/ghoori_idle_8fps.webp new file mode 100644 index 00000000..ba57850b Binary files /dev/null and b/src/assets/animals/frog/ghoori_idle_8fps.webp differ diff --git a/src/assets/animals/frog/ghoori_lie_8fps.gif b/src/assets/animals/frog/ghoori_lie_8fps.gif deleted file mode 100644 index c1f8fc36..00000000 Binary files a/src/assets/animals/frog/ghoori_lie_8fps.gif and /dev/null differ diff --git a/src/assets/animals/frog/ghoori_lie_8fps.webp b/src/assets/animals/frog/ghoori_lie_8fps.webp new file mode 100644 index 00000000..bf8a070c Binary files /dev/null and b/src/assets/animals/frog/ghoori_lie_8fps.webp differ diff --git a/src/assets/animals/frog/ghoori_run_8fps.gif b/src/assets/animals/frog/ghoori_run_8fps.gif deleted file mode 100644 index 31213997..00000000 Binary files a/src/assets/animals/frog/ghoori_run_8fps.gif and /dev/null differ diff --git a/src/assets/animals/frog/ghoori_run_8fps.webp b/src/assets/animals/frog/ghoori_run_8fps.webp new file mode 100644 index 00000000..2cc6dac9 Binary files /dev/null and b/src/assets/animals/frog/ghoori_run_8fps.webp differ diff --git a/src/assets/animals/frog/ghoori_swipe_8fps.gif b/src/assets/animals/frog/ghoori_swipe_8fps.gif deleted file mode 100644 index add44f50..00000000 Binary files a/src/assets/animals/frog/ghoori_swipe_8fps.gif and /dev/null differ diff --git a/src/assets/animals/frog/ghoori_swipe_8fps.webp b/src/assets/animals/frog/ghoori_swipe_8fps.webp new file mode 100644 index 00000000..e67c905a Binary files /dev/null and b/src/assets/animals/frog/ghoori_swipe_8fps.webp differ diff --git a/src/assets/animals/frog/ghoori_walk_8fps.gif b/src/assets/animals/frog/ghoori_walk_8fps.gif deleted file mode 100644 index 4001c09c..00000000 Binary files a/src/assets/animals/frog/ghoori_walk_8fps.gif and /dev/null differ diff --git a/src/assets/animals/frog/ghoori_walk_8fps.webp b/src/assets/animals/frog/ghoori_walk_8fps.webp new file mode 100644 index 00000000..2aff24f7 Binary files /dev/null and b/src/assets/animals/frog/ghoori_walk_8fps.webp differ diff --git a/src/assets/animals/frog/ghoori_walk_fast_8fps.gif b/src/assets/animals/frog/ghoori_walk_fast_8fps.gif deleted file mode 100644 index 6c6fd37c..00000000 Binary files a/src/assets/animals/frog/ghoori_walk_fast_8fps.gif and /dev/null differ diff --git a/src/assets/animals/frog/ghoori_walk_fast_8fps.webp b/src/assets/animals/frog/ghoori_walk_fast_8fps.webp new file mode 100644 index 00000000..44caf646 Binary files /dev/null and b/src/assets/animals/frog/ghoori_walk_fast_8fps.webp differ diff --git a/src/assets/emotions.png b/src/assets/emotions.png deleted file mode 100644 index c4df9223..00000000 Binary files a/src/assets/emotions.png and /dev/null differ diff --git a/src/assets/fonts/samim/Samim-FD.woff b/src/assets/fonts/samim/Samim-FD.woff deleted file mode 100644 index 758cf522..00000000 Binary files a/src/assets/fonts/samim/Samim-FD.woff and /dev/null differ diff --git a/src/assets/fonts/samim/Samim-FD.woff2 b/src/assets/fonts/samim/Samim-FD.woff2 new file mode 100644 index 00000000..fab766cb Binary files /dev/null and b/src/assets/fonts/samim/Samim-FD.woff2 differ diff --git a/src/assets/fonts/samim/Samim-Medium-FD.woff b/src/assets/fonts/samim/Samim-Medium-FD.woff deleted file mode 100644 index c2b27d7e..00000000 Binary files a/src/assets/fonts/samim/Samim-Medium-FD.woff and /dev/null differ diff --git a/src/assets/fonts/samim/Samim-Medium-FD.woff2 b/src/assets/fonts/samim/Samim-Medium-FD.woff2 new file mode 100644 index 00000000..c56384d8 Binary files /dev/null and b/src/assets/fonts/samim/Samim-Medium-FD.woff2 differ diff --git a/src/assets/google-meet.png b/src/assets/google-meet.png deleted file mode 100644 index faa8fc31..00000000 Binary files a/src/assets/google-meet.png and /dev/null differ diff --git a/src/assets/google-calendar.png b/src/assets/images/google-calendar.png similarity index 100% rename from src/assets/google-calendar.png rename to src/assets/images/google-calendar.png diff --git a/src/assets/keep-it.png b/src/assets/images/keep-it.png similarity index 100% rename from src/assets/keep-it.png rename to src/assets/images/keep-it.png diff --git a/src/assets/images/no-internet.png b/src/assets/images/no-internet.png deleted file mode 100644 index d8c8cffd..00000000 Binary files a/src/assets/images/no-internet.png and /dev/null differ diff --git a/src/components/extension-installed-modal.tsx b/src/components/extension-installed-modal.tsx index ed88d506..cd89e9e6 100644 --- a/src/components/extension-installed-modal.tsx +++ b/src/components/extension-installed-modal.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import keepItImage from '@/assets/keep-it.png' +import keepItImage from '@/assets/images/keep-it.png' import { Button } from './button/button' import Checkbox from './checkbox' import Modal from './modal' diff --git a/src/fonts.css b/src/fonts.css index d3298283..62cbcb00 100644 --- a/src/fonts.css +++ b/src/fonts.css @@ -65,14 +65,14 @@ /* Samim Font Family */ @font-face { font-family: "Samim"; - src: url("./assets/fonts/samim/Samim-FD.woff") format("woff"); + src: url("./assets/fonts/samim/Samim-FD.woff2") format("woff2"); font-weight: 400; font-style: normal; } @font-face { font-family: "Samim"; - src: url("./assets/fonts/samim/Samim-Medium-FD.woff") format("woff"); + src: url("./assets/fonts/samim/Samim-Medium-FD.woff2") format("woff2"); font-weight: 500; font-style: normal; } diff --git a/src/layouts/setting/tabs/account/tabs/user-profile/connections/components/platform-data.tsx b/src/layouts/setting/tabs/account/tabs/user-profile/connections/components/platform-data.tsx index 6f10c2f6..752c9a61 100644 --- a/src/layouts/setting/tabs/account/tabs/user-profile/connections/components/platform-data.tsx +++ b/src/layouts/setting/tabs/account/tabs/user-profile/connections/components/platform-data.tsx @@ -1,5 +1,5 @@ import type { Platform } from './platform-config' -import GoogleCalendar from '@/assets/google-calendar.png' +import GoogleCalendar from '@/assets/images/google-calendar.png' export const PLATFORM_CONFIGS: Omit[] = [ { diff --git a/src/layouts/widgetify-card/pets/core/base-pet.tsx b/src/layouts/widgetify-card/pets/core/base-pet.tsx index 292f3dd4..55fa43b7 100644 --- a/src/layouts/widgetify-card/pets/core/base-pet.tsx +++ b/src/layouts/widgetify-card/pets/core/base-pet.tsx @@ -11,6 +11,13 @@ import { } from './pet-types' import { UI, useAppearanceSetting } from '@/context/appearance.context' +/** How fast a pet still airborne (e.g. mid-climb) settles back to the ground. */ +const FALL_SPEED = 1.5 + +function randomDuration({ min, max }: { min: number; max: number }): number { + return Math.floor(Math.random() * (max - min) + min) +} + export interface BasePetProps { name: string animations: PetAnimations @@ -157,6 +164,9 @@ export function useBasePetLogic({ const [action, setAction] = useState('idle') const [actionTimer, setActionTimer] = useState(0) const [behaviorState, setBehaviorState] = useState(PetBehavior.RESTING) + // Whether a climb is heading back down. Keeps the pet in the CLIMBING behavior + // for the whole up-and-down trip so it never idles mid-air — see climbWall. + const [isDescending, setIsDescending] = useState(false) const [targetX, setTargetX] = useState(null) const [isMovingToTarget, setIsMovingToTarget] = useState(false) const [showName, setShowName] = useState(false) @@ -166,11 +176,17 @@ export function useBasePetLogic({ const getMovementBounds = useCallback(() => { const container = containerRef.current + const visibleHeight = container?.offsetHeight ?? dimensions.maxHeight + return { minX: 10, maxX: (container?.offsetWidth || 300) - dimensions.size - 10, minY: 0, - maxY: dimensions.maxHeight, + // The container clips overflow (see BasePetContainer's h-16/h-8), which is + // shorter than several pets' configured maxHeight (80-100px). Climbing past + // it pushed pets above the visible area, so they'd reappear "floating" back + // down into frame — clamp to whichever is actually smaller. + maxY: Math.max(0, Math.min(dimensions.maxHeight, visibleHeight - dimensions.size)), } }, [dimensions.size, dimensions.maxHeight]) @@ -226,15 +242,22 @@ export function useBasePetLogic({ setCollectibles((prev) => [...prev, newCollectible]) setCollectibleIdCounter((prev) => prev + 1) - if (action === 'sit' || action === 'idle') { - updateAction('stand') - setTimeout(() => { + // Only force an immediate chase reaction while grounded. If the pet is + // mid-climb, forcing 'run' here would move it horizontally while still + // airborne (the same "flying" bug climbWall guards against) — let it + // land first; updateBehavior picks up the waiting collectible on its own + // the moment position.y reaches 0. + if (position.y === 0) { + if (action === 'sit' || action === 'idle') { + updateAction('stand') + setTimeout(() => { + updateAction('run') + updateBehaviorState(PetBehavior.CHASING) + }, 300) + } else { updateAction('run') updateBehaviorState(PetBehavior.CHASING) - }, 300) - } else { - updateAction('run') - updateBehaviorState(PetBehavior.CHASING) + } } } }, @@ -242,6 +265,7 @@ export function useBasePetLogic({ collectibleIdCounter, assets.collectibleSize, action, + position.y, getMovementBounds, updateAction, updateBehaviorState, @@ -347,64 +371,40 @@ export function useBasePetLogic({ }, [collectibles]) const roamOrRest = useCallback(() => { + // Always land before switching to anything else — never leave the pet + // paused mid-climb. climbWall handles the actual descent and transitions + // to RESTING itself once position.y reaches 0. + if (behaviorState === PetBehavior.CLIMBING) { + setIsDescending(true) + return + } + if (isHungry) { updateBehaviorState(PetBehavior.RESTING) updateAction('sit') - setActionTimer( - Math.floor( - Math.random() * (durations.rest.max - durations.rest.min) + - durations.rest.min - ) - ) - + setActionTimer(randomDuration(durations.rest)) return } + const random = Math.random() if (behaviorState === PetBehavior.ROAMING) { if (isNearWall() && random > 0.7 && animations.climb) { + setIsDescending(false) updateBehaviorState(PetBehavior.CLIMBING) updateAction('climb') - setActionTimer( - Math.floor( - Math.random() * (durations.climb.max - durations.climb.min) + - durations.climb.min - ) - ) + setActionTimer(randomDuration(durations.climb)) } else { updateBehaviorState(PetBehavior.RESTING) const shouldSit = Math.random() > 0.5 && animations.sit updateAction(shouldSit ? 'sit' : 'idle') - setActionTimer( - Math.floor( - Math.random() * (durations.rest.max - durations.rest.min) + - durations.rest.min - ) - ) + setActionTimer(randomDuration(durations.rest)) } - } else if (behaviorState === PetBehavior.CLIMBING) { - updateBehaviorState(PetBehavior.RESTING) - updateAction(animations.stand ? 'stand' : 'idle') - setActionTimer( - Math.floor( - Math.random() * (durations.rest.max - durations.rest.min) + - durations.rest.min - ) - ) } else { // Includes PetBehavior.RESTING or initial state updateBehaviorState(PetBehavior.ROAMING) const shouldRun = Math.random() > 0.6 updateAction(shouldRun ? 'run' : 'walk') - setActionTimer( - Math.floor( - Math.random() * - (shouldRun - ? durations.run.max - durations.run.min + durations.run.min - : durations.walk.max - - durations.walk.min + - durations.walk.min) - ) - ) + setActionTimer(randomDuration(shouldRun ? durations.run : durations.walk)) } if (onLevelDownHungryState) { @@ -412,10 +412,10 @@ export function useBasePetLogic({ } }, [ behaviorState, + isHungry, isNearWall, animations.climb, animations.sit, - animations.stand, durations, updateAction, updateBehaviorState, @@ -424,7 +424,11 @@ export function useBasePetLogic({ const updateBehavior = useCallback(() => { const nearestCollectible = findNearestCollectible(collectibles) - if (nearestCollectible) { + // Only chase while grounded. Reacting to a collectible mid-climb used to + // switch straight to 'run' and move horizontally while the pet was still + // airborne — i.e. it would fly toward the treat. Once landed, this same + // check runs again next tick and starts the chase normally. + if (nearestCollectible && position.y === 0) { if (behaviorState !== PetBehavior.CHASING) { updateBehaviorState(PetBehavior.CHASING) updateAction('run') @@ -455,6 +459,7 @@ export function useBasePetLogic({ behaviorState, isMovingToTarget, actionTimer, + position.y, updateAction, updateBehaviorState, roamOrRest, @@ -476,7 +481,10 @@ export function useBasePetLogic({ if (newDirection !== currentDirection) { setDirection(newDirection) } - const newY = currentPosition.y > 0 ? Math.max(0, currentPosition.y - 0.5) : 0 + const newY = + currentPosition.y > 0 + ? Math.max(0, currentPosition.y - FALL_SPEED) + : 0 return { x: newX, y: newY } }, [getMovementBounds, getCurrentSpeed] @@ -538,22 +546,42 @@ export function useBasePetLogic({ const climbWall = useCallback( (currentPosition: Position, currentDirection: number) => { const bounds = getMovementBounds() - let newY = currentPosition.y + dimensions.climbSpeed - if (newY >= bounds.maxY) { - newY = bounds.maxY - // Optionally, transition to another state once max height is reached - // updateBehaviorState(PetBehavior.RESTING); - // updateAction('idle'); - } const wallX = currentDirection === 1 ? bounds.maxX : bounds.minX + + if (isDescending) { + const newY = currentPosition.y - dimensions.climbSpeed + if (newY <= 0) { + // Landed. Hand off to the normal rest cycle here, at y=0, instead of + // switching to an idle/stand pose earlier and leaving gravity to + // trickle the position down separately — that gap is what made pets + // (most visibly the dog) look like they were floating back to earth. + setIsDescending(false) + updateBehaviorState(PetBehavior.RESTING) + updateAction(animations.stand ? 'stand' : 'idle') + setActionTimer(randomDuration(durations.rest)) + return { x: wallX, y: 0 } + } + return { x: wallX, y: newY } + } + + const newY = Math.min(currentPosition.y + dimensions.climbSpeed, bounds.maxY) return { x: wallX, y: newY } }, - [dimensions.climbSpeed, dimensions.maxHeight, getMovementBounds] + [ + isDescending, + dimensions.climbSpeed, + durations.rest, + animations.stand, + getMovementBounds, + updateBehaviorState, + updateAction, + ] ) + /** Safety net for a pet ever left with y > 0 outside an active climb. */ const applyGravity = useCallback((currentPosition: Position) => { if (currentPosition.y > 0) { - return { ...currentPosition, y: Math.max(0, currentPosition.y - 1.5) } + return { ...currentPosition, y: Math.max(0, currentPosition.y - FALL_SPEED) } } return currentPosition }, []) @@ -594,10 +622,30 @@ export function useBasePetLogic({ applyGravity, ]) + // physicsUpdate gets a new identity on almost every tick (it transitively + // depends on position/behaviorState via updateBehavior/movePet/etc.), so an + // effect keyed on it would tear down and recreate the timer ~60 times a + // second. Keeping the latest version in a ref lets the loop itself mount + // once. requestAnimationFrame also pauses automatically while the tab is + // backgrounded, unlike setInterval. + const physicsUpdateRef = useRef(physicsUpdate) + physicsUpdateRef.current = physicsUpdate + useEffect(() => { - const animationLoop = setInterval(physicsUpdate, 16) // Approx 60 FPS - return () => clearInterval(animationLoop) - }, [physicsUpdate]) + let frameId: number + let lastTick = performance.now() + + const loop = (now: number) => { + if (now - lastTick >= 16) { + lastTick = now + physicsUpdateRef.current() + } + frameId = requestAnimationFrame(loop) + } + + frameId = requestAnimationFrame(loop) + return () => cancelAnimationFrame(frameId) + }, []) useEffect(() => { const container = containerRef.current diff --git a/src/layouts/widgetify-card/pets/pet-item/pet-cat.tsx b/src/layouts/widgetify-card/pets/pet-item/pet-cat.tsx index 7c94cf24..67aa26ab 100644 --- a/src/layouts/widgetify-card/pets/pet-item/pet-cat.tsx +++ b/src/layouts/widgetify-card/pets/pet-item/pet-cat.tsx @@ -1,9 +1,9 @@ import catFood from '@/assets/animals/cat/cat-food.png' -import idle from '@/assets/animals/cat/zardaloo_idle_8fps.gif' -import lie from '@/assets/animals/cat/zardaloo_lie_8fps.gif' -import running from '@/assets/animals/cat/zardaloo_run_8fps.gif' -import swipe from '@/assets/animals/cat/zardaloo_swipe_8fps.gif' -import walking from '@/assets/animals/cat/zardaloo_walk_fast_8fps.gif' +import idle from '@/assets/animals/cat/zardaloo_idle_8fps.webp' +import lie from '@/assets/animals/cat/zardaloo_lie_8fps.webp' +import running from '@/assets/animals/cat/zardaloo_run_8fps.webp' +import swipe from '@/assets/animals/cat/zardaloo_swipe_8fps.webp' +import walking from '@/assets/animals/cat/zardaloo_walk_fast_8fps.webp' import { BasePetContainer, useBasePetLogic } from '../core/base-pet' import { PetFood } from '../core/pet-food' diff --git a/src/layouts/widgetify-card/pets/pet-item/pet-chicken.tsx b/src/layouts/widgetify-card/pets/pet-item/pet-chicken.tsx index db3697f3..273b5cb7 100644 --- a/src/layouts/widgetify-card/pets/pet-item/pet-chicken.tsx +++ b/src/layouts/widgetify-card/pets/pet-item/pet-chicken.tsx @@ -1,8 +1,8 @@ import chickenFood from '@/assets/animals/chicken/chicken-food.png' -import idle from '@/assets/animals/chicken/white_idle_8fps.gif' -import running from '@/assets/animals/chicken/white_run_8fps.gif' -import swipe from '@/assets/animals/chicken/white_swipe_8fps.gif' -import walking from '@/assets/animals/chicken/white_walk_fast_8fps.gif' +import idle from '@/assets/animals/chicken/white_idle_8fps.webp' +import running from '@/assets/animals/chicken/white_run_8fps.webp' +import swipe from '@/assets/animals/chicken/white_swipe_8fps.webp' +import walking from '@/assets/animals/chicken/white_walk_fast_8fps.webp' import { BasePetContainer, useBasePetLogic } from '../core/base-pet' import { PetFood } from '../core/pet-food' import { diff --git a/src/layouts/widgetify-card/pets/pet-item/pet-crab.tsx b/src/layouts/widgetify-card/pets/pet-item/pet-crab.tsx index f491782c..82f3ea35 100644 --- a/src/layouts/widgetify-card/pets/pet-item/pet-crab.tsx +++ b/src/layouts/widgetify-card/pets/pet-item/pet-crab.tsx @@ -1,8 +1,8 @@ import crabFood from '@/assets/animals/crab/crab-food.png' -import idle from '@/assets/animals/crab/red_idle_8fps.gif' -import running from '@/assets/animals/crab/red_run_8fps.gif' -import swipe from '@/assets/animals/crab/red_swipe_8fps.gif' -import walking from '@/assets/animals/crab/red_walk_fast_8fps.gif' +import idle from '@/assets/animals/crab/red_idle_8fps.webp' +import running from '@/assets/animals/crab/red_run_8fps.webp' +import swipe from '@/assets/animals/crab/red_swipe_8fps.webp' +import walking from '@/assets/animals/crab/red_walk_fast_8fps.webp' import { BasePetContainer, useBasePetLogic } from '../core/base-pet' import { PetFood } from '../core/pet-food' diff --git a/src/layouts/widgetify-card/pets/pet-item/pet-dog.tsx b/src/layouts/widgetify-card/pets/pet-item/pet-dog.tsx index de88c05f..1de9ca1c 100644 --- a/src/layouts/widgetify-card/pets/pet-item/pet-dog.tsx +++ b/src/layouts/widgetify-card/pets/pet-item/pet-dog.tsx @@ -1,8 +1,8 @@ -import idle from '@/assets/animals/dog/akita_idle_8fps.gif' -import lie from '@/assets/animals/dog/akita_lie_8fps.gif' -import running from '@/assets/animals/dog/akita_run_8fps.gif' -import swipe from '@/assets/animals/dog/akita_swipe_8fps.gif' -import walking from '@/assets/animals/dog/akita_walk_fast_8fps.gif' +import idle from '@/assets/animals/dog/akita_idle_8fps.webp' +import lie from '@/assets/animals/dog/akita_lie_8fps.webp' +import running from '@/assets/animals/dog/akita_run_8fps.webp' +import swipe from '@/assets/animals/dog/akita_swipe_8fps.webp' +import walking from '@/assets/animals/dog/akita_walk_fast_8fps.webp' import dogFood from '@/assets/animals/dog/dog-food.png' import { PetFood } from '../core/pet-food' diff --git a/src/layouts/widgetify-card/pets/pet-item/pet-frog.tsx b/src/layouts/widgetify-card/pets/pet-item/pet-frog.tsx index 197f636b..c277c4fc 100644 --- a/src/layouts/widgetify-card/pets/pet-item/pet-frog.tsx +++ b/src/layouts/widgetify-card/pets/pet-item/pet-frog.tsx @@ -1,9 +1,9 @@ -import idle from '@/assets/animals/frog/ghoori_idle_8fps.gif' -import lie from '@/assets/animals/frog/ghoori_lie_8fps.gif' -import running from '@/assets/animals/frog/ghoori_run_8fps.gif' -import swipe from '@/assets/animals/frog/ghoori_swipe_8fps.gif' -import walking from '@/assets/animals/frog/ghoori_walk_8fps.gif' -import walking_fast from '@/assets/animals/frog/ghoori_walk_fast_8fps.gif' +import idle from '@/assets/animals/frog/ghoori_idle_8fps.webp' +import lie from '@/assets/animals/frog/ghoori_lie_8fps.webp' +import running from '@/assets/animals/frog/ghoori_run_8fps.webp' +import swipe from '@/assets/animals/frog/ghoori_swipe_8fps.webp' +import walking from '@/assets/animals/frog/ghoori_walk_8fps.webp' +import walking_fast from '@/assets/animals/frog/ghoori_walk_fast_8fps.webp' import { LuBug } from 'react-icons/lu' import { BasePetContainer, useBasePetLogic } from '../core/base-pet' import {