Skip to content

feat:Validate and fix modular graph canvas for Emscripten web demo #208

Merged
MohitBareja16 merged 11 commits into
sudip-mondal-2002:mainfrom
bhavyanjain3004:feature/modular-graph-canvas-web
May 25, 2026
Merged

feat:Validate and fix modular graph canvas for Emscripten web demo #208
MohitBareja16 merged 11 commits into
sudip-mondal-2002:mainfrom
bhavyanjain3004:feature/modular-graph-canvas-web

Conversation

@bhavyanjain3004

@bhavyanjain3004 bhavyanjain3004 commented May 23, 2026

Copy link
Copy Markdown
Contributor

Tasks

fixes #149

  • Build the web demo with PR feat: implement modular DAG routing canvas with Splitter/Mixer nodes … #132 and run existing Playwright tests
  • Manual test: pan canvas with right-click-drag, add nodes, draw cables — verified in Chrome
  • Add touch event handling: two-finger drag to pan, pinch-to-zoom the canvas
  • Test via browser DevTools device emulation (mobile Chrome simulation)
  • Add Playwright tests for:
    • Canvas pan gesture
    • Adding a Splitter node
    • Drawing a cable between two nodes
    • Deleting a node
  • Verify HiDPI canvas scaling is correct (nodes/cables not offset on Retina displays)
  • Check FPS stays ≥ 30 on a mid-range mobile device with 10 nodes + 15 cables

Acceptance Criteria

  • All existing Playwright tests still pass after PR feat: implement modular DAG routing canvas with Splitter/Mixer nodes … #132
  • New Playwright tests for canvas interactions pass in CI
  • Canvas pan/zoom works via mouse on desktop browsers
  • Canvas pan/zoom works via touch on mobile browsers (tested via emulation)
  • Touch events on mobile don't interfere with desktop mouse input
  • Canvas performance stays ≥ 30 FPS on mobile with 15 nodes + 20 cables
  • HiDPI canvas scale factor correctly applied (no node/cable offset misalignment on Retina)
  • File dialog (native and web) unaffected by canvas changes

Native unit test

Screenshot 2026-05-23 at 10 27 26 PM

Playwright E2E tests

Screenshot 2026-05-23 at 10 27 40 PM

Zoom and pan behaviour

Screen.Recording.2026-05-23.at.10.40.42.PM.mov

Summary by CodeRabbit

  • New Features

    • Smooth, animated canvas zooming and panning (time-based interpolation) with DPI-aware rendering and canvas hover tracking.
    • Mouse-wheel zoom (Ctrl to zoom toward cursor), two-finger pinch/gesture support, and browser touch/wheel handlers.
    • Browser integration APIs to drive canvas and basic graph actions from JS.
  • Tests

    • End-to-end tests for canvas interactions and modular graph operations.
  • Chores

    • Playwright launch config and CI artifact uploads updated.
    • .gitignore extended to exclude Playwright/web test reports.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

Failed to post review comments

📝 Walkthrough

Walkthrough

Adds DPI-aware canvas state and smooth time-based zoom/pan, hover-gated input handling, Emscripten-exported gesture and graph APIs, browser touch/wheel bridging, and Playwright E2E tests verifying pan/zoom, node/link creation, and deletion.

Changes

Web Canvas Interactions

Layer / File(s) Summary
Canvas state and DPI propagation
src/gui/gui_graph_state.h, src/gui/gui_manager.cpp, src/gui/gui_manager.h
GuiGraphState adds target_scrolling, target_zoom, dpi_scale, last_canvas_pos, and canvas_hovered. GuiManager::initialize stores computed dpi_scale to the singleton. GuiManager::audio_engine() getter was added.
Smooth zoom/pan, input handling, and Emscripten font scaling
src/gui/pedal_board_chain.cpp
DeltaTime-based interpolation eases zoom toward target_zoom and scrolling toward target_scrolling; scroll is rescaled on zoom changes. Wheel input runs only when canvas is hovered; Ctrl+wheel sets exponential target_zoom toward cursor. Applies ImGui::SetWindowFontScale divided by dpi_scale on Emscripten paths. Refactors pin/wire/cable and in-progress wire rendering.
Emscripten API exports for gestures and graph ops
src/main.cpp
Adds EMSCRIPTEN_KEEPALIVE exports: canvas gesture handler (on_canvas_touch_gesture), hover/zoom/scroll getters, graph queries (node/link counts, type checks), node/link creation helpers, pin-id lookup by index, and last-deletable-node deletion with node_positions cleanup.
Browser event listeners bridging touch and wheel
web/shell.html
Adds canvas touchstart/touchmove/touchend/touchcancel and wheel handlers that compute pinch/drag and ctrl-wheel zoom and call Module.ccall('on_canvas_touch_gesture', ...). Listeners use { passive: false } and call preventDefault().
E2E test suite and Module typing
tests/web/amplitron.spec.ts
Adds typed global Module declaration for ccall and a "Modular Graph Canvas Interactions" Playwright suite that verifies right-click panning, pinch-zoom, splitter node addition, link creation, and node deletion via simulated input and Module.ccall checks.
Playwright config and CI artifacts / .gitignore
tests/web/playwright.config.ts, .github/workflows/ci.yml, .gitignore
Playwright launch args now choose --use-gl=swiftshader + --disable-gpu in CI or --use-gl=angle locally. CI now always uploads Playwright HTML report and test-results artifact. .gitignore excludes Playwright report artifacts.

Sequence Diagram(s)

sequenceDiagram
  participant Browser as Browser/User
  participant ShellHTML as shell.html (Event Listeners)
  participant EmscriptenAPI as Emscripten API (main.cpp)
  participant PedalBoard as PedalBoard (pedal_board_chain.cpp)
  participant GuiGraphState as GuiGraphState
  participant AudioGraph as Audio Graph (GuiManager)

  Browser->>ShellHTML: two-finger pinch/drag or wheel/right-drag
  ShellHTML->>EmscriptenAPI: on_canvas_touch_gesture(dx, dy, scale, localX, localY)
  EmscriptenAPI->>GuiGraphState: set target_zoom, adjust target_scrolling or set target_scrolling

  PedalBoard->>GuiGraphState: read zoom, target_zoom, scrolling, target_scrolling
  PedalBoard->>PedalBoard: lerp(zoom, target_zoom, DeltaTime) and lerp(scrolling, target_scrolling)
  PedalBoard->>AudioGraph: render nodes/wires with DPI-scaled fonts

  Browser->>ShellHTML: triggers add splitter node
  ShellHTML->>EmscriptenAPI: trigger_add_splitter_node()
  EmscriptenAPI->>AudioGraph: create splitter node (node_count++)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Suggested labels

quality:clean

Suggested reviewers

  • sudip-mondal-2002

"I hopped the canvas, small and spry,
Two fingers pinched the zoom to sky,
Wires and nodes in playful threads,
Tests confirm the UI treads,
A rabbit cheers the web build high!" 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: validation and fixes for the modular graph canvas web demo, which aligns with the primary objective of the PR.
Linked Issues check ✅ Passed The PR substantially addresses linked issue #149: adds canvas zoom/pan animations, DPI scaling, implements touch gesture handling for mobile, adds browser event handlers, exposes C-exported functions for canvas interactions, and includes comprehensive E2E tests for pan/zoom/node operations.
Out of Scope Changes check ✅ Passed All changes are directly scoped to web canvas validation and fixes: DPI scaling, zoom/pan animations, touch/wheel handlers, browser event routing, Playwright test coverage, and CI report uploads. No unrelated refactoring or out-of-scope features detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@bhavyanjain3004 bhavyanjain3004 changed the title fix(web): smooth pan/zoom and touch gestures for modular graph canvas feat:Validate and fix modular graph canvas for Emscripten web demo May 23, 2026
@github-actions

github-actions Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Report 📊

Line Coverage: 79.1%

✅ Coverage meets threshold: 79.1% >= 60%

Full Coverage Summary
Summary coverage rate:
  lines......: 79.1% (3325 of 4203 lines)
  functions..: 89.4% (471 of 527 functions)
  branches...: no data found

@github-actions

github-actions Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

PR Preview Removed

The GitHub Pages preview for this PR has been removed because the PR was closed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
tests/web/amplitron.spec.ts (1)

579-583: ⚡ Quick win

Avoid hard-coded node indices in the cable test.

Using fixed indices (2, 3) couples this test to initial graph shape and can cause brittle failures after unrelated graph-default changes.

Suggested fix
-    const result: number = await page.evaluate(() => {
-      const srcPin = Module.ccall('get_node_output_pin_by_index', 'number', ['number', 'number'], [2, 0]);
-      const dstPin = Module.ccall('get_node_input_pin_by_index', 'number', ['number', 'number'], [3, 0]);
-      return Module.ccall('trigger_add_link', 'number', ['number', 'number'], [srcPin, dstPin]);
-    });
+    const result: number = await page.evaluate(() => {
+      const nodeCount = Module.ccall('get_node_count', 'number', [], []);
+      if (nodeCount < 2) return -1;
+      const srcNodeIndex = nodeCount - 2;
+      const dstNodeIndex = nodeCount - 1;
+      const srcPin = Module.ccall('get_node_output_pin_by_index', 'number', ['number', 'number'], [srcNodeIndex, 0]);
+      const dstPin = Module.ccall('get_node_input_pin_by_index', 'number', ['number', 'number'], [dstNodeIndex, 0]);
+      return Module.ccall('trigger_add_link', 'number', ['number', 'number'], [srcPin, dstPin]);
+    });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/web/amplitron.spec.ts` around lines 579 - 583, The test currently
hard-codes node indices 2 and 3 when creating srcPin/dstPin which makes it
brittle; replace those literals by looking up the node indices dynamically
(e.g., call whatever existing runtime helpers or use Module.ccall to iterate
nodes: get_node_count/get_node_label_by_index or a findNodeIndexByLabel helper)
to find the source and destination node indices, then pass those computed
indices into get_node_output_pin_by_index and get_node_input_pin_by_index before
calling trigger_add_link; update the variables srcPin and dstPin to be derived
from that lookup rather than fixed numbers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/gui/pedal_board_chain.cpp`:
- Around line 27-30: The zoom anchoring is using ImGui::GetMousePos() (screen
coords) against ui_state.scrolling (canvas coords), causing drift; compute the
mouse position in canvas-local coordinates first (mouse_local =
ImGui::GetMousePos() - canvas_screen_origin or
ImGui::GetCursorScreenPos()/window origin used for this canvas), then apply the
scaling: use actual_factor = ui_state.zoom / old_zoom and update
ui_state.scrolling.x and .y with mouse_local (not raw screen pos) so the scroll
transform anchors correctly during zoom. Ensure you reference the same canvas
origin used elsewhere for rendering so the subtraction matches
ui_state.scrolling space.
- Line 15: ui_state.canvas_hovered is being set using
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) which reports hover for
the whole window, causing non-canvas UI to mark the canvas as hovered; replace
that assignment so it tests hover for the actual canvas item/child instead
(e.g., call ImGui::IsItemHovered(...) immediately after the canvas
BeginChild/Canvas widget, or use ImGui::IsWindowHovered with a handle limited to
the canvas child window if you create the canvas via BeginChild) so
ui_state.canvas_hovered reflects only pointer over the canvas itself.

In `@src/main.cpp`:
- Around line 178-189: The trigger_delete_last_node function currently deletes
the last node unconditionally; instead, check the last node's identity or
protection flag before calling graph.remove_node to match the GUI rules. Locate
trigger_delete_last_node and, after obtaining nodes.back(), inspect the node's
name/type or a protection accessor (e.g., node.name, node.type, or a
is_protected/is_deletable method on the node or graph) and return false if it is
a protected node (e.g., "Input" or "Amp Sim") or if the graph’s deletion policy
forbids it; if deletion is allowed, proceed with graph.remove_node(last_id) and
erase node_positions and commit changes as before. If the project has an
existing UI-safe deletion helper, call that instead of graph.remove_node to
preserve invariants.

In `@web/shell.html`:
- Around line 349-353: The empty catch around the
Module.ccall('is_canvas_hovered', 'boolean') call swallows bridge errors; update
the try/catch that sets canvasHovered to catch (err) and log the error
(including err and context like "is_canvas_hovered failed") via console.error or
an existing logger, and optionally set canvasHovered to a safe default; ensure
the code still guards Module && Module.ccall but does not silently ignore
exceptions from the WASM bridge.

---

Nitpick comments:
In `@tests/web/amplitron.spec.ts`:
- Around line 579-583: The test currently hard-codes node indices 2 and 3 when
creating srcPin/dstPin which makes it brittle; replace those literals by looking
up the node indices dynamically (e.g., call whatever existing runtime helpers or
use Module.ccall to iterate nodes: get_node_count/get_node_label_by_index or a
findNodeIndexByLabel helper) to find the source and destination node indices,
then pass those computed indices into get_node_output_pin_by_index and
get_node_input_pin_by_index before calling trigger_add_link; update the
variables srcPin and dstPin to be derived from that lookup rather than fixed
numbers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 910e1830-62a4-4269-827b-1ab72a60c73f

📥 Commits

Reviewing files that changed from the base of the PR and between 8b197e1 and 60e469b.

📒 Files selected for processing (10)
  • .gitignore
  • src/gui/gui_graph_state.h
  • src/gui/gui_manager.cpp
  • src/gui/gui_manager.h
  • src/gui/pedal_board_chain.cpp
  • src/main.cpp
  • tests/web/amplitron.spec.ts
  • tests/web/playwright-report/index.html
  • tests/web/playwright.config.ts
  • web/shell.html

Comment thread src/gui/pedal_board_chain.cpp Outdated
Comment thread src/gui/pedal_board_chain.cpp Outdated
Comment thread src/main.cpp Outdated
Comment thread web/shell.html
@sudip-mondal-2002 sudip-mondal-2002 added type:feature New feature or request GUI Related to the ImGui user interface and UX level:intermediate Intermediate task · 25 GSSoC points platform: web Web/Emscripten-specific issue or feature DAG Related to DAG-based modular signal routing architecture labels May 24, 2026

@MohitBareja16 MohitBareja16 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Code looks fine and web demo works smoothly as well. It only works on the web right? Would be better if you can test it once on your linux/macos/windows and implement the same feature there too.

@bhavyanjain3004

Copy link
Copy Markdown
Contributor Author

@MohitBareja16 The screenrecording I shared is actually from the native macOS desktop app itself and not the web browser. so it works fine.

@MohitBareja16

Copy link
Copy Markdown
Collaborator

@MohitBareja16 The screenrecording I shared is actually from the native macOS desktop app itself and not the web browser. so it works fine.

LGTM then, Nice work!

@MohitBareja16 MohitBareja16 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Zoom in, zoom out working! LGTM!

@MohitBareja16 MohitBareja16 merged commit cd648a0 into sudip-mondal-2002:main May 25, 2026
9 checks passed
github-actions Bot added a commit that referenced this pull request May 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DAG Related to DAG-based modular signal routing architecture gssoc:approved GSSoC 2026 contribution GUI Related to the ImGui user interface and UX level:intermediate Intermediate task · 25 GSSoC points mentor:MohitBareja16 mentor:sudip-mondal-2002 platform: web Web/Emscripten-specific issue or feature quality:exceptional type:feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Validate and fix modular graph canvas for Emscripten web demo

3 participants