Skip to content

feat(viz): Phase 2 — particles, ripple/pulse, ownership mode, time scrubber, guided tour#1

Open
Enreign wants to merge 48 commits intomainfrom
viz/phase-2
Open

feat(viz): Phase 2 — particles, ripple/pulse, ownership mode, time scrubber, guided tour#1
Enreign wants to merge 48 commits intomainfrom
viz/phase-2

Conversation

@Enreign
Copy link
Copy Markdown
Contributor

@Enreign Enreign commented Mar 16, 2026

Summary

Phase 2 — Visualization Enhancements

  • Animated blast radius ripple/pulse — node selection triggers a depth-by-depth wave animation (Phase A) followed by continuous brightness oscillation per-depth (Phase B), replacing the static highlight
  • Co-change particle flow — when the co-change layer is enabled, selecting a node streams particles along Bezier arcs to its historically co-changed files, with speed proportional to co-change confidence
  • Ownership mode — third visualization mode recolors nodes by code owner (djb2 hash into 16-color palette) and regions by plurality owner, with a live legend
  • Time scrubber — histogram overlay shows commit activity over time; dragging the handle left dims files with no activity before the cutoff date
  • Guided tour — 5-step first-visit walkthrough with flyTo animations and step cards

Unified Filters

  • Owner filter — click any owner row in the ownership legend to dim all non-matching nodes; chip appears in stats panel; clicking same row toggles off
  • Risk filter — Low/Med/High band preset buttons + continuous slider in the risk legend; cross-mode
  • Connectivity filters — degree slider and 3-hop reachable count slider, always visible in stats panel
  • All filters compose — a node must pass every active filter and the time scrubber to be bright
  • Persistent chips — each active filter shows a dismissible chip; clearing one filter leaves others unaffected

Test Plan

  • Load viz with OpenClaw data (297 owners, 6566 files)
  • Switch to Ownership mode → click owner row → non-owner nodes dim, chip appears
  • Click same owner row again → filter clears
  • Switch to Risk mode → click band button → matching nodes stay bright, chip shows ≥ N%
  • Drag risk slider continuously → dimming updates in real time
  • Drag degree slider to > 0 → only high-degree nodes stay bright
  • Drag reachable slider → only well-connected nodes stay bright
  • Switch modes while filter active → filter persists across architecture/risk/ownership
  • Enable time scrubber + set owner filter → node must pass both to be bright
  • Click × on chip → that filter clears, others unaffected
  • Escape key → clears node selection, filters unaffected

🤖 Generated with Claude Code

Enreign and others added 30 commits March 16, 2026 00:48
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…k score

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds colors.js with DIR_COLORS palette and riskColor interpolation,
layout.js with computeLayout() that maps data.tree into 1000x1000
world-space fileNodes and regions, and wires both into main.js.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After a window resize, camera bounds are updated but camInitial was
stale, causing incorrect zoom computation. Fix by registering a resize
callback from interaction.js that refreshes camInitial and resets pan/zoom.

Also removes unused imports: getInstancedMesh, dirColor, filePositions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces D3/SVG force-directed viz with Three.js orthographic treemap.
- Data pipeline: SQLite → data.json with risk scores and co-change data
- Hierarchical treemap layout via d3-hierarchy
- Instanced WebGL rendering with bloom post-processing
- Architecture and Risk display modes
- GPU color-buffer node picking
- BFS blast radius on selection
- Search with autocomplete
- Stats panel, hotspot list, selection detail panel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enreign and others added 18 commits March 16, 2026 10:52
… doc

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…vity, owner rows

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bug 1 (search): Add Enter key handler to navigate to first result when
the dropdown is visible. Previously pressing Enter did nothing, so users
had to click results manually.

Bug 2 (scrubber): Hide the scrubber bar when commits.first === commits.last
(zero temporal range) instead of showing a bar that doesn't respond to
dragging. Also fix the root cause in the Rust indexer: co-change edges
now store the actual git commit timestamp (CommitInfo.timestamp) via the
new add_cochange_edge method, rather than the indexing time (Utc::now).
This produces meaningful temporal spread in data.json after re-indexing.

Bug 3 (co-change sparsity): Lower the default cochange threshold in
viz.py from 0.25 to 0.10 so more pairs survive the filter on repositories
with limited commit history. Users can still pass --cochange-threshold
to override.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Re-indexed cartograph itself with the fixed add_cochange_edge method.
Co-change edges now store actual git commit timestamps rather than
indexing time. 153 co-change pairs at threshold 0.10 (vs 30 at 0.25).

Scrubber stays hidden (first === last) because this repo's entire
history falls within one calendar month (March 2026). On a production
repo with years of history, the scrubber will show real temporal spread.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ory)

Indexed openclaw: 6566 TypeScript files, 10k commits, 563 co-change
pairs at threshold 0.10.

- commits: 2 buckets (Feb 2026, Mar 2026) — scrubber now functional
- cochange_by_node: 399 nodes with partners (vs 30 on cartograph itself)
- owners: 298

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The hardcoded 10k cap was cutting off history for large repos. OpenClaw
has 19k commits — all fell in Feb-Mar 2026 with the old cap, giving the
scrubber only 2 months.

--max-commits defaults to 50000 (0 = no limit). The internal safety cap
in commits.rs is raised to 100k since the CLI now owns the policy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…its)

Full 19,558-commit history mined (vs previous 10k cap).
- commits: 3 buckets Jan–Mar 2026 (vs 2 before) — scrubber spans 3 months
- cochange_by_node: 222 nodes (vs 399 at 10k cap — normalized confidence
  shifts with more commits, fewer pairs clear the 0.10 threshold)
- 302 co-change edges at threshold 0.10

Older commits (Nov–Dec 2025) touch files since renamed/deleted; those
paths have no entity match so they don't produce co-change edges.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously, only files matching current paths produced co-change edges.
Files renamed or moved had their entire pre-rename history ignored,
limiting the scrubber to Jan-Mar 2026 for openclaw despite commits
going back to Nov 2025.

Changes:
- commits.rs: add ChangeKind::Renamed { old_path } and parse R<score>
  lines properly (was silently discarding old_path)
- cochange.rs: build_rename_map() walks commits newest-first to build
  old_path → current_path resolution, with chained rename support.
  analyze_cochanges() resolves all historical paths before creating
  pairs, and skips deleted files.
- main.rs: --max-commits flag already in place from previous commit

Tests: test_rename_tracking_merges_history, test_deleted_files_excluded,
test_parse_rename_lines all pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ltered

build_commits() was receiving only the high-confidence edges (>=0.10),
which were all from Jan-Mar 2026. The scrubber never showed older months
even when the DB had edges going back to Nov 2025.

Fix: load_entities_and_edges() now returns temporal_cochange_edges
(threshold=0) alongside the normal cochange_edges. build_data() passes
temporal_cochange_edges to build_commits() so the scrubber reflects the
full activity history of the codebase.

Result for openclaw: 5 months (Nov 2025 - Mar 2026) vs 3 before.

Co-Authored-By: Claude Sonnet 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