forked from Rockachopa/the-matrix
Fixes: - #22 OrbitControls damping: call updateControls() in animate loop - #23 Empty catch blocks: add console.warn + error surfacing to chat panel - #24 escapeHtml: add quote escaping (" '), use in renderAgentList - #25 WS reconnect: check close code (1000/1001) before reconnecting, add exponential backoff + heartbeat zombie detection - #26 IDLE state visibility: brighten from near-invisible to #005500 - #5 PWA: manifest.json, service worker (network-first), theme-color, favicon, loading screen, safe-area-inset padding, apple-mobile-web-app - #14 Adaptive render quality: new quality.js hardware detection (low/ medium/high tiers), tiered particle counts, grid density, antialias, pixel ratio caps New files: - js/quality.js — hardware detection + quality tier logic - manifest.json — PWA manifest - public/sw.js — service worker (network-first with offline cache) - public/favicon.svg — SVG favicon - icons/icon-192.svg, icons/icon-512.svg — PWA icons
64 lines
1.9 KiB
JavaScript
64 lines
1.9 KiB
JavaScript
import * as THREE from 'three';
|
|
import { getMaxPixelRatio, getQualityTier } from './quality.js';
|
|
|
|
let scene, camera, renderer;
|
|
|
|
export function initWorld() {
|
|
scene = new THREE.Scene();
|
|
scene.background = new THREE.Color(0x000000);
|
|
scene.fog = new THREE.FogExp2(0x000000, 0.035);
|
|
|
|
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 500);
|
|
camera.position.set(0, 12, 28);
|
|
camera.lookAt(0, 0, 0);
|
|
|
|
const tier = getQualityTier();
|
|
renderer = new THREE.WebGLRenderer({ antialias: tier !== 'low' });
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
renderer.setPixelRatio(Math.min(window.devicePixelRatio, getMaxPixelRatio()));
|
|
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
|
document.body.prepend(renderer.domElement);
|
|
|
|
addLights(scene);
|
|
addGrid(scene, tier);
|
|
|
|
return { scene, camera, renderer };
|
|
}
|
|
|
|
function addLights(scene) {
|
|
const ambient = new THREE.AmbientLight(0x001a00, 0.6);
|
|
scene.add(ambient);
|
|
|
|
const point = new THREE.PointLight(0x00ff41, 2, 80);
|
|
point.position.set(0, 20, 0);
|
|
scene.add(point);
|
|
|
|
const fill = new THREE.DirectionalLight(0x003300, 0.4);
|
|
fill.position.set(-10, 10, 10);
|
|
scene.add(fill);
|
|
}
|
|
|
|
function addGrid(scene, tier) {
|
|
const gridDivisions = tier === 'low' ? 20 : 40;
|
|
const grid = new THREE.GridHelper(100, gridDivisions, 0x003300, 0x001a00);
|
|
grid.position.y = -0.01;
|
|
scene.add(grid);
|
|
|
|
const planeGeo = new THREE.PlaneGeometry(100, 100);
|
|
const planeMat = new THREE.MeshBasicMaterial({
|
|
color: 0x000a00,
|
|
transparent: true,
|
|
opacity: 0.5,
|
|
});
|
|
const plane = new THREE.Mesh(planeGeo, planeMat);
|
|
plane.rotation.x = -Math.PI / 2;
|
|
plane.position.y = -0.02;
|
|
scene.add(plane);
|
|
}
|
|
|
|
export function onWindowResize(camera, renderer) {
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
camera.updateProjectionMatrix();
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
}
|