Skip to content

Add Electron app with node editor UI#533

Draft
fdb wants to merge 34 commits intorewrite-in-rustfrom
electron-app
Draft

Add Electron app with node editor UI#533
fdb wants to merge 34 commits intorewrite-in-rustfrom
electron-app

Conversation

@fdb
Copy link
Member

@fdb fdb commented Feb 16, 2026

Summary

  • Adds a full Electron + Vite + React desktop app under electron-app/ that replicates the Rust/egui NodeBox UI
  • Implements network canvas with node creation, selection, drag, connections, and rubber-band selection
  • Implements parameter panel with DragValue widgets, point editing, and two-tone label/value columns
  • Implements viewer canvas with pan/zoom, geometry rendering, origin crosshair, colored points, point numbers, and canvas border
  • Implements data viewer, animation bar, address bar, node selection dialog, and about dialog
  • Adds evaluator that produces render results from the node graph
  • Adds file operations (new, open, save) and export (SVG, PNG) via Electron IPC
  • Adds undo/redo history
  • Includes 89 Playwright E2E tests covering all major features
  • Uses Tailwind CSS v4 with a Linear-inspired dark theme matching the Rust version

Test plan

  • npx tsc --noEmit — zero type errors
  • npm run build — clean production build
  • npx playwright test — 88/89 tests pass (1 pre-existing flaky pixel test)
  • Visual comparison against Rust desktop version for parameter panel, viewer, network, and dialogs

🤖 Generated with Claude Code

fdb and others added 30 commits February 16, 2026 00:30
- Add electron-app with React/Zustand/Vite stack
- Extract nodebox-eval crate from nodebox-desktop
- Add nodebox-electron crate for WASM bridge
- Fix preload script loading by using .mjs extension for ESM compat
- Fix E2E test assertions for new layout (no scrubber, document properties panel)
- Add __storeState__ test helper for canvas-based feature testing
- Add setNodePosition, setViewerMode, viewerMode to store slices

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Network: node dragging, rubber band selection, double-click to render,
  connection creation with port hit-testing
- Parameters: DragValue component with drag/click-to-edit/hover modes,
  float/int and point port widgets with data-testid attributes
- Evaluator: recursive graph evaluation with memoization, rect/ellipse/
  colorize/stroke/translate generators
- Data viewer: table view with fill/stroke colors, contour/point counts
- Viewer mode switching between Visual and Data tabs
- 16 new E2E tests (75 total, all passing)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nd missing evaluator nodes

- Smooth zoom with scrollToZoom option, fix bezier rendering, add handles/points display
- Port hover tooltips and highlight, node category icons in network view
- Pane header borders, white parameter text, right-aligned labels
- Animation playback loop with requestAnimationFrame at 30fps
- Add rotate, scale, copy, line, polygon, star, grid, make_point, math ops to evaluator
- Show zoom percentage in viewer header, increase max zoom to 10x

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d animation bar

- Remove duplicate NodeHeader from parameter panel (info already in pane header)
- Add full-width two-tone background columns to parameter panel
- Add inset hover highlight on DragValue widgets
- Add draggable labels to adjust numeric parameter values
- Fix pane header border colors (ZINC_600 top, ZINC_900 bottom)
- Remove spacebar playback toggle (decouple for future hold-to-pan)
- Fix zoom-around-cursor by combining pan/zoom into single state update
- Add ResizeObserver to canvas renderer for proper resize redraws
- Add zoom controls [-][100%][+] to viewer header
- Fix splitters: 2px visual with 8px invisible hit area
- Add category headers and SVG icons to node selection dialog
- Replace frame counter span with draggable DragValue widget

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Right-align labels with justify-end (matching Rust version)
- Add horizontal margin to DragValue hover highlight for proper inset
- Fix shift-drag snap-back: use incremental deltas instead of total
  delta from start, so changing speed modifiers mid-drag only affects
  future movement

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rovements, Tailwind migration

- White SVG icons in node selection dialog via CSS filter
- Procedural category icons on network nodes (diamond, arrow, circle, plus, etc.)
- Persist viewer zoom across Visual/Data mode switches
- Draw origin crosshair on top of geometry
- Colored filled-circle points by type (green/red/blue)
- Point number labels with bitmap digit cache
- Fix DragValue vertical-only margins
- Expand @theme with semantic colors and sizing tokens
- Migrate 8 DOM components from inline styles to Tailwind CSS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 16px gap between point sub-fields (x/y) matching Rust layout
- Add 8px right padding on value containers
- Use lowercase labels matching Rust port names

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clicking the label of a point port starts text editing on the X field.
Committing the edit applies the value to both X and Y.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nd connection drag targets

- Add centerOrigin option to usePanZoom for correct zoom-around-cursor in
  ViewerCanvas (which uses a center-origin coordinate system)
- Remove blue category background rectangles from network nodes, enlarge
  SVG icons from 16px to 24px matching the Rust implementation
- Expand input port hit areas during connection drag to span the entire
  node height, matching the Rust network_view input_rect behavior
- Show port tooltips during connection drag via hover detection with
  expanded hit areas

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ix flaky test

- Add user-select:none, user-drag:none, cursor:default to html for
  native app feel; restore selection on input/textarea/select
- Color connection lines by output port type, make pending connections
  solid instead of dashed
- Refactor NetworkCanvas: simplify NodeIconCache, remove dead fromType
  field, extract duplicate getBoundingClientRect, use else-if for
  mutually exclusive branches
- Simplify usePanZoom zoom anchor calculation
- Fix evaluation test: sample off-center to avoid origin crosshair,
  use toPass() polling instead of fixed sleep

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bundle Inter.ttf in nodebox-core for platform-independent text rendering.
Add text_to_path WASM export, wire JS evaluator to call it, and handle
quadratic bezier curves in the viewer. Fix contour fill to use a single
combined Path2D for correct winding (holes in o/e). Mark textpath paths
as non-editable to suppress handle visualization on font glyph outlines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… node position

- Add StringPortWidget for editable text inputs (e.g. textpath text)
- Add ColorPortWidget with native color picker and hex display
- Show "connected" label for ports with incoming connections
- Fix network canvas initial pan from (200,100) to (8,8) so grid
  position (1,1) visually appears at the first grid cell
- Update E2E test coordinates to match new pan offset

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…Handle

Handles now show an interactive bounding box for rect/ellipse nodes that
allows dragging corners to resize and center to reposition, with undo support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…se throughout

Remove the TypeScript node evaluation implementation (generators.ts) and replace
it with calls to the Rust evaluate_library() WASM function. Convert all TypeScript
types to snake_case to match Rust serde serialization, and adopt the externally-tagged
Value format ({ Float: 100 } instead of { type: 'float', value: 100 }). Update all
components, state management, and E2E tests to use the new naming conventions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the hardcoded 25-node NODE_PROTOTYPES array in NodeSelectionDialog
with Rust's 156 node templates served via WASM. Add create_node() WASM
function that builds fully-configured nodes from templates, and wire it
through the TypeScript bridge so the dialog uses Rust for both the node
catalog and node creation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use serde serialization for port types in get_node_templates() to produce
PascalCase ("Geometry") matching the TypeScript PortType, instead of
as_str() which returns lowercase ("geometry"). Also adds drag-to-empty-space
node creation with auto-connect, disconnect-and-reroute from input ports,
multi-node drag, and keyboard Delete/Backspace for selected nodes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fdb and others added 4 commits February 16, 2026 22:52
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After parsing .ndbx, nodes only contain explicitly overridden ports.
Merge each node's ports with its template's full port list so that
inherited ports (e.g. shape from corevector.filter) are present,
fixing broken connection rendering in NetworkCanvas.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The relative path resolved against the crate root, placing the WASM
output in crates/electron-app/wasm/ instead of electron-app/wasm/.
Use an absolute path to ensure the binary lands in the correct directory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

1 participant