From b13a5ae1ae2e7a4ebe916edff12733afed5010ca Mon Sep 17 00:00:00 2001 From: filemon Date: Tue, 24 Mar 2026 12:09:12 -0300 Subject: [PATCH] Add reactive companion visibility with companionId tracking - Track companionId in useBlobbiEntryAnimation to detect companion changes - When companion is selected/changed, trigger new entry animation immediately - Random entry direction (fall or rise) for new companion appearances - No transition delay for companion changes (unlike route changes) - Companion removal hides Blobbi via existing isVisible logic --- .../companion/hooks/useBlobbiCompanion.ts | 3 +- .../hooks/useBlobbiEntryAnimation.ts | 29 +++++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/blobbi/companion/hooks/useBlobbiCompanion.ts b/src/blobbi/companion/hooks/useBlobbiCompanion.ts index 90e1fbed..b070f843 100644 --- a/src/blobbi/companion/hooks/useBlobbiCompanion.ts +++ b/src/blobbi/companion/hooks/useBlobbiCompanion.ts @@ -226,7 +226,7 @@ export function useBlobbiCompanion(): UseBlobbiCompanionResult { onReachedTarget, }); - // Entry animation management (handles route changes) + // Entry animation management (handles route changes and companion changes) // Must be after motion so we can pass isDragging const { entryState, @@ -240,6 +240,7 @@ export function useBlobbiCompanion(): UseBlobbiCompanionResult { pathname: location.pathname, sidebarOrder, isDragging: motion.isDragging, + companionId: companion?.d ?? null, // Track companion identity for reactive updates onComplete: handleEntryComplete, onStart: handleEntryStart, }); diff --git a/src/blobbi/companion/hooks/useBlobbiEntryAnimation.ts b/src/blobbi/companion/hooks/useBlobbiEntryAnimation.ts index 9c2a03d5..b8c82fd7 100644 --- a/src/blobbi/companion/hooks/useBlobbiEntryAnimation.ts +++ b/src/blobbi/companion/hooks/useBlobbiEntryAnimation.ts @@ -45,6 +45,8 @@ interface UseBlobbiEntryAnimationOptions { sidebarOrder: string[]; /** Whether the companion is currently being dragged */ isDragging: boolean; + /** Unique identifier of current companion (d-tag) - changes trigger re-entry */ + companionId: string | null; /** Called when entry animation completes */ onComplete: () => void; /** Called when entry starts (for resetting position) */ @@ -93,6 +95,7 @@ export function useBlobbiEntryAnimation({ pathname, sidebarOrder, isDragging, + companionId, onComplete, onStart, }: UseBlobbiEntryAnimationOptions): UseBlobbiEntryAnimationResult { @@ -106,6 +109,7 @@ export function useBlobbiEntryAnimation({ // Refs for tracking state const animationRef = useRef(null); const lastPathnameRef = useRef(pathname); + const lastCompanionIdRef = useRef(companionId); const routeChangeTimeoutRef = useRef | null>(null); const hasCompletedFirstEntryRef = useRef(false); @@ -237,24 +241,37 @@ export function useBlobbiEntryAnimation({ }, [entryState.phase, isDragging, resolvePermanentStuck]); /** - * Handle route changes - determine entry direction and start animation. + * Handle route changes and companion changes - trigger entry animation. */ useEffect(() => { if (!isActive) return; const previousPath = lastPathnameRef.current; + const previousCompanionId = lastCompanionIdRef.current; const isInitialEntry = !hasCompletedFirstEntryRef.current; const routeChanged = pathname !== previousPath; + const companionChanged = companionId !== previousCompanionId && companionId !== null; - if (isInitialEntry) { + // Update refs + lastPathnameRef.current = pathname; + lastCompanionIdRef.current = companionId; + + if (isInitialEntry && companionId) { // First entry - determine direction based on previous path (if any) const entryType = getEntryDirection(null, pathname, sidebarOrder); startEntry(entryType); - lastPathnameRef.current = pathname; - } else if (routeChanged) { + } else if (companionChanged) { + // Companion changed - trigger new entry with random direction + // Cancel any existing entry immediately + cancelEntry(); + setIsHiddenForTransition(false); // Show immediately (no delay for companion change) + + // Random entry type for new companion (fall or rise) + const entryType: EntryType = Math.random() < 0.5 ? 'fall' : 'rise'; + startEntry(entryType); + } else if (routeChanged && companionId) { // Route changed - determine direction for new route const entryType = getEntryDirection(previousPath, pathname, sidebarOrder); - lastPathnameRef.current = pathname; // Immediately hide Blobbi and cancel current entry cancelEntry(); @@ -265,7 +282,7 @@ export function useBlobbiEntryAnimation({ startEntry(entryType); }, entryConfig.routeChangeRestartDelay); } - }, [isActive, pathname, sidebarOrder, startEntry, cancelEntry, entryConfig.routeChangeRestartDelay]); + }, [isActive, pathname, companionId, sidebarOrder, startEntry, cancelEntry, entryConfig.routeChangeRestartDelay]); /** * Animation loop for FALL entry.