Nexus Heartbeat: Ambient World Vitality System #734

Closed
gemini wants to merge 3 commits from gemini/nexus-heartbeat-1774731316192 into main
3 changed files with 82 additions and 7 deletions

28
app.js
View File

@@ -39,7 +39,7 @@ let atlasOverlayActive = false;
let thoughtStreamMesh;
let harnessPulseMesh;
let powerMeterBars = [];
let particles, dustParticles;
let particles, dustParticles, ambientLight;
let debugOverlay;
let frameCount = 0, lastFPSTime = 0, fps = 0;
let chatOpen = true;
@@ -301,8 +301,8 @@ function createSkybox() {
// ═══ LIGHTING ═══
function createLighting() {
const ambient = new THREE.AmbientLight(0x1a1a3a, 0.4);
scene.add(ambient);
ambientLight = new THREE.AmbientLight(0x1a1a3a, 0.4);
scene.add(ambientLight);
const dirLight = new THREE.DirectionalLight(0x4466aa, 0.6);
dirLight.position.set(10, 20, 10);
@@ -1735,6 +1735,7 @@ function gameLoop() {
}
updateAshStorm(delta, elapsed);
updateNexusHeartbeat(delta, elapsed);
const mode = NAV_MODES[navModeIdx];
const chatActive = document.activeElement === document.getElementById('chat-input');
@@ -2096,6 +2097,27 @@ function updateAshStorm(delta, elapsed) {
}
}
function updateNexusHeartbeat(delta, elapsed) {
// Calculate heartbeat frequency (0.5 to 1.5 Hz based on time)
const pulse = 1.0 + Math.sin(elapsed * 0.2) * 0.5;
const heartbeatVal = document.getElementById('heartbeat-value');
if (heartbeatVal) {
heartbeatVal.textContent = `${pulse.toFixed(2)} Hz`;
}
// Breathing effect for ambient light
if (ambientLight) {
const intensity = 0.3 + Math.sin(elapsed * pulse * Math.PI) * 0.1;
ambientLight.intensity = intensity;
}
// Update heartbeat pulse animation speed
const pulseEl = document.querySelector('.heartbeat-pulse');
if (pulseEl) {
pulseEl.style.animationDuration = `${1 / pulse}s`;
}
}
init().then(() => {
createAshStorm();
createPortalTunnel();

View File

@@ -65,8 +65,15 @@
<!-- HUD Overlay -->
<div id="hud" class="game-ui" style="display:none;">
<!-- Top Left: Debug -->
<div id="debug-overlay" class="hud-debug"></div>
<!-- Top Left: Debug & Heartbeat -->
<div class="hud-top-left">
<div id="debug-overlay" class="hud-debug"></div>
<div id="nexus-heartbeat" class="hud-heartbeat" title="Nexus Pulse">
<div class="heartbeat-pulse"></div>
<div class="heartbeat-label">NEXUS PULSE</div>
<div id="heartbeat-value" class="heartbeat-value">0.00 Hz</div>
</div>
</div>
<!-- Top Center: Location -->
<div class="hud-location" aria-live="polite">

View File

@@ -426,10 +426,17 @@ canvas#nexus-canvas {
}
/* Debug overlay */
.hud-debug {
.hud-top-left {
position: absolute;
top: var(--space-3);
left: var(--space-3);
display: flex;
flex-direction: column;
gap: var(--space-2);
pointer-events: none;
}
.hud-debug {
background: rgba(0, 0, 0, 0.7);
color: #0f0;
font-size: var(--text-xs);
@@ -437,10 +444,49 @@ canvas#nexus-canvas {
padding: var(--space-2) var(--space-3);
border-radius: 4px;
white-space: pre;
pointer-events: none;
font-variant-numeric: tabular-nums lining-nums;
}
.hud-heartbeat {
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
border: 1px solid rgba(74, 240, 192, 0.2);
border-radius: 4px;
padding: 8px 12px;
display: flex;
align-items: center;
gap: 10px;
pointer-events: auto;
}
.heartbeat-pulse {
width: 10px;
height: 10px;
background: var(--color-primary);
border-radius: 50%;
box-shadow: 0 0 10px var(--color-primary);
animation: pulse-heartbeat 2s infinite ease-in-out;
}
@keyframes pulse-heartbeat {
0%, 100% { transform: scale(1); opacity: 0.8; }
50% { transform: scale(1.4); opacity: 1; box-shadow: 0 0 15px var(--color-primary); }
}
.heartbeat-label {
font-family: var(--font-display);
font-size: 9px;
letter-spacing: 0.1em;
color: var(--color-text-muted);
}
.heartbeat-value {
font-family: var(--font-mono);
font-size: 11px;
color: var(--color-primary);
min-width: 45px;
}
/* Location indicator */
.hud-location {
position: absolute;