feat(mnemosyne): integrate ambient particle system into Nexus

- Import MemoryParticles component
- Init after SpatialMemory, wire onMemoryPlaced callback
- Update in animation loop
- Spawn burst on memory placement (via callback)
- Access trail on crystal click and navigate
- Category colors for all particles
This commit is contained in:
2026-04-11 00:50:43 +00:00
parent 0bf810f1e8
commit dc88f1b834

20
app.js
View File

@@ -8,6 +8,7 @@ import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js';
import { SpatialMemory } from './nexus/components/spatial-memory.js';
import { SessionRooms } from './nexus/components/session-rooms.js';
import { TimelineScrubber } from './nexus/components/timeline-scrubber.js';
import { MemoryParticles } from './nexus/components/memory-particles.js';
// ═══════════════════════════════════════════
// NEXUS v1.1 — Portal System Update
@@ -709,6 +710,8 @@ async function init() {
createWorkshopTerminal();
createAshStorm();
SpatialMemory.init(scene);
MemoryParticles.init(scene);
SpatialMemory.setOnMemoryPlaced(MemoryParticles.onMemoryPlaced);
TimelineScrubber.init(SpatialMemory);
SessionRooms.init(scene, camera, null);
updateLoad(90);
@@ -1915,6 +1918,10 @@ function setupControls() {
const memInfo = SpatialMemory.getMemoryFromMesh(hitMesh);
if (memInfo) {
SpatialMemory.highlightMemory(memInfo.data.id);
// Memory access trail particles
if (camera) {
MemoryParticles.onMemoryAccessed(camera.position, hitMesh.position, memInfo.data.category || memInfo.region || 'working');
}
showMemoryPanel(memInfo, e.clientX, e.clientY);
return;
}
@@ -2770,6 +2777,18 @@ function _positionPanel(panel, clickX, clickY) {
function _navigateToMemory(memId) {
SpatialMemory.highlightMemory(memId);
addChatMessage('system', `Focus: ${memId.replace(/_/g, ' ')}`);
// Access trail particles
const meshes = SpatialMemory.getCrystalMeshes();
for (const mesh of meshes) {
if (mesh.userData && mesh.userData.memId === memId) {
const memInfo = SpatialMemory.getMemoryFromMesh(mesh);
if (memInfo && camera) {
MemoryParticles.onMemoryAccessed(camera.position, mesh.position, memInfo.data.category || memInfo.region || 'working');
}
break;
}
}
const meshes = SpatialMemory.getCrystalMeshes();
for (const mesh of meshes) {
if (mesh.userData && mesh.userData.memId === memId) {
@@ -2975,6 +2994,7 @@ function gameLoop() {
// Project Mnemosyne - Memory Orb Animation
if (typeof animateMemoryOrbs === 'function') {
SpatialMemory.update(delta);
MemoryParticles.update(delta);
TimelineScrubber.update();
animateMemoryOrbs(delta);
}