Skip to content

Add animation path generation and controls#60

Open
sidhant-sriv wants to merge 1 commit intomasterfrom
animate
Open

Add animation path generation and controls#60
sidhant-sriv wants to merge 1 commit intomasterfrom
animate

Conversation

@sidhant-sriv
Copy link
Owner

No description provided.

@sidhant-sriv sidhant-sriv requested a review from Copilot October 25, 2025 20:59
@gemini-code-assist
Copy link

Summary of Changes

Hello @sidhant-sriv, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant new feature that brings dynamic animation capabilities to flowcharts. It enables the automatic generation of potential execution paths through a given code's control flow, and then provides an interactive visual representation of these paths directly within the flowchart viewer. This enhancement aims to improve the understanding of complex code logic by allowing users to 'step through' the flowchart and observe the flow of execution.

Highlights

  • Animation Path Generation: Introduced a new AnimationPathGenerator class responsible for traversing the flowchart's Intermediate Representation (IR) and identifying all possible execution paths, including handling decision points and loops with limited iterations. These paths are then stored within the FlowchartIR.
  • Flowchart IR Extension: The FlowchartIR interface has been extended to include an optional animationPaths array, which will hold the generated AnimationPath objects, each detailing the sequence of nodes and edges for a specific execution flow.
  • Mermaid Integration: The EnhancedMermaidGenerator now incorporates the generated animation paths into the Mermaid output as special comments (%% ANIM_PATH and %% ANIM_DESC). This allows the webview to parse and utilize these paths for animation without altering the core Mermaid diagram structure.
  • Interactive Animation Controls: Added new UI elements to the flowchart viewer, including 'Animate' and 'Path Selector' buttons. These controls enable users to start/stop the animation and switch between different generated execution paths.
  • Visual Animation Feedback: Implemented CSS styles and JavaScript logic within the webview to visually animate the flowchart. This includes highlighting the current node with a pulsing glow, marking visited nodes with a distinct background, and highlighting traversed edges, providing clear visual feedback of the execution flow.
  • Webview Communication: New message types (StartAnimationMessage, StopAnimationMessage, SwitchPathMessage) and corresponding handlers have been added to BaseFlowchartProvider to facilitate communication between the VS Code extension and the webview for controlling the animation state.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds animation capabilities to the Visor flowchart extension, allowing users to visualize execution paths through code flowcharts with step-by-step animations. The changes introduce path generation logic, animation controls, and UI elements for managing multiple execution paths.

Key changes:

  • Implements an AnimationPathGenerator to automatically discover and generate execution paths through flowcharts
  • Adds animation control buttons and UI for starting/stopping animations and switching between paths
  • Extends the webview messaging system to handle animation commands

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/view/BaseFlowchartProvider.ts Adds animation message types, handlers, UI controls, and JavaScript animation logic in the webview
src/logic/utils/AnimationPathGenerator.ts New file implementing path generation algorithm with support for branches, loops, and exit detection
src/logic/EnhancedMermaidGenerator.ts Integrates path generator and embeds animation metadata as comments in Mermaid output
src/ir/ir.ts Adds AnimationPath interface and optional animationPaths field to FlowchartIR

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

[...pathSteps],
depth + 1
);
}
Copy link

Choose a reason for hiding this comment

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

Bug: Loop Handling Fails to Explore Multiple Exit Paths

The loop handling in generatePathsFromNode has two issues: the number of simulated iterations is incorrectly tied to the count of outgoing edges (Math.min(outgoingEdges.length, this.MAX_LOOP_ITERATIONS)), leading to inconsistent loop counts. Also, it always follows the first outgoing edge (outgoingEdges[0]) for all iterations, preventing exploration of other potential loop exit paths.

Fix in Cursor Fix in Web

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a major new feature: animated execution paths for flowcharts. It adds the backend logic to generate these paths from the flowchart's intermediate representation and integrates the animation controls and rendering into the webview. My review focuses on the correctness and robustness of the new path generation algorithm, especially concerning loops and fallback scenarios. I've also identified several areas for improvement in the webview implementation, including theme-aware styling, performance, and UI clarity. There are a few critical issues in the path generation that need to be addressed to ensure animations work correctly for all flowcharts.

Comment on lines +84 to +88
// Prevent cycles
if (visited.has(nodeId)) {
console.log(`AnimationPathGenerator: Cycle detected at node ${nodeId}`);
return;
}

Choose a reason for hiding this comment

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

critical

The current cycle detection logic prevents the correct traversal of loops. The visited.has(nodeId) check will cause the path generation to terminate immediately upon re-entering a node that is part of a loop, meaning loops will not be animated correctly. The logic needs to be adjusted to allow visiting a node multiple times within a path, up to a certain limit, to correctly represent loops. One approach could be to pass a map of node visit counts instead of a Set and check against a maximum visit count.

const paths = [];
const pathDescriptions = new Map();

const lines = mermaidSource.split('\\n');

Choose a reason for hiding this comment

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

critical

The parseAnimationPaths function uses split('\\n') to process the Mermaid source. This will attempt to split the string by a literal backslash followed by the character 'n', which is incorrect. The textContent of the source div will contain actual newline characters (\n), so the split should be done on \n.

Suggested change
const lines = mermaidSource.split('\\n');
const lines = mermaidSource.split('\n');

const loopIterations = Math.min(outgoingEdges.length, this.MAX_LOOP_ITERATIONS);

for (let i = 0; i < loopIterations; i++) {
const edge = outgoingEdges[0]; // Assume first edge is the loop continuation

Choose a reason for hiding this comment

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

high

The assumption that outgoingEdges[0] is always the loop continuation path is risky and may not be true for all control flow structures (e.g., a for loop could have its exit condition check result in a different edge order). This could lead to incorrect animation paths. The logic should be made more robust, for example by analyzing edge properties or labels if available to distinguish between the loop body and loop exit paths.

Comment on lines +257 to +273
private static generateFallbackPath(ir: FlowchartIR): AnimationPath[] {
// If no paths were generated, create a simple linear path
const nodes = ir.nodes.map(n => n.id);
const edges: string[] = [];

// Create edges between consecutive nodes
for (let i = 0; i < nodes.length - 1; i++) {
edges.push(`${nodes[i]}_${nodes[i + 1]}`);
}

return [{
id: 'path_0',
nodes,
edges,
description: `Linear path: ${nodes.join(' → ')}`
}];
}

Choose a reason for hiding this comment

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

high

The fallback path generation is flawed. It assumes a linear execution flow based on the order of nodes in the ir.nodes array, which is not guaranteed to be correct. It also fabricates edge IDs between consecutive nodes, which may not correspond to actual edges in the graph. This can result in a nonsensical or broken fallback animation. A more robust fallback would be to perform a simple depth-first traversal from the entry node without exploring branches, to construct a single, valid path.

Comment on lines +759 to +783
/* Animation styles */
.animated-current > rect,
.animated-current > polygon,
.animated-current > circle,
.animated-current > path {
stroke: #00ff00 !important;
stroke-width: 5px !important;
filter: drop-shadow(0 0 10px #00ff00);
animation: pulse-glow 1s ease-in-out infinite alternate;
}

.animated-visited > rect,
.animated-visited > polygon,
.animated-visited > circle,
.animated-visited > path {
fill: rgba(0, 255, 0, 0.2) !important;
stroke: #00aa00 !important;
stroke-width: 2px !important;
}

.animated-edge {
stroke: #00ff00 !important;
stroke-width: 4px !important;
filter: drop-shadow(0 0 4px #00ff00);
}

Choose a reason for hiding this comment

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

high

The animation styles use hardcoded colors (e.g., #00ff00, #00aa00). This will not look good on all user themes and may cause accessibility issues due to poor contrast. Please use VS Code theme variables (e.g., var(--vscode-charts-green)) to ensure the animation colors are consistent with the user's environment.

            /* Animation styles */
            .animated-current > rect,
            .animated-current > polygon,
            .animated-current > circle,
            .animated-current > path {
                stroke: var(--vscode-charts-green) !important;
                stroke-width: 5px !important;
                filter: drop-shadow(0 0 10px var(--vscode-charts-green));
                animation: pulse-glow 1s ease-in-out infinite alternate;
            }

            .animated-visited > rect,
            .animated-visited > polygon,
            .animated-visited > circle,
            .animated-visited > path {
                fill: var(--vscode-charts-green) !important;
                fill-opacity: 0.2 !important;
                stroke: var(--vscode-charts-green) !important;
                stroke-width: 2px !important;
            }

            .animated-edge {
                stroke: var(--vscode-charts-green) !important;
                stroke-width: 4px !important;
                filter: drop-shadow(0 0 4px var(--vscode-charts-green));
            }

Comment on lines +3 to +8
export interface AnimationPath {
id: string;
nodes: string[];
edges: string[];
description: string;
}

Choose a reason for hiding this comment

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

medium

The AnimationPath interface is duplicated here. It has also been added to src/ir/ir.ts in this pull request. To maintain a single source of truth and avoid potential inconsistencies, please remove this local definition and import it from ../../ir/ir instead. You will need to update the import statement on line 1 accordingly.

Comment on lines +278 to +298
public static getPathDescription(path: AnimationPath, maxLength: number = 50): string {
if (path.description.length <= maxLength) {
return path.description;
}

return path.description.substring(0, maxLength - 3) + '...';
}

/**
* Check if a path contains loops
*/
public static hasLoops(path: AnimationPath): boolean {
const nodeCounts = new Map<string, number>();

for (const nodeId of path.nodes) {
const count = nodeCounts.get(nodeId) || 0;
nodeCounts.set(nodeId, count + 1);
}

return Array.from(nodeCounts.values()).some(count => count > 1);
}

Choose a reason for hiding this comment

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

medium

These methods (getPathDescription and hasLoops) are public but seem to be unused in the current implementation. If they are intended for future use, it might be worth adding a comment indicating that. Otherwise, they should be removed to avoid dead code.

Comment on lines +785 to +792
@keyframes pulse-glow {
from {
filter: drop-shadow(0 0 10px #00ff00);
}
to {
filter: drop-shadow(0 0 20px #00ff00);
}
}

Choose a reason for hiding this comment

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

medium

The @keyframes pulse-glow animates the filter property. Animating filter is often not hardware-accelerated and can be performance-intensive, potentially causing jank. For a smoother pulsing effect, consider animating transform: scale() and opacity instead, as these properties are typically handled by the GPU.

Comment on lines +1319 to +1322
const shortDesc = currentPath.description.length > 15
? currentPath.description.substring(0, 15) + '...'
: currentPath.description;
pathSelector.textContent = \`Path \${animationState.currentPathIndex + 1}\`;

Choose a reason for hiding this comment

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

medium

The updatePathSelector function calculates a shortDesc by truncating the path's description, but this variable is never used. The button text is set to a generic Path {n}. Using the shortDesc for the button's text would make the UI more informative for the user. I've also slightly increased the length before truncation.

                    const shortDesc = currentPath.description.length > 25 
                        ? currentPath.description.substring(0, 25) + '...'
                        : currentPath.description;
                    pathSelector.textContent = `Path (${animationState.currentPathIndex + 1}/${animationState.paths.length}) ${shortDesc}`;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants