Nexus Heartbeat: Ambient World Vitality System #734
28
app.js
28
app.js
@@ -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();
|
||||
|
||||
11
index.html
11
index.html
@@ -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">
|
||||
|
||||
50
style.css
50
style.css
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user