feat: implement Timmy's mood lighting for Nexus atmosphere
Some checks failed
CI / validate (pull_request) Failing after 5s
CI / auto-merge (pull_request) Has been skipped

This commit is contained in:
Alexander Whitestone
2026-03-24 00:31:47 -04:00
parent b61f651226
commit 11d7b6dd25

53
app.js
View File

@@ -14,7 +14,14 @@ const NEXUS = {
constellationLine: 0x334488,
constellationFade: 0x112244,
accent: 0x4488ff,
}
},
moods: {
content: { bg: 0x002828, ambient: 1.4, particleIntensity: 0.9, particleSpeed: 0.01 },
busy: { bg: 0x003838, ambient: 1.8, particleIntensity: 1.2, particleSpeed: 0.02 },
contemplative: { bg: 0x000818, ambient: 0.8, particleIntensity: 0.6, particleSpeed: 0.005 },
error: { bg: 0x280808, ambient: 1.0, particleIntensity: 0.8, particleSpeed: 0.01 }
},
currentMood: 'content'
};
// === ASSET LOADER ===
@@ -343,6 +350,37 @@ window.addEventListener('resize', () => {
// === ANIMATION LOOP ===
const clock = new THREE.Clock();
// Mood derivation variables
let chatActivity = 0;
let prMergeRate = 0;
let errorCount = 0;
let lastMoodUpdate = 0;
/**
* Derives Timmy's mood based on current metrics.
*/
function deriveMood() {
const now = clock.getElapsedTime();
if (now - lastMoodUpdate < 5) return; // Update mood every 5 seconds
lastMoodUpdate = now;
if (errorCount > 3) {
NEXUS.currentMood = 'error';
} else if (chatActivity > 5 || prMergeRate > 1) {
NEXUS.currentMood = 'busy';
} else if (chatActivity < 2 && prMergeRate === 0) {
NEXUS.currentMood = 'contemplative';
} else {
NEXUS.currentMood = 'content';
}
// Update scene atmosphere based on mood
const mood = NEXUS.moods[NEXUS.currentMood];
scene.background = new THREE.Color(mood.bg);
ambientLight.intensity = mood.ambient;
starMaterial.opacity = mood.particleIntensity;
}
/**
* Main animation loop — called each frame via requestAnimationFrame.
* @returns {void}
@@ -351,6 +389,9 @@ function animate() {
// Only start animation after assets are loaded
requestAnimationFrame(animate);
const elapsed = clock.getElapsedTime();
// Update mood based on metrics
deriveMood();
// Smooth camera transition for overview mode
const targetT = overviewMode ? 1 : 0;
@@ -440,6 +481,10 @@ import { wsClient } from './ws-client.js';
wsClient.connect();
// Simulate error count for mood derivation (replace with real error tracking)
setInterval(() => {
if (Math.random() < 0.1) errorCount++;
}, 10000);
window.addEventListener('player-joined', (/** @type {CustomEvent} */ event) => {
console.log('Player joined:', event.detail);
});
@@ -450,6 +495,7 @@ window.addEventListener('player-left', (/** @type {CustomEvent} */ event) => {
window.addEventListener('chat-message', (/** @type {CustomEvent} */ event) => {
console.log('Chat message:', event.detail);
chatActivity++;
if (typeof event.detail?.text === 'string' && event.detail.text.toLowerCase().includes('sovereignty')) {
triggerSovereigntyEasterEgg();
}
@@ -615,7 +661,10 @@ async function initCommitBanners() {
];
// Load commit banners after assets are ready
initCommitBanners();
initCommitBanners();
// Update PR merge rate for mood derivation
prMergeRate++;
}
const spreadX = [-7, -3.5, 0, 3.5, 7];