World/Brain: denser breathing mesh — support neurons + resting shimmer
Hierarchy (neural-brain) v2: - structure nodes (org/company/team) join as dim support-neurons, so the brain has body even with one or two agents (a real mesh, not a few dots). - a resting-state shimmer: every neuron occasionally self-activates a touch, so a dormant brain still breathes. - agents brighten on working status AND on a recent touch (real activity), then fire signals along pathways that chain through the support mesh. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
3b012b12bf
commit
9725d620cf
@@ -395,30 +395,43 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
|||||||
// Neural-brain view: agents are neurons in a dormant mesh; active agents fire
|
// Neural-brain view: agents are neurons in a dormant mesh; active agents fire
|
||||||
// signals along pathways to neighbors (chaining), so the brain comes alive.
|
// signals along pathways to neighbors (chaining), so the brain comes alive.
|
||||||
const renderBrain = (dt: number) => {
|
const renderBrain = (dt: number) => {
|
||||||
const ids: string[] = [];
|
// Neurons = agents (bright, drive firing) + structure nodes (org/company/
|
||||||
const seen = new Set<string>();
|
// team) as a dim support mesh, so even a near-idle brain has body.
|
||||||
|
type Neuron = { id: string; color: string; agent: boolean; boost: number };
|
||||||
|
const neurons: Neuron[] = [];
|
||||||
for (const p of engine.pawns.values()) {
|
for (const p of engine.pawns.values()) {
|
||||||
ids.push(p.id);
|
const recent = p.idle < 2.5 ? 1 : 0; // a recent touch lights the neuron
|
||||||
seen.add(p.id);
|
neurons.push({ id: p.id, color: p.color, agent: true, boost: (p.status === "working" ? 0.9 : 0) + recent });
|
||||||
if (!brainPositions.has(p.id)) brainPositions.set(p.id, neuronPos(p.id));
|
}
|
||||||
const pos = brainPositions.get(p.id)!;
|
for (const n of engine.nodes.values()) {
|
||||||
let g = neuronGlows.get(p.id);
|
if (n.tier === "org" || n.tier === "company" || n.tier === "team")
|
||||||
|
neurons.push({ id: n.id, color: n.color, agent: false, boost: n.heat });
|
||||||
|
}
|
||||||
|
const ids = neurons.map((n) => n.id);
|
||||||
|
const seen = new Set(ids);
|
||||||
|
for (const ne of neurons) {
|
||||||
|
if (!brainPositions.has(ne.id)) brainPositions.set(ne.id, neuronPos(ne.id));
|
||||||
|
const pos = brainPositions.get(ne.id)!;
|
||||||
|
let g = neuronGlows.get(ne.id);
|
||||||
if (!g) {
|
if (!g) {
|
||||||
g = newGlow(brainGroup);
|
g = newGlow(brainGroup);
|
||||||
neuronGlows.set(p.id, g);
|
neuronGlows.set(ne.id, g);
|
||||||
}
|
}
|
||||||
let act = neuronAct.get(p.id) ?? 0.06;
|
let act = neuronAct.get(ne.id) ?? (ne.agent ? 0.06 : 0.03);
|
||||||
if (p.status === "working") act = Math.min(1, act + dt * 0.9);
|
act = Math.min(1, act + ne.boost * dt * 1.3);
|
||||||
act = Math.max(0.06, act - dt * 0.22);
|
if (Math.random() < dt * 0.5) act = Math.min(1, act + 0.08); // resting shimmer → the brain breathes
|
||||||
neuronAct.set(p.id, act);
|
act = Math.max(ne.agent ? 0.06 : 0.025, act - dt * 0.22);
|
||||||
|
neuronAct.set(ne.id, act);
|
||||||
g.position.copy(pos);
|
g.position.copy(pos);
|
||||||
const gs = 16 + act * 36;
|
const base = ne.agent ? 16 : 8;
|
||||||
|
const gs = base + act * (ne.agent ? 36 : 16);
|
||||||
g.scale.set(gs, gs, 1);
|
g.scale.set(gs, gs, 1);
|
||||||
const gm = g.material as THREE.SpriteMaterial;
|
const gm = g.material as THREE.SpriteMaterial;
|
||||||
gm.color.set(p.color);
|
gm.color.set(ne.color);
|
||||||
gm.opacity = 0.18 + act * 0.82;
|
gm.opacity = (ne.agent ? 0.16 : 0.06) + act * (ne.agent ? 0.84 : 0.5);
|
||||||
const nbrs = brainAdj.get(p.id);
|
// fire a signal along a pathway (chaining through the mesh)
|
||||||
if (nbrs && nbrs.length && Math.random() < act * dt * 7) {
|
const nbrs = brainAdj.get(ne.id);
|
||||||
|
if (nbrs && nbrs.length && Math.random() < act * dt * (ne.agent ? 7 : 3.5)) {
|
||||||
const tid = nbrs[(Math.random() * nbrs.length) | 0];
|
const tid = nbrs[(Math.random() * nbrs.length) | 0];
|
||||||
const tp = brainPositions.get(tid);
|
const tp = brainPositions.get(tid);
|
||||||
if (tp) {
|
if (tp) {
|
||||||
@@ -427,8 +440,8 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
|||||||
const dz = tp.z - pos.z;
|
const dz = tp.z - pos.z;
|
||||||
const len = Math.hypot(dx, dy, dz) || 1;
|
const len = Math.hypot(dx, dy, dz) || 1;
|
||||||
const speed = 150;
|
const speed = 150;
|
||||||
spawn(pos.x, pos.y, pos.z, p.color, (dx / len) * speed, (dy / len) * speed, (dz / len) * speed, speed / len + 0.25);
|
spawn(pos.x, pos.y, pos.z, ne.color, (dx / len) * speed, (dy / len) * speed, (dz / len) * speed, speed / len + 0.25);
|
||||||
neuronAct.set(tid, Math.min(1, (neuronAct.get(tid) ?? 0.06) + 0.12));
|
neuronAct.set(tid, Math.min(1, (neuronAct.get(tid) ?? 0.05) + 0.14));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user