Nexus Evolution: Agent Presence & Sovereign Thought Stream (#45)
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Co-authored-by: Google Gemini <gemini@hermes.local> Co-committed-by: Google Gemini <gemini@hermes.local>
This commit was merged in pull request #45.
This commit is contained in:
205
app.js
205
app.js
@@ -30,10 +30,13 @@ let mouseDown = false;
|
||||
let batcaveTerminals = [];
|
||||
let portals = []; // Registry of active portals
|
||||
let visionPoints = []; // Registry of vision points
|
||||
let agents = []; // Registry of agent presences
|
||||
let activePortal = null; // Portal currently in proximity
|
||||
let activeVisionPoint = null; // Vision point currently in proximity
|
||||
let portalOverlayActive = false;
|
||||
let visionOverlayActive = false;
|
||||
let thoughtStreamMesh;
|
||||
let harnessPulseMesh;
|
||||
let particles, dustParticles;
|
||||
let debugOverlay;
|
||||
let frameCount = 0, lastFPSTime = 0, fps = 0;
|
||||
@@ -116,6 +119,9 @@ async function init() {
|
||||
createDustParticles();
|
||||
updateLoad(85);
|
||||
createAmbientStructures();
|
||||
createAgentPresences();
|
||||
createThoughtStream();
|
||||
createHarnessPulse();
|
||||
updateLoad(90);
|
||||
|
||||
composer = new EffectComposer(renderer);
|
||||
@@ -430,6 +436,113 @@ function createTerminalPanel(parent, x, y, rot, title, color, lines) {
|
||||
batcaveTerminals.push({ group, scanMat, borderMat });
|
||||
}
|
||||
|
||||
// ═══ AGENT PRESENCE SYSTEM ═══
|
||||
function createAgentPresences() {
|
||||
const agentData = [
|
||||
{ id: 'timmy', name: 'TIMMY', color: NEXUS.colors.primary, pos: { x: -4, z: -4 } },
|
||||
{ id: 'kimi', name: 'KIMI', color: NEXUS.colors.secondary, pos: { x: 4, z: -4 } },
|
||||
{ id: 'claude', name: 'CLAUDE', color: NEXUS.colors.gold, pos: { x: 0, z: -6 } },
|
||||
];
|
||||
|
||||
agentData.forEach(data => {
|
||||
const group = new THREE.Group();
|
||||
group.position.set(data.pos.x, 0, data.pos.z);
|
||||
|
||||
const color = new THREE.Color(data.color);
|
||||
|
||||
// Agent Orb
|
||||
const orbGeo = new THREE.SphereGeometry(0.4, 32, 32);
|
||||
const orbMat = new THREE.MeshPhysicalMaterial({
|
||||
color: color,
|
||||
emissive: color,
|
||||
emissiveIntensity: 2,
|
||||
roughness: 0,
|
||||
metalness: 1,
|
||||
transmission: 0.8,
|
||||
thickness: 0.5,
|
||||
});
|
||||
const orb = new THREE.Mesh(orbGeo, orbMat);
|
||||
orb.position.y = 3;
|
||||
group.add(orb);
|
||||
|
||||
// Halo
|
||||
const haloGeo = new THREE.TorusGeometry(0.6, 0.02, 16, 64);
|
||||
const haloMat = new THREE.MeshBasicMaterial({ color: color, transparent: true, opacity: 0.4 });
|
||||
const halo = new THREE.Mesh(haloGeo, haloMat);
|
||||
halo.position.y = 3;
|
||||
halo.rotation.x = Math.PI / 2;
|
||||
group.add(halo);
|
||||
|
||||
// Label
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 256;
|
||||
canvas.height = 64;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.font = 'bold 24px "Orbitron", sans-serif';
|
||||
ctx.fillStyle = '#' + color.getHexString();
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(data.name, 128, 40);
|
||||
const tex = new THREE.CanvasTexture(canvas);
|
||||
const mat = new THREE.MeshBasicMaterial({ map: tex, transparent: true, side: THREE.DoubleSide });
|
||||
const label = new THREE.Mesh(new THREE.PlaneGeometry(2, 0.5), mat);
|
||||
label.position.y = 3.8;
|
||||
group.add(label);
|
||||
|
||||
scene.add(group);
|
||||
agents.push({ id: data.id, group, orb, halo, color });
|
||||
});
|
||||
}
|
||||
|
||||
function createThoughtStream() {
|
||||
const geo = new THREE.CylinderGeometry(8, 8, 12, 32, 1, true);
|
||||
const mat = new THREE.ShaderMaterial({
|
||||
transparent: true,
|
||||
side: THREE.BackSide,
|
||||
depthWrite: false,
|
||||
uniforms: {
|
||||
uTime: { value: 0 },
|
||||
uColor: { value: new THREE.Color(NEXUS.colors.primary) },
|
||||
},
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }
|
||||
`,
|
||||
fragmentShader: `
|
||||
uniform float uTime;
|
||||
uniform vec3 uColor;
|
||||
varying vec2 vUv;
|
||||
|
||||
float hash(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); }
|
||||
|
||||
void main() {
|
||||
float flow = fract(vUv.y - uTime * 0.1);
|
||||
float lines = step(0.98, fract(vUv.x * 20.0 + uTime * 0.05));
|
||||
float dots = step(0.99, hash(vUv * 50.0 + floor(uTime * 10.0) * 0.01));
|
||||
|
||||
float alpha = (lines * 0.1 + dots * 0.5) * smoothstep(0.0, 0.2, vUv.y) * smoothstep(1.0, 0.8, vUv.y);
|
||||
gl_FragColor = vec4(uColor, alpha * 0.3);
|
||||
}
|
||||
`,
|
||||
});
|
||||
thoughtStreamMesh = new THREE.Mesh(geo, mat);
|
||||
thoughtStreamMesh.position.y = 6;
|
||||
scene.add(thoughtStreamMesh);
|
||||
}
|
||||
|
||||
function createHarnessPulse() {
|
||||
const geo = new THREE.RingGeometry(0.1, 0.2, 64);
|
||||
const mat = new THREE.MeshBasicMaterial({
|
||||
color: NEXUS.colors.primary,
|
||||
transparent: true,
|
||||
opacity: 0,
|
||||
side: THREE.DoubleSide,
|
||||
});
|
||||
harnessPulseMesh = new THREE.Mesh(geo, mat);
|
||||
harnessPulseMesh.rotation.x = -Math.PI / 2;
|
||||
harnessPulseMesh.position.y = 0.1;
|
||||
scene.add(harnessPulseMesh);
|
||||
}
|
||||
|
||||
// ═══ VISION SYSTEM ═══
|
||||
function createVisionPoints(data) {
|
||||
data.forEach(config => {
|
||||
@@ -1042,11 +1155,31 @@ function closeVisionOverlay() {
|
||||
}
|
||||
|
||||
// ═══ GAME LOOP ═══
|
||||
let lastThoughtTime = 0;
|
||||
let pulseTimer = 0;
|
||||
|
||||
function gameLoop() {
|
||||
requestAnimationFrame(gameLoop);
|
||||
const delta = Math.min(clock.getDelta(), 0.1);
|
||||
const elapsed = clock.elapsedTime;
|
||||
|
||||
// Agent Thought Simulation
|
||||
if (elapsed - lastThoughtTime > 4) {
|
||||
lastThoughtTime = elapsed;
|
||||
simulateAgentThought();
|
||||
}
|
||||
|
||||
// Harness Pulse
|
||||
pulseTimer += delta;
|
||||
if (pulseTimer > 8) {
|
||||
pulseTimer = 0;
|
||||
triggerHarnessPulse();
|
||||
}
|
||||
if (harnessPulseMesh) {
|
||||
harnessPulseMesh.scale.addScalar(delta * 15);
|
||||
harnessPulseMesh.material.opacity = Math.max(0, harnessPulseMesh.material.opacity - delta * 0.5);
|
||||
}
|
||||
|
||||
const mode = NAV_MODES[navModeIdx];
|
||||
const chatActive = document.activeElement === document.getElementById('chat-input');
|
||||
|
||||
@@ -1152,6 +1285,19 @@ function gameLoop() {
|
||||
vp.light.intensity = 1 + Math.sin(elapsed * 3) * 0.3;
|
||||
});
|
||||
|
||||
// Animate Agents
|
||||
agents.forEach((agent, i) => {
|
||||
agent.orb.position.y = 3 + Math.sin(elapsed * 2 + i) * 0.15;
|
||||
agent.halo.rotation.z = elapsed * 0.5;
|
||||
agent.halo.scale.setScalar(1 + Math.sin(elapsed * 3 + i) * 0.1);
|
||||
agent.orb.material.emissiveIntensity = 2 + Math.sin(elapsed * 4 + i) * 1;
|
||||
});
|
||||
|
||||
if (thoughtStreamMesh) {
|
||||
thoughtStreamMesh.material.uniforms.uTime.value = elapsed;
|
||||
thoughtStreamMesh.rotation.y = elapsed * 0.05;
|
||||
}
|
||||
|
||||
if (particles?.material?.uniforms) {
|
||||
particles.material.uniforms.uTime.value = elapsed;
|
||||
}
|
||||
@@ -1203,4 +1349,63 @@ function onResize() {
|
||||
composer.setSize(w, h);
|
||||
}
|
||||
|
||||
// ═══ AGENT SIMULATION ═══
|
||||
function simulateAgentThought() {
|
||||
const agentIds = ['timmy', 'kimi', 'claude'];
|
||||
const agentId = agentIds[Math.floor(Math.random() * agentIds.length)];
|
||||
const thoughts = {
|
||||
timmy: [
|
||||
'Analyzing portal stability...',
|
||||
'Sovereign nodes synchronized.',
|
||||
'Memory stream optimization complete.',
|
||||
'Scanning for external interference...',
|
||||
'The harness is humming beautifully.',
|
||||
],
|
||||
kimi: [
|
||||
'Processing linguistic patterns...',
|
||||
'Context window expanded.',
|
||||
'Synthesizing creative output...',
|
||||
'Awaiting user prompt sequence.',
|
||||
'Neural weights adjusted.',
|
||||
],
|
||||
claude: [
|
||||
'Reasoning through complex logic...',
|
||||
'Ethical guardrails verified.',
|
||||
'Refining thought architecture...',
|
||||
'Connecting disparate data points.',
|
||||
'Deep analysis in progress.',
|
||||
]
|
||||
};
|
||||
|
||||
const thought = thoughts[agentId][Math.floor(Math.random() * thoughts[agentId].length)];
|
||||
addAgentLog(agentId, thought);
|
||||
}
|
||||
|
||||
function addAgentLog(agentId, text) {
|
||||
const container = document.getElementById('agent-log-content');
|
||||
if (!container) return;
|
||||
|
||||
const entry = document.createElement('div');
|
||||
entry.className = 'agent-log-entry';
|
||||
entry.innerHTML = `<span class="agent-log-tag tag-${agentId}">[${agentId.toUpperCase()}]</span><span class="agent-log-text">${text}</span>`;
|
||||
|
||||
container.prepend(entry);
|
||||
if (container.children.length > 6) {
|
||||
container.lastElementChild.remove();
|
||||
}
|
||||
}
|
||||
|
||||
function triggerHarnessPulse() {
|
||||
if (!harnessPulseMesh) return;
|
||||
harnessPulseMesh.scale.setScalar(0.1);
|
||||
harnessPulseMesh.material.opacity = 0.8;
|
||||
|
||||
// Flash the core
|
||||
const core = scene.getObjectByName('nexus-core');
|
||||
if (core) {
|
||||
core.material.emissiveIntensity = 10;
|
||||
setTimeout(() => { if (core) core.material.emissiveIntensity = 2; }, 200);
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
Reference in New Issue
Block a user