Skip to content

feat: electric mode — spreading activation visualization#124

Open
nvandessel wants to merge 9 commits intomainfrom
feature/electric-graph
Open

feat: electric mode — spreading activation visualization#124
nvandessel wants to merge 9 commits intomainfrom
feature/electric-graph

Conversation

@nvandessel
Copy link
Owner

Summary

  • Adds electric mode to the interactive graph view (floop graph --format html --serve): clicking a node runs the real Go spreading activation engine server-side and animates the results in the browser with flowing particles, node glow, and step-by-step playback controls
  • New Engine.ActivateWithSteps() method captures per-step activation snapshots for animation timeline (initial seed → propagation steps → post-inhibition/sigmoid final)
  • Lightweight HTTP server (visualization.Server) serves the graph HTML and handles /api/activate?seed=<id> requests — zero JS algorithm duplication, no risk of divergence from the Go engine

Architecture

Browser (JS)                    Go Server (localhost)
─────────────                   ────────────────────
Click node "b42"  ──GET────>   /api/activate?seed=b42
                                  │
                                  ├─ Engine.ActivateWithSteps(seed)
                                  │    └─ returns per-step snapshots
                                  │
                  <──JSON────   [{step:0, activation:{...}}, ...]
Animate particles,
glow, playback controls

Changes

File What
internal/spreading/engine.go ActivateWithSteps(), extracted propagateStep()/postProcess() shared methods
internal/spreading/engine_test.go 4 new tests for step snapshots
internal/visualization/server.go New: HTTP server with cached HTML + /api/activate endpoint
internal/visualization/server_test.go New: 5 server endpoint tests
internal/visualization/dot.go RenderHTMLForServer(), APIBaseURL in template data
internal/visualization/dot_test.go Tests for electric mode markers in HTML
internal/visualization/templates/graph.html.tmpl Electric mode CSS + JS (~250 lines): particles, glow, playback toolbar
cmd/floop/cmd_graph.go --serve flag, server lifecycle with graceful shutdown

Usage

# Static export (default, no electric mode)
floop graph --format html

# Server mode with electric activation
floop graph --format html --serve

Test plan

  • go test ./internal/spreading/... — ActivateWithSteps tests pass
  • go test ./internal/visualization/... — server + HTML marker tests pass
  • go test ./... — all 29 packages pass, no regressions
  • Manual: floop graph --format html --serve → click node → particles flow, toolbar works
  • Manual: floop graph --format html → static file export still works (no server)
  • Manual: Ctrl-C cleanly shuts down server

🤖 Generated with Claude Code

@nvandessel nvandessel marked this pull request as draft February 18, 2026 15:52
@greptile-apps
Copy link

greptile-apps bot commented Feb 18, 2026

Greptile Summary

This PR adds electric mode visualization to the graph view, allowing users to click nodes and watch spreading activation propagate in real-time with animated particles and glow effects. The implementation is well-architected: the Go engine was cleanly refactored to expose step-by-step activation snapshots via ActivateWithSteps(), a lightweight HTTP server handles activation requests, and the browser animates the results without duplicating any algorithm logic.

Key changes:

  • Core engine refactored to share propagation logic between Activate() and new ActivateWithSteps() method
  • New HTTP server with graceful shutdown and cached HTML rendering
  • Electric mode JavaScript adds particle system, glow animations, and playback controls (~250 lines)
  • --serve flag enables server mode with electric activation
  • Comprehensive test coverage for engine snapshots and server endpoints
  • Playwright-based integration tests for browser animation

Minor issues already noted in previous review threads:

  • Store errors masked as 404 in server.go:125
  • --serve flag silently ignored for non-HTML formats
  • No error handling on fetch() call in template

Confidence Score: 4/5

  • Safe to merge with comprehensive tests, but three minor issues from previous review should be addressed for production readiness
  • The core implementation is solid with excellent test coverage (29 packages passing, 4 new engine tests, 5 server tests, Playwright integration tests). The refactoring of propagation logic is clean and maintains backward compatibility. However, three issues already identified in previous threads should be addressed: error handling conflation (500 vs 404), silent flag validation, and missing fetch error handling. These don't affect correctness but impact debuggability and user experience.
  • internal/visualization/server.go (error handling), cmd/floop/cmd_graph.go (flag validation), internal/visualization/templates/graph.html.tmpl (fetch error handling) — all have issues noted in previous review threads

Important Files Changed

Filename Overview
internal/spreading/engine.go Adds ActivateWithSteps() method and refactors core propagation logic into reusable propagateStep() and postProcess() helpers — clean extraction with proper synchronous updates
internal/spreading/engine_test.go Adds 4 comprehensive tests for ActivateWithSteps() covering linear chains, snapshot independence, sigmoid application, and empty seeds edge case
internal/visualization/server.go New HTTP server with cached HTML rendering and /api/activate endpoint — graceful shutdown implemented correctly, minor error handling issue noted in previous review
internal/visualization/server_test.go Comprehensive test suite covering server startup, HTML serving, activation endpoint with valid/invalid seeds, and graceful shutdown
internal/visualization/dot.go Adds RenderHTMLForServer() variant that embeds API base URL for electric mode — clean separation between static and server modes
internal/visualization/dot_test.go Adds tests verifying electric mode markers appear in server HTML but not in static HTML exports
internal/visualization/templates/graph.html.tmpl Adds ~250 lines of electric mode CSS and JavaScript including particle animation, glow effects, playback controls — no error handling on fetch call noted in previous review
cmd/floop/cmd_graph.go Adds --serve flag with server lifecycle management and graceful shutdown — minor issue with flag validation for non-HTML formats noted in previous review

Sequence Diagram

sequenceDiagram
    participant Browser
    participant Server as Go HTTP Server
    participant Engine as Spreading Engine
    participant Store as Graph Store

    Browser->>Server: GET /
    Server->>Store: GetNodes(), GetEdges()
    Store-->>Server: Graph data
    Server->>Server: RenderHTMLForServer(apiBaseURL)
    Server-->>Browser: HTML + embedded graph JSON

    Note over Browser: User clicks node "b42"

    Browser->>Server: GET /api/activate?seed=b42
    Server->>Store: GetNode(b42)
    Store-->>Server: Node exists
    Server->>Engine: ActivateWithSteps([{b42, 1.0}])
    
    Engine->>Engine: Step 0: Initialize seed
    loop For each propagation step
        Engine->>Store: GetEdges(active nodes)
        Store-->>Engine: Edge list
        Engine->>Engine: propagateStep()
        Engine->>Engine: Capture snapshot
    end
    
    Engine->>Engine: postProcess() - inhibition + sigmoid
    Engine-->>Server: []StepSnapshot (JSON)
    Server-->>Browser: Step-by-step activation data

    Note over Browser: Animate particles, glow, playback controls
Loading

Last reviewed commit: 7e18797

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

8 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@nvandessel
Copy link
Owner Author

New commit: reduce spark size and improve edge visibility

Smaller sparks:

  • Base radius: 6 + sparkBright * 63 + sparkBright * 3 (halved)
  • Halo multiplier: 2.5x1.8x, core: 1.8x1.2x
  • Halo opacity reduced for subtler bloom

Better edge visibility:

  • Fallback opacity: 0.100.18
  • Energy decay floor: 00.06 (edges never fully vanish)
  • Residual glow factor: 0.150.25

All 18 visual tests pass. Ready for visual review — run floop graph --format html --serve to check live.

@nvandessel nvandessel force-pushed the feature/electric-graph branch from 54efba1 to 7e18797 Compare February 20, 2026 03:08
@nvandessel nvandessel marked this pull request as ready for review February 20, 2026 03:11
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

nvandessel and others added 9 commits February 19, 2026 19:32
… view

Click a node in the HTML graph to see real spreading activation propagate
through the behavior graph. The Go engine runs server-side on each click;
JavaScript handles only animation and playback controls.

- Add ActivateWithSteps() to spreading engine (per-step snapshots)
- Add HTTP server (visualization/server.go) with /api/activate endpoint
- cmd_graph.go: server mode by default, --output for static export
- Electric mode JS: particles, glow, playback toolbar, test helpers
- APIBaseURL in template data to toggle electric vs focus mode

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- H1: Add --serve flag (opt-in server mode), keep temp-file as default
- H2: Fix signal goroutine leak with defer signal.Stop
- H3: Extract propagateStep/postProcess to eliminate duplication
- H4: Use generic error messages in HTTP responses
- M1: Restrict handlers to GET method only
- M2: Pre-render and cache HTML at server startup
- M3: Remove seed ID echo from 404 response
- M5: Restore security comments in dot.go
- M6: Remove duplicate onNodeClick/onBackgroundClick handlers
- L3: Add null guard in linkDirectionalParticleWidth
- L5: Fix shadowed ctx in TestServer_ActivateEndpoint
- L8: Create engine once in NewServer, reuse per request
- M4: Drain errCh in server tests via t.Cleanup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The spark rendering code (comet trails, glowing tips, ember particles)
was never executing because force-graph v1.51.1's linkCanvasObject
callback is never invoked despite the API existing. Migrated all spark
rendering to onRenderFramePost which fires at 60fps.

Also fixed nodeFirstStep threshold (0.01 → 0) so neighbor nodes with
small activation values get tracked for spark timing, and added
Playwright visual test infrastructure for electric mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Eliminate all ctx.shadowBlur calls (3 sites) — replaced with gradient-only
  equivalents. Shadow compositing is the heaviest Canvas 2D operation.
- Memoize getElectricProgress() per frame — eliminates ~970 redundant
  computations per frame via cached wrapper.
- Cache getEdgeWaveEnergy() results per frame — reduces edge energy
  computations from 3E to E per frame.
- Switch autoPauseRedraw default to true — zero CPU cost when idle.
  Electric mode toggles it on/off as needed.
- Remove cooldownTime(Infinity) — let physics naturally settle.
- Add FPS diagnostic counter with on-screen overlay (press F to toggle)
  and window.__getElectricFPS() test helper.

Estimated combined impact: +18-33 FPS during electric mode animation.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…ps (#133)

- Replace edge wire illumination and comet trail LinearGradients with
  solid rgba() strokes — eliminates ~9,600 gradient object allocations
  per second during electric mode animation.
- Merge electricUILoop rAF into onRenderFramePost — single animation
  loop instead of dual, reducing rAF overhead.
- Capture Date.now() once per frame (_frameNow) for ripple phase,
  avoiding repeated syscalls inside the per-node rendering loop.
- Reduce ember particles from 4 to 2 per edge — halves particle draw
  calls with minimal visual difference.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sparks were larger than nodes (up to 60px halo vs 5-16px nodes) — halved
base radius and tightened halo/core multipliers. Edges were dropping to
10% opacity away from the wave front — raised fallback to 18%, added 0.06
energy floor, and increased residual glow factor.

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>
@nvandessel nvandessel force-pushed the feature/electric-graph branch from 07cf88d to 78c0393 Compare February 20, 2026 03:32
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

Comments