perf(nexus): implement performance tier optimization for low-end devices

This commit is contained in:
Allegro (Burn Mode)
2026-04-05 11:36:40 +00:00
parent 9a22d26b9c
commit ae9b51c3f1

43
app.js
View File

@@ -644,19 +644,31 @@ async function init() {
playerPos = new THREE.Vector3(0, 2, 12);
playerRot = new THREE.Euler(0, 0, 0, 'YXZ');
// Detect performance tier BEFORE creating renderer (antialias cannot be changed after)
performanceTier = detectPerformanceTier();
const canvas = document.getElementById('nexus-canvas');
renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
const antialias = performanceTier !== 'low';
renderer = new THREE.WebGLRenderer({ canvas, antialias });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.2;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.shadowMap.enabled = performanceTier !== 'low';
renderer.shadowMap.type = performanceTier === 'high' ? THREE.PCFSoftShadowMap : THREE.BasicShadowMap;
performanceTier = detectPerformanceTier();
updateLoad(10);
scene = new THREE.Scene();
// Fog density based on performance tier
if (performanceTier === 'low') {
// No fog for low tier
scene.fog = null;
} else if (performanceTier === 'medium') {
scene.fog = new THREE.FogExp2(0x050510, 0.008);
} else {
scene.fog = new THREE.FogExp2(0x050510, 0.012);
}
setupGOFAI();
camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 0.1, 1000);
@@ -710,6 +722,20 @@ async function init() {
fetchGiteaData();
setInterval(fetchGiteaData, 30000); // Refresh every 30s
// Initialize post-processing based on performance tier
// Low tier: No post-processing (avoids GPU stalls from readPixels)
// Medium tier: RenderPass + SMAA only (no bloom)
// High tier: Full post-processing with bloom
if (performanceTier === 'low') {
// No composer for low tier - use direct renderer.render()
composer = null;
} else if (performanceTier === 'medium') {
composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
// Skip UnrealBloomPass to avoid GPU stalls from readPixels
composer.addPass(new SMAAPass(window.innerWidth, window.innerHeight));
} else {
// High tier: Full post-processing with bloom
composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const bloom = new UnrealBloomPass(
@@ -718,6 +744,7 @@ async function init() {
);
composer.addPass(bloom);
composer.addPass(new SMAAPass(window.innerWidth, window.innerHeight));
}
updateLoad(95);
@@ -2495,7 +2522,12 @@ function gameLoop() {
core.material.emissiveIntensity = 1.5 + Math.sin(elapsed * 2) * 0.5;
}
// Render based on performance tier (low tier bypasses composer to avoid GPU stalls)
if (composer) {
composer.render();
} else {
renderer.render(scene, camera);
}
updateAshStorm(delta, elapsed);
updatePortalTunnel(delta, elapsed);
@@ -2528,8 +2560,11 @@ function onResize() {
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
// Only resize composer if it exists (low tier has no composer)
if (composer) {
composer.setSize(w, h);
}
}
// ═══ AGENT SIMULATION ═══
function simulateAgentThought() {