Cluster gravity: per-cluster centroid pull force in the engine
The 'virtual node' realized as a centroid force: two allocation-free O(n) passes per tick (membership resolved once at sim creation; Float64Array sums). Measured indistinguishable from force-off at 338 nodes (271ms vs 272ms per 400-tick settle). - createGraphSimulation: SimOptions.clusterPull + linkStrength + velocityDecay (physics controls plumbing); degree-scaled link stiffness so linkStrength=1 is exactly d3's default - settleGraphLayout split into layout-settle.ts (it computes the Louvain partition for the pull); layout.ts stays browser-barrel-pure - barrel no longer re-exports clusters.ts: graphology + louvain are fully out of the client bundle (verified against built chunks) - replay passes the per-batch partition; CLUSTER_PULL_STRENGTH=0.15 tuned by sweep: cluster spread 63->36 world units, centroid separation and total span unchanged (no blob merge, no collapse)
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
* npx tsx scripts/replay-layout.ts
|
||||
*/
|
||||
import { graphStore } from "../src/store/graph.ts";
|
||||
import { detectCommunities } from "../src/core/clusters.ts";
|
||||
import { incrementalLayout } from "../src/core/layout.ts";
|
||||
import type { GraphNode, NodeMapping, Position } from "../src/core/contracts.ts";
|
||||
|
||||
@@ -69,11 +70,11 @@ function main() {
|
||||
const activeEdges = edges.filter((e) => delivered.has(e.from) && delivered.has(e.to));
|
||||
|
||||
const before = new Map(positions);
|
||||
positions = incrementalLayout(
|
||||
nodes.filter((n) => delivered.has(n.id)),
|
||||
activeEdges,
|
||||
positions,
|
||||
);
|
||||
const batchNodes = nodes.filter((n) => delivered.has(n.id));
|
||||
positions = incrementalLayout(batchNodes, activeEdges, positions, {
|
||||
// The same partition the real settle would see for this batch.
|
||||
clusters: detectCommunities(batchNodes, activeEdges).communities,
|
||||
});
|
||||
for (const [id, prev] of before) {
|
||||
const now = positions.get(id)!;
|
||||
const shift = Math.hypot(prev.x - now.x, prev.y - now.y);
|
||||
|
||||
Reference in New Issue
Block a user