Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove animation canvas entirely | move to animation package #1457

Merged
merged 60 commits into from
Feb 28, 2025

Conversation

shanimal08
Copy link
Collaborator

@shanimal08 shanimal08 commented Jan 30, 2025

Description

  • most of the work was done in the new tari-tower repo @tari-project/tari-tower repo
    • implemented typescript, and converted Classes to modules where i could
    • fixed type errors
    • added load/remove tower functions which are exported along with setAnimationState and setAnimationProperties
    • built and published as a lib
  • added @tari-project/tari-tower package
  • removed old webgl build files
  • updated imports
  • added extra toggle loading state flag (to help in useMiningUiStateMachine.ts)
  • updated workflows so we can use the package

Motivation and Context

  • toggling visual mode previously just hid the canvas, this removes the element entirely + frees up some gpu after removing the WEBGL renderer

How Has This Been Tested?

GPU.mining.on.on.off.diff.mov
GPU.mining.off.on.off.diff.mov
animation.still.behaving.normally.mov

What process can a PR reviewer use to test or verify this change?

  • run with visual mode on vs off and see GPU stats

Breaking Changes

  • yes, after this is merged you will need to install @tari-labs/tari-tower for local development
  • nope, just npm ci after it's merged :3

Summary by CodeRabbit

  • New Features

    • Introduced an enhanced visual mode with improved loading indicators and smoother animation transitions powered by an external graphics module.
  • Refactor

    • Streamlined the page layout by removing embedded graphics initialization code and redundant elements, resulting in more efficient loading and clearer error feedback.
  • Style

    • Updated styling for key visual elements with revised identifiers to ensure a consistent and polished interface.
  • Bug Fixes

    • Improved error handling for WebGL support notifications and visual mode toggling.
  • Chores

    • Updated dependency versions for improved performance and stability.
    • Removed outdated licensing documentation for texture assets.
    • Removed unused TypeScript declarations and related files to clean up the codebase.

- add tari-tower animation lib
- remove old build files
- update imports and uses
- implement complete canvas removal
- update workflows to include setting up npm credentials
@shanimal08 shanimal08 changed the title feat: rm canvas [wip] feat: remove animation canvas entirely | move to animation package Jan 30, 2025
@shanimal08 shanimal08 marked this pull request as ready for review January 31, 2025 15:21
@brianp
Copy link
Collaborator

brianp commented Feb 3, 2025

nestedblocks.mov

When i turned visual mode off, then on this happened. It doesn't correct itself. On the next floor the glitched level moves up with everything else.

When I turned it off and on again, it broke entirely and the tower never returned.

Universe log shows nothing noteworthy.

@shanimal08
Copy link
Collaborator Author

When i turned visual mode off, then on this happened. It doesn't correct itself. On the next floor the glitched level moves up with everything else.

how did you even manage this @brianp 😭

turned it off during mining right? did you switch back super quick after, or after some time?
had you won/failed during this

@brianp
Copy link
Collaborator

brianp commented Feb 3, 2025

I didn't switch it back super quick, as I was watching resources after I turned it off.
Mining is on.
This is reproducible for me after restart.

First on/off. Broken floor.
Second on/off. Missing tower.

I have since won blocks.

5th on/off the tower returned, but it's in an absolutely abysmal state. I won't take a video. It's shocking and scary.

@brianp
Copy link
Collaborator

brianp commented Feb 3, 2025

There's also a memory leak in here somewhere. I can very quickly go from the normal 800mb on the front end to 2GB by flicking visual mode on and off.

@shanimal08 shanimal08 marked this pull request as draft February 4, 2025 08:27
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/store/useAppConfigStore.ts (2)

308-317: ⚠️ Potential issue

Add cleanup for tower animation resources.

To prevent the reported memory leaks when toggling visual mode, implement proper cleanup of animation resources.

This issue was previously identified. Apply the suggested cleanup implementation:

 if (appConfig.visual_mode && !canvasElement) {
+    let cleanupAnimation: (() => void) | undefined;
     try {
-        await loadTowerAnimation({ canvasId: TOWER_CANVAS_ID, offset: sidebarTowerOffset });
+        cleanupAnimation = await loadTowerAnimation({ canvasId: TOWER_CANVAS_ID, offset: sidebarTowerOffset });
     } catch (e) {
         console.error('Error at loadTowerAnimation:', e);
         useAppConfigStore.setState({ visual_mode: false });
+    } finally {
+        return () => cleanupAnimation?.();
     }
 }

327-344: ⚠️ Potential issue

Enhance visual mode toggle with retry mechanism.

The current implementation uses a simple timeout but lacks a retry mechanism, which may not fully address the reported issues with visual mode toggling and persistence.

This issue was previously identified. Apply the suggested retry implementation:

+const VISUAL_MODE_TOGGLE_TIMEOUT_MS = 5000;
+const MAX_RETRY_ATTEMPTS = 3;
+
 export const setVisualMode = (enabled: boolean) => {
+    let timeoutId: NodeJS.Timeout;
+    let retryCount = 0;
+
+    const cleanup = () => {
+        clearTimeout(timeoutId);
+        useAppConfigStore.setState({ visualModeToggleLoading: false });
+    };
+
+    const attemptToggle = () => {
+        timeoutId = setTimeout(() => {
+            if (retryCount < MAX_RETRY_ATTEMPTS) {
+                console.warn(`Visual mode toggle attempt ${retryCount + 1} timed out, retrying...`);
+                retryCount++;
+                attemptToggle();
+            } else {
+                console.error('Visual mode toggle failed after max retries');
+                useAppConfigStore.setState({ visual_mode: !enabled });
+                cleanup();
+            }
+        }, VISUAL_MODE_TOGGLE_TIMEOUT_MS);
+
+        invoke('set_visual_mode', { enabled })
+            .then(() => {
+                clearTimeout(timeoutId);
+                cleanup();
+            })
+            .catch((e) => {
+                const appStateStore = useAppStateStore.getState();
+                console.error('Could not set visual mode', e);
+                appStateStore.setError('Could not change visual mode');
+                useAppConfigStore.setState({ visual_mode: !enabled });
+                cleanup();
+            });
+    };
+
     useAppConfigStore.setState({ visual_mode: enabled, visualModeToggleLoading: true });
-    invoke('set_visual_mode', { enabled })
-        .catch((e) => {
-            const appStateStore = useAppStateStore.getState();
-            console.error('Could not set visual mode', e);
-            appStateStore.setError('Could not change visual mode');
-            useAppConfigStore.setState({ visual_mode: !enabled });
-        })
-        .finally(() => {
-            if (loadingTimeout) {
-                clearTimeout(loadingTimeout);
-            }
-            loadingTimeout = setTimeout(() => {
-                useAppConfigStore.setState({ visualModeToggleLoading: false });
-            }, 3500);
-        });
+    attemptToggle();
 };
🧹 Nitpick comments (1)
src/store/useAppConfigStore.ts (1)

337-342: Consider reducing the loading timeout duration.

The current timeout of 3500ms might be too long for users, especially when combined with the retry mechanism.

-            loadingTimeout = setTimeout(() => {
-                useAppConfigStore.setState({ visualModeToggleLoading: false });
-            }, 3500);
+            loadingTimeout = setTimeout(() => {
+                useAppConfigStore.setState({ visualModeToggleLoading: false });
+            }, 2000);
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7aea559 and ab1c5c9.

📒 Files selected for processing (3)
  • index.html (1 hunks)
  • src/store/useAppConfigStore.ts (4 hunks)
  • src/store/useBlockchainVisualisationStore.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/store/useBlockchainVisualisationStore.ts
🧰 Additional context used
🧠 Learnings (1)
index.html (1)
Learnt from: shanimal08
PR: tari-project/universe#1457
File: index.html:184-187
Timestamp: 2025-02-12T07:12:44.355Z
Learning: The canvas cleanup and DOM manipulation for the tower animation is handled by the `@tari-project/tari-tower` package, which completely removes the canvas element when visual mode is disabled.
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: tauri-build
  • GitHub Check: machete
  • GitHub Check: cargo checks (fmt, clippy, check)
🔇 Additional comments (4)
index.html (2)

191-192: LGTM! Clean and minimal body structure.

The simplified DOM structure with TypeScript integration looks good. The removal of the <main> tag and transition to modular TypeScript code aligns well with the project's modernization goals.


184-187:

❓ Verification inconclusive

Verify pointer events behavior with the tower package.

The pointer-events: auto setting allows the canvas to receive mouse/touch events. Please verify that this aligns with the interaction requirements of the @tari-project/tari-tower package.


🌐 Web query:

Does @tari-project/tari-tower package require pointer-events: auto for touch/mouse interaction?

💡 Result:

The available search results do not provide explicit information about whether the @tari-project/tari-tower package requires pointer-events: auto for touch/mouse interaction. Here's what we can determine from the evidence:

  1. Tari Tower Package Details ([4]):

    • The GitHub repository describes it as a tower animation component for Tari Universe
    • Installation instructions show an npm-based workflow
    • No configuration details or CSS requirements are mentioned in the provided content
  2. General Pointer Events Context ([3][6][9]):

    • pointer-events: auto is the default CSS value that allows normal interaction with elements
    • This property controls whether elements can:
      • Be targeted by mouse/touch/pen events
      • Trigger hover states
      • Capture click/drag interactions
  3. Interaction Patterns ([2][5]):

    • Touch/mouse implementations typically require event handlers for:
      • pointerdown/touchstart
      • pointermove/touchmove
      • pointerup/touchend
    • No specific CSS requirements are mandated by W3C standards for basic pointer interaction

Without explicit documentation from Tari Tower's source code or official docs in the search results, we cannot definitively state its CSS requirements. However, most interactive web components using pointer/touch events would need either:

  • Default pointer-events: auto behavior
  • Explicit styling if containing elements block pointer propagation

For definitive answers, consult:

npm view @tari-project/tari-tower peerDependencies

or inspect the component's source code for CSS declarations related to pointer events[4].

Citations:


Confirm Pointer Events Setup for #tower-canvas

The pointer-events: auto style is standard for ensuring that the canvas receives touch and mouse interactions. Our investigation did not reveal any explicit requirements from the @tari-project/tari-tower package that would mandate a different pointer-events configuration. However, please verify through practical testing that the current setup meets the interaction needs without unintended side effects.

src/store/useAppConfigStore.ts (2)

16-18: LGTM! Good addition of loading state.

The addition of visualModeToggleLoading to the State type is a good practice for tracking async operations.


1-1:

❓ Verification inconclusive

Verify imports and their versions.

The new imports from @tari-project/tari-tower and UI store need version verification to ensure compatibility and prevent the reported white screen issues.

Also applies to: 10-10, 14-14


🌐 Web query:

What is the latest version of @tari-project/tari-tower package?

💡 Result:

The latest version of the @tari-project/tari-tower package is v0.0.9, released 2 days ago as of February 14, 2025[1]. This information comes directly from its GitHub repository, which lists this version under the "Releases" section with a timestamp matching the current date context[1].

For developers using this library, note that it provides animation control methods like loadTowerAnimation, setAnimationState, and utilities for managing canvas-based animations in Tari Universe applications[1].

Citations:


Import Version Verification: Confirm @tari-project/tari-tower (v0.0.9) and UI store Compatibility

  • The web query confirms that the latest version of @tari-project/tari-tower is v0.0.9.
  • Please ensure that the import for @tari-project/tari-tower (and its usage) in the codebase aligns with version v0.0.9.
  • Also, verify that the version of the UI store imported at lines 10 and 14 is compatible with this update to avoid any white screen issues.

@@ -1,3 +1,4 @@
let loadingTimeout: NodeJS.Timeout | undefined;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove unused timeout variable.

After implementing the retry mechanism, this global timeout variable becomes unnecessary.

-let loadingTimeout: NodeJS.Timeout | undefined;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let loadingTimeout: NodeJS.Timeout | undefined;

@shanimal08 shanimal08 marked this pull request as draft February 24, 2025 07:10
@shanimal08 shanimal08 marked this pull request as ready for review February 24, 2025 11:13
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/store/useAppConfigStore.ts (2)

323-340: ⚠️ Potential issue

Improve timeout handling in setVisualMode.

The current implementation has several issues:

  1. Fixed timeout of 3500ms might not be sufficient for all network conditions.
  2. No cleanup on component unmount.
  3. No retry mechanism for failed toggles.

The previous review already suggested adding a timeout and retry mechanism. Please refer to that comment for the implementation details.


1-1: 🛠️ Refactor suggestion

Move timeout variable into component scope.

The global loadingTimeout variable could lead to race conditions if multiple visual mode toggles occur simultaneously. Consider moving this into the component's scope or using a ref.

-let loadingTimeout: NodeJS.Timeout | undefined;
🧹 Nitpick comments (1)
index.html (1)

192-195: Consider adding z-index to canvas element.

The absolute positioning without a z-index might cause layering issues with other UI elements.

 #tower-canvas {
     position: absolute;
     pointer-events: auto;
+    z-index: 1;
 }
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 267fbd9 and 05ff133.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • index.html (1 hunks)
  • package.json (1 hunks)
  • src/App/App.tsx (1 hunks)
  • src/store/useAppConfigStore.ts (4 hunks)
  • src/store/useUIStore.ts (2 hunks)
  • src/theme/GlobalStyle.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • package.json
  • src/App/App.tsx
  • src/store/useUIStore.ts
  • src/theme/GlobalStyle.ts
🧰 Additional context used
🧠 Learnings (1)
index.html (1)
Learnt from: shanimal08
PR: tari-project/universe#1457
File: index.html:184-187
Timestamp: 2025-02-12T07:12:44.355Z
Learning: The canvas cleanup and DOM manipulation for the tower animation is handled by the `@tari-project/tari-tower` package, which completely removes the canvas element when visual mode is disabled.
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: tauri-build
  • GitHub Check: cargo checks (fmt, clippy, check)
🔇 Additional comments (1)
index.html (1)

199-200: LGTM!

The simplified DOM structure and delegation of canvas management to @tari-project/tari-tower package aligns with the PR objectives.

Comment on lines +310 to +317
if (appConfig.visual_mode && !canvasElement) {
try {
await loadTowerAnimation({ canvasId: TOWER_CANVAS_ID, offset: sidebarTowerOffset });
} catch (e) {
console.error('Error at loadTowerAnimation:', e);
useAppConfigStore.setState({ visual_mode: false });
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling in fetchAppConfig.

The error handling in the visual mode initialization could be more robust:

  1. No retry mechanism for failed tower animation loading.
  2. Silent failure might confuse users.
 if (appConfig.visual_mode && !canvasElement) {
+    let retryCount = 0;
+    const maxRetries = 3;
+    const retryDelay = 1000;
+
+    const attemptLoad = async () => {
         try {
             await loadTowerAnimation({ canvasId: TOWER_CANVAS_ID, offset: sidebarTowerOffset });
         } catch (e) {
             console.error('Error at loadTowerAnimation:', e);
-            useAppConfigStore.setState({ visual_mode: false });
+            if (retryCount < maxRetries) {
+                retryCount++;
+                console.warn(`Retrying tower animation load (attempt ${retryCount}/${maxRetries})...`);
+                setTimeout(attemptLoad, retryDelay);
+            } else {
+                console.error('Failed to load tower animation after max retries');
+                useAppConfigStore.setState({ visual_mode: false });
+                const appStateStore = useAppStateStore.getState();
+                appStateStore.setError('Failed to initialize visual mode');
+            }
         }
     }
+    attemptLoad();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (appConfig.visual_mode && !canvasElement) {
try {
await loadTowerAnimation({ canvasId: TOWER_CANVAS_ID, offset: sidebarTowerOffset });
} catch (e) {
console.error('Error at loadTowerAnimation:', e);
useAppConfigStore.setState({ visual_mode: false });
}
}
if (appConfig.visual_mode && !canvasElement) {
let retryCount = 0;
const maxRetries = 3;
const retryDelay = 1000;
const attemptLoad = async () => {
try {
await loadTowerAnimation({ canvasId: TOWER_CANVAS_ID, offset: sidebarTowerOffset });
} catch (e) {
console.error('Error at loadTowerAnimation:', e);
if (retryCount < maxRetries) {
retryCount++;
console.warn(`Retrying tower animation load (attempt ${retryCount}/${maxRetries})...`);
setTimeout(attemptLoad, retryDelay);
} else {
console.error('Failed to load tower animation after max retries');
useAppConfigStore.setState({ visual_mode: false });
const appStateStore = useAppStateStore.getState();
appStateStore.setError('Failed to initialize visual mode');
}
}
};
attemptLoad();
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
src/containers/main/Dashboard/components/VisualMode.tsx (1)

5-17: 💡 Verification agent

🧩 Analysis chain

Verify the import paths for required components.

Check that all imported functions from the new @tari-project/tari-tower package are available and properly exported.


🏁 Script executed:

#!/bin/bash
# Check the tari-tower package exports

echo "Checking the tari-tower package exports:"
npm list @tari-project/tari-tower
echo "Looking for exported functions in node_modules:"
grep -r "export.*loadTowerAnimation\|export.*removeTowerAnimation\|export.*setAnimationState" ./node_modules/@tari-project/tari-tower --include="*.js" --include="*.ts" | head -10

Length of output: 539


Actionable: Verify the '@tari-project/tari-tower' dependency installation and import paths

The executed script indicates that the @tari-project/tari-tower package is not found in your dependencies—none of the expected exports (loadTowerAnimation, removeTowerAnimation, setAnimationState) are available. Please ensure that:

  • The package is correctly installed (or added to your dependencies) if it is intended to be used.
  • The import path is accurate based on the package’s actual location and exported members.
  • If the package naming or structure has changed, update the imports accordingly.
♻️ Duplicate comments (1)
src/containers/main/Dashboard/components/VisualMode.tsx (1)

54-60: 🛠️ Refactor suggestion

Add debounce to prevent rapid toggling.

Rapid toggling could exacerbate memory issues and visual glitches reported in PR comments.

+import { debounce } from 'lodash';
+
-const handleSwitch = useCallback(() => {
+const handleSwitch = useCallback(
+    debounce(() => {
         if (visualMode) {
             handleDisable();
         } else {
             handleEnable();
         }
-    }, [handleDisable, handleEnable, visualMode]);
+    }, 1000),
+    [handleDisable, handleEnable, visualMode],
+);
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6214a66 and 8e2a838.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • package.json (1 hunks)
  • src/containers/main/Dashboard/components/VisualMode.tsx (3 hunks)
  • src/store/useUIStore.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • src/store/useUIStore.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: tauri-build
🔇 Additional comments (2)
src/containers/main/Dashboard/components/VisualMode.tsx (2)

28-41: Consider adding a timeout to prevent hangs during disable operation.

The disable operation could potentially hang if the animation cleanup takes too long. Adding a timeout would ensure the UI remains responsive.

 const handleDisable = useCallback(() => {
+    const timeoutId = setTimeout(() => {
+        console.error('Tower animation cleanup timed out');
+        setVisualMode(false);
+    }, 5000);
+
     setVisualMode(false);
     removeTowerAnimation({ canvasId: TOWER_CANVAS_ID })
         .then(() => {
             // Force garbage collection to clean up WebGL context
             if (window.gc) {
                 window.gc();
             }
         })
         .catch((e) => {
             console.error('Could not disable visual mode. Error at loadTowerAnimation:', e);
             setVisualMode(true);
         })
+        .finally(() => {
+            clearTimeout(timeoutId);
+        });
 }, []);

42-52: Add memory usage monitoring to help debug reported memory leaks.

The PR comments mention significant memory usage increases (800MB to 2GB). Adding monitoring could help diagnose this issue.

 const handleEnable = useCallback(() => {
+    const initialMemory = window.performance.memory?.usedJSHeapSize;
+    
     loadTowerAnimation({ canvasId: TOWER_CANVAS_ID, offset: sidebarTowerOffset })
         .then(() => {
             setVisualMode(true);
             setAnimationState('showVisual');
+            
+            // Monitor memory usage
+            const currentMemory = window.performance.memory?.usedJSHeapSize;
+            if (currentMemory && initialMemory && currentMemory - initialMemory > 500 * 1024 * 1024) {
+                console.warn('High memory usage detected after enabling visual mode');
+            }
         })
         .catch((e) => {
             console.error('Could not enable visual mode. Error at loadTowerAnimation:', e);
             setVisualMode(false);
         });
 }, []);

Comment on lines +28 to +41
const handleDisable = useCallback(() => {
setVisualMode(false);
removeTowerAnimation({ canvasId: TOWER_CANVAS_ID })
.then(() => {
// Force garbage collection to clean up WebGL context
if (window.gc) {
window.gc();
}
})
.catch((e) => {
console.error('Could not disable visual mode. Error at loadTowerAnimation:', e);
setVisualMode(true);
});
}, []);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Implement a reset mechanism to address reported visual glitches.

PR comments mention persistent visual glitches when toggling visual mode. A complete reset mechanism may help resolve this.

Also applies to: 42-52


🏁 Script executed:

#!/bin/bash
# Check for any existing error handling or reset mechanisms in the codebase

echo "Checking for existing reset mechanisms in animation handling:"
rg -A 3 "reset.*animation|animation.*reset" --type ts

Length of output: 188


Implement a complete reset mechanism for the tower animation cleanup

After verifying the codebase, it appears that there’s no dedicated reset functionality for the tower animation. The current implementation in src/containers/main/Dashboard/components/VisualMode.tsx (lines 28–41 and the corresponding block at 42–52) disables visual mode by removing the tower animation and forcing garbage collection, but it lacks a reset step that fully clears any residual animation state. This omission could allow persistent visual glitches when toggling visual mode.

  • Issue: No explicit reset mechanism is implemented in the animation cleanup process.
  • Suggestion: In addition to calling removeTowerAnimation and performing GC, implement a reset routine that clears all animation-related data and state, ensuring any stuck visual elements are fully removed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/store/useAppConfigStore.ts (3)

1-1: 🛠️ Refactor suggestion

Remove unused global variable.

The global variable loadingTimeout makes the code less maintainable and could lead to issues if setVisualMode is called multiple times. This variable should be localized within the function.

-let loadingTimeout: NodeJS.Timeout | undefined;

315-322: ⚠️ Potential issue

Add retry mechanism for tower animation loading.

The current implementation lacks a retry mechanism for loading the tower animation, which could be causing the reported issues with visual mode toggling. Users reported white screens and glitches when toggling back to visual mode.

if (appConfig.visual_mode && !canvasElement) {
+    let retryCount = 0;
+    const maxRetries = 3;
+    const retryDelay = 1000;
+
+    const attemptLoad = async () => {
        try {
            await loadTowerAnimation({ canvasId: TOWER_CANVAS_ID, offset: sidebarTowerOffset });
        } catch (e) {
            console.error('Error at loadTowerAnimation:', e);
-            useAppConfigStore.setState({ visual_mode: false });
+            if (retryCount < maxRetries) {
+                retryCount++;
+                console.warn(`Retrying tower animation load (attempt ${retryCount}/${maxRetries})...`);
+                setTimeout(attemptLoad, retryDelay);
+            } else {
+                console.error('Failed to load tower animation after max retries');
+                useAppConfigStore.setState({ visual_mode: false });
+                const appStateStore = useAppStateStore.getState();
+                appStateStore.setError('Failed to initialize visual mode');
+            }
        }
    }
+    attemptLoad();
}

328-345: ⚠️ Potential issue

Add timeout and resource cleanup for visual mode toggle.

The current implementation has several issues:

  1. Uses a global variable for timeout management
  2. Has a hardcoded delay that may not be sufficient
  3. Lacks a retry mechanism for visual mode toggle
  4. Doesn't properly clean up animation resources

These issues likely contribute to the reported memory leak (800MB to 2GB) and visual glitches when toggling modes.

+const VISUAL_MODE_TOGGLE_TIMEOUT_MS = 5000;
+const MAX_RETRY_ATTEMPTS = 3;
+
 export const setVisualMode = (enabled: boolean) => {
+    let timeoutId: NodeJS.Timeout;
+    let retryCount = 0;
+
+    const cleanup = () => {
+        clearTimeout(timeoutId);
+        useAppConfigStore.setState({ visualModeToggleLoading: false });
+    };
+
+    const attemptToggle = () => {
+        timeoutId = setTimeout(() => {
+            if (retryCount < MAX_RETRY_ATTEMPTS) {
+                console.warn(`Visual mode toggle attempt ${retryCount + 1} timed out, retrying...`);
+                retryCount++;
+                attemptToggle();
+            } else {
+                console.error('Visual mode toggle failed after max retries');
+                useAppConfigStore.setState({ visual_mode: !enabled });
+                cleanup();
+            }
+        }, VISUAL_MODE_TOGGLE_TIMEOUT_MS);
+
+        invoke('set_visual_mode', { enabled })
+            .then(() => {
+                clearTimeout(timeoutId);
+                cleanup();
+            })
+            .catch((e) => {
+                const appStateStore = useAppStateStore.getState();
+                console.error('Could not set visual mode', e);
+                appStateStore.setError('Could not change visual mode');
+                useAppConfigStore.setState({ visual_mode: !enabled });
+                cleanup();
+            });
+    };
+
     useAppConfigStore.setState({ visual_mode: enabled, visualModeToggleLoading: true });
-    invoke('set_visual_mode', { enabled })
-        .catch((e) => {
-            const appStateStore = useAppStateStore.getState();
-            console.error('Could not set visual mode', e);
-            appStateStore.setError('Could not change visual mode');
-            useAppConfigStore.setState({ visual_mode: !enabled });
-        })
-        .finally(() => {
-            if (loadingTimeout) {
-                clearTimeout(loadingTimeout);
-            }
-            loadingTimeout = setTimeout(() => {
-                useAppConfigStore.setState({ visualModeToggleLoading: false });
-            }, 3500);
-        });
+    attemptToggle();
};
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e2a838 and c7d6fd8.

📒 Files selected for processing (2)
  • package.json (1 hunks)
  • src/store/useAppConfigStore.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: tauri-build
  • GitHub Check: cargo checks (fmt, clippy, check)
🔇 Additional comments (1)
src/store/useAppConfigStore.ts (1)

16-18: Good addition of loading state tracking.

Adding visualModeToggleLoading to the state is a good approach for handling the UI feedback during visual mode transitions.

import { useMiningMetricsStore } from '@app/store/useMiningMetricsStore.ts';
import { pauseMining, startMining, stopMining } from '@app/store/miningStoreActions.ts';

type State = Partial<AppConfig>;
import { loadTowerAnimation } from '@tari-project/tari-tower';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

❓ Verification inconclusive

Ensure proper cleanup of tower animation resources.

To prevent the reported memory leaks (increasing from 800MB to 2GB), ensure loadTowerAnimation returns a cleanup function that is properly called when visual mode is toggled off.

Run this script to check if the loadTowerAnimation function returns a cleanup function:


🏁 Script executed:

#!/bin/bash
# Check if loadTowerAnimation returns a cleanup function

# Check if there's any code that handles cleanup returned from loadTowerAnimation
rg -A 2 -B 2 "loadTowerAnimation.*\).*cleanup|cleanup.*loadTowerAnimation"

# Look at the tower package to understand its API
rg "loadTowerAnimation|removeTowerAnimation" node_modules/@tari-project/tari-tower

Length of output: 239


Manual Verification Required: Confirm Cleanup Implementation for loadTowerAnimation

The script results did not indicate that a cleanup function is returned or used when toggling visual mode off. Additionally, the error regarding the missing node_modules entry for @tari-project/tari-tower suggests that the package’s contents were not available for inspection. Please manually verify the following:

  • Confirm that the @tari-project/tari-tower dependency is correctly installed and its API (specifically, the behavior of loadTowerAnimation) matches expectations.
  • Check that loadTowerAnimation indeed returns a cleanup function and that this return value is utilized appropriately in your code—specifically when visual mode is toggled off.
  • Ensure that all necessary cleanup calls are in place to prevent memory leaks.

Copy link
Collaborator

@brianp brianp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on Mac and Windows 👍🏻

@brianp brianp merged commit 333aa88 into tari-project:main Feb 28, 2025
9 checks passed
@shanimal08 shanimal08 deleted the test/ts_ani branch February 28, 2025 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a-blocktower-animations a-ui dependencies Pull requests that update a dependency file javascript Pull requests that update Javascript code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants