mirror of
https://github.com/samvallad33/vestige.git
synced 2026-04-26 09:16:21 +02:00
feat: live memory materialization — nodes spawn in 3D graph in real-time
When memories are created, promoted, deleted, or dreamed via MCP tools, the 3D graph now shows spectacular live animations: - Rainbow particle burst + elastic scale-up on MemoryCreated - Ripple wave cascading to nearby nodes - Green pulse + node growth on MemoryPromoted - Implosion + dissolution on MemoryDeleted - Edge growth animation on ConnectionDiscovered - Purple cascade on DreamStarted/DreamProgress/DreamCompleted - FIFO eviction at 50 live nodes to guard performance Also: graph center defaults to most-connected node, legacy HTML redirects to SvelteKit dashboard, CSS height chain fix in layout. Testing: 150 unit tests (vitest), 11 e2e tests (Playwright with MCP Streamable HTTP client), 22 proof screenshots. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
816b577f69
commit
9bdcc69ce3
76 changed files with 5915 additions and 332 deletions
|
|
@ -8,7 +8,7 @@
|
|||
import { ParticleSystem } from '$lib/graph/particles';
|
||||
import { EffectManager } from '$lib/graph/effects';
|
||||
import { DreamMode } from '$lib/graph/dream-mode';
|
||||
import { mapEventToEffects } from '$lib/graph/events';
|
||||
import { mapEventToEffects, type GraphMutationContext, type GraphMutation } from '$lib/graph/events';
|
||||
import { createNebulaBackground, updateNebula } from '$lib/graph/shaders/nebula.frag';
|
||||
import { createPostProcessing, updatePostProcessing, type PostProcessingStack } from '$lib/graph/shaders/post-processing';
|
||||
import type * as THREE from 'three';
|
||||
|
|
@ -20,9 +20,10 @@
|
|||
events?: VestigeEvent[];
|
||||
isDreaming?: boolean;
|
||||
onSelect?: (nodeId: string) => void;
|
||||
onGraphMutation?: (mutation: GraphMutation) => void;
|
||||
}
|
||||
|
||||
let { nodes, edges, centerId, events = [], isDreaming = false, onSelect }: Props = $props();
|
||||
let { nodes, edges, centerId, events = [], isDreaming = false, onSelect, onGraphMutation }: Props = $props();
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let ctx: SceneContext;
|
||||
|
|
@ -41,6 +42,9 @@
|
|||
// Event tracking
|
||||
let processedEventCount = 0;
|
||||
|
||||
// Internal tracking: initial nodes + live-added nodes
|
||||
let allNodes: GraphNode[] = [];
|
||||
|
||||
onMount(() => {
|
||||
ctx = createScene(container);
|
||||
|
||||
|
|
@ -63,6 +67,9 @@
|
|||
edgeManager.createEdges(edges, positions);
|
||||
forceSim = new ForceSimulation(positions);
|
||||
|
||||
// Track all nodes (initial set)
|
||||
allNodes = [...nodes];
|
||||
|
||||
ctx.scene.add(edgeManager.group);
|
||||
ctx.scene.add(nodeManager.group);
|
||||
|
||||
|
|
@ -96,9 +103,12 @@
|
|||
nodeManager.updatePositions();
|
||||
edgeManager.updatePositions(nodeManager.positions);
|
||||
|
||||
// Animate edge growth/dissolution
|
||||
edgeManager.animateEdges(nodeManager.positions);
|
||||
|
||||
// Animate
|
||||
particles.animate(time);
|
||||
nodeManager.animate(time, nodes, ctx.camera);
|
||||
nodeManager.animate(time, allNodes, ctx.camera);
|
||||
|
||||
// Dream mode
|
||||
dreamMode.setActive(isDreaming);
|
||||
|
|
@ -116,7 +126,7 @@
|
|||
|
||||
// Events + effects
|
||||
processEvents();
|
||||
effects.update(nodeManager.meshMap, ctx.camera);
|
||||
effects.update(nodeManager.meshMap, ctx.camera, nodeManager.positions);
|
||||
|
||||
ctx.controls.update();
|
||||
ctx.composer.render();
|
||||
|
|
@ -128,8 +138,26 @@
|
|||
const newEvents = events.slice(processedEventCount);
|
||||
processedEventCount = events.length;
|
||||
|
||||
const mutationCtx: GraphMutationContext = {
|
||||
effects,
|
||||
nodeManager,
|
||||
edgeManager,
|
||||
forceSim,
|
||||
camera: ctx.camera,
|
||||
onMutation: (mutation: GraphMutation) => {
|
||||
// Update internal allNodes tracking
|
||||
if (mutation.type === 'nodeAdded') {
|
||||
allNodes = [...allNodes, mutation.node];
|
||||
} else if (mutation.type === 'nodeRemoved') {
|
||||
allNodes = allNodes.filter((n) => n.id !== mutation.nodeId);
|
||||
}
|
||||
// Notify parent
|
||||
onGraphMutation?.(mutation);
|
||||
},
|
||||
};
|
||||
|
||||
for (const event of newEvents) {
|
||||
mapEventToEffects(event, effects, nodeManager.positions, nodeManager.meshMap, ctx.camera);
|
||||
mapEventToEffects(event, mutationCtx, allNodes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue