World/Brain: signals colored by activity type (think/tool/file/run)
Each agent carries a fireColor for its most recent activity — reasoning (purple), tool (cyan), file op (coral), run (green) — derived in the engine from the touch weight/node + reasoning events (now wired into the engine). The brain fires signals in that colour, and the HUD shows a small colour key in Hierarchy, so you can read WHAT KIND of work is lighting up the 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
b9d3fc4f44
commit
86524cb309
@@ -181,6 +181,7 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
||||
live.on("agent.status", (d) => e.onStatus(d)),
|
||||
live.on("world.touch", (d) => e.onTouch(d)),
|
||||
live.on("node.activity", (d) => e.onNodeActivity(d)),
|
||||
live.on("agent.reasoning.delta", (d) => e.onReasoning(d.agentId)),
|
||||
];
|
||||
return () => offs.forEach((off) => off());
|
||||
}, [live, mode]);
|
||||
@@ -434,15 +435,15 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
||||
const renderBrain = (dt: number) => {
|
||||
// Neurons = agents (bright, drive firing) + structure nodes (org/company/
|
||||
// team) as a dim support mesh, so even a near-idle brain has body.
|
||||
type Neuron = { id: string; color: string; agent: boolean; boost: number };
|
||||
type Neuron = { id: string; color: string; fire: string; agent: boolean; boost: number };
|
||||
const neurons: Neuron[] = [];
|
||||
for (const p of engine.pawns.values()) {
|
||||
const recent = p.idle < 2.5 ? 1 : 0; // a recent touch lights the neuron
|
||||
neurons.push({ id: p.id, color: p.color, agent: true, boost: (p.status === "working" ? 0.9 : 0) + recent });
|
||||
neurons.push({ id: p.id, color: p.color, fire: p.fireColor ?? p.color, agent: true, boost: (p.status === "working" ? 0.9 : 0) + recent });
|
||||
}
|
||||
for (const n of engine.nodes.values()) {
|
||||
if (n.tier === "org" || n.tier === "company" || n.tier === "team")
|
||||
neurons.push({ id: n.id, color: n.color, agent: false, boost: n.heat });
|
||||
neurons.push({ id: n.id, color: n.color, fire: n.color, agent: false, boost: n.heat });
|
||||
}
|
||||
const ids = neurons.map((n) => n.id);
|
||||
const seen = new Set(ids);
|
||||
@@ -480,7 +481,7 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
||||
const dz = tp.z - pos.z;
|
||||
const len = Math.hypot(dx, dy, dz) || 1;
|
||||
const speed = 150;
|
||||
spawn(pos.x, pos.y, pos.z, ne.color, (dx / len) * speed, (dy / len) * speed, (dz / len) * speed, speed / len + 0.25);
|
||||
spawn(pos.x, pos.y, pos.z, ne.fire, (dx / len) * speed, (dy / len) * speed, (dz / len) * speed, speed / len + 0.25);
|
||||
neuronAct.set(tid, Math.min(1, (neuronAct.get(tid) ?? 0.05) + 0.14));
|
||||
}
|
||||
}
|
||||
@@ -928,6 +929,16 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
{formation === "hierarchy" ? (
|
||||
<div style={{ display: "flex", gap: 8, marginTop: 5, fontSize: 9, color: "#8a8a92", flexWrap: "wrap" }}>
|
||||
{([["#c98af0", "think"], ["#5ec8d8", "tool"], ["#ff6f61", "file"], ["#5fd08a", "run"]] as const).map(([c, l]) => (
|
||||
<span key={l} style={{ display: "flex", alignItems: "center", gap: 3 }}>
|
||||
<span style={{ width: 6, height: 6, borderRadius: "50%", background: c }} />
|
||||
{l}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{/* WorldClock — live ⇄ replay (Gource-style playback of run history) */}
|
||||
<div
|
||||
|
||||
@@ -44,6 +44,7 @@ export interface GPawn {
|
||||
idle: number;
|
||||
alpha: number;
|
||||
retime: number;
|
||||
fireColor?: string; // colour of this agent's most recent activity (type)
|
||||
}
|
||||
|
||||
export interface Beam {
|
||||
@@ -205,6 +206,16 @@ export class WorldEngine {
|
||||
const w = e.weight ?? 0.5;
|
||||
node.heat = Math.min(1, node.heat + 0.5);
|
||||
node.burst = Math.max(node.burst, w); // file ops (weight 1) → explosive burst
|
||||
// activity type → signal colour: file=coral, tool=cyan, run=green
|
||||
if (e.nodeId.startsWith("tool:")) p.fireColor = w >= 0.9 ? "#ff6f61" : "#5ec8d8";
|
||||
else if (e.nodeId.startsWith("run:")) p.fireColor = "#5fd08a";
|
||||
}
|
||||
|
||||
/** A reasoning token from an agent — marks it active and tints its signals. */
|
||||
onReasoning(agentId: string) {
|
||||
const p = this.ensurePawn(agentId);
|
||||
p.fireColor = "#c98af0"; // think = purple
|
||||
p.idle = 0;
|
||||
}
|
||||
onNodeActivity(e: TaxonomyEvents["node.activity"]) {
|
||||
const node = this.ensureNode(e.nodeId, e.kind === "event" ? "event" : "service", e.label ?? e.nodeId, ROOT, 1);
|
||||
|
||||
Reference in New Issue
Block a user