Brighter night scene, building interior view on click
Browse files- Night lighting 3x brighter: hemi 0.35, ambient 0.25, lighter sky gradient, less fog
- Window glow increased to 0.8 emissive intensity
- Click building to enter interior: walls become transparent, camera zooms in
- See agents inside on beds, tables, desks
- Exit interior on empty click, Escape, or close panel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- web/3d.html +57 -11
web/3d.html
CHANGED
|
@@ -233,7 +233,7 @@ const SKY_PHASES = {
|
|
| 233 |
morning: { top:'#4a90c8', mid:'#88b8d8', bot:'#c8e0f0' },
|
| 234 |
afternoon: { top:'#2878b8', mid:'#60a0d0', bot:'#88c8e8' },
|
| 235 |
evening: { top:'#1a1040', mid:'#884060', bot:'#e07840' },
|
| 236 |
-
night: { top:'#
|
| 237 |
};
|
| 238 |
|
| 239 |
const LOCATION_POSITIONS = {
|
|
@@ -1737,12 +1737,12 @@ function updateTimeOfDay(phase, hour) {
|
|
| 1737 |
|
| 1738 |
// Lighting
|
| 1739 |
if (isNight) {
|
| 1740 |
-
hemiLight.intensity = 0.
|
| 1741 |
-
ambientLight.intensity = 0.
|
| 1742 |
-
sunLight.intensity = 0.
|
| 1743 |
-
ground.material.color.set(
|
| 1744 |
-
gridHelper.material.opacity = 0.
|
| 1745 |
-
scene.fog = new THREE.FogExp2(
|
| 1746 |
} else if (phase === 'evening') {
|
| 1747 |
hemiLight.intensity = 0.35; hemiLight.color.set(0xcc8855);
|
| 1748 |
ambientLight.intensity = 0.2;
|
|
@@ -1772,7 +1772,7 @@ function updateTimeOfDay(phase, hour) {
|
|
| 1772 |
if (isNight) {
|
| 1773 |
o.material.color.set(BLDG_COLORS.windowLit);
|
| 1774 |
o.material.emissive = new THREE.Color(BLDG_COLORS.windowLit);
|
| 1775 |
-
o.material.emissiveIntensity = 0.
|
| 1776 |
} else {
|
| 1777 |
o.material.color.set(BLDG_COLORS.window);
|
| 1778 |
o.material.emissive = new THREE.Color(0x000000);
|
|
@@ -1782,7 +1782,8 @@ function updateTimeOfDay(phase, hour) {
|
|
| 1782 |
});
|
| 1783 |
|
| 1784 |
const deepNight = phase === 'night';
|
| 1785 |
-
for (const [, bldg] of buildingMeshes) {
|
|
|
|
| 1786 |
const btype = bldg.userData?.type;
|
| 1787 |
const isResidential = btype === 'house' || btype === 'apartment';
|
| 1788 |
if (!isResidential) continue;
|
|
@@ -2120,6 +2121,49 @@ function handleStateUpdate(msg) {
|
|
| 2120 |
// CLICK / SELECTION
|
| 2121 |
// ============================================================
|
| 2122 |
let selectedId = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2123 |
const raycaster = new THREE.Raycaster();
|
| 2124 |
const mouse = new THREE.Vector2();
|
| 2125 |
let mouseDownPos = new THREE.Vector2();
|
|
@@ -2166,12 +2210,13 @@ renderer.domElement.addEventListener('pointerup', (e) => {
|
|
| 2166 |
while (parent.parent && !parent.userData?.id) parent = parent.parent;
|
| 2167 |
if (parent.userData?.id) {
|
| 2168 |
selectBuilding(parent.userData.id);
|
| 2169 |
-
|
| 2170 |
return;
|
| 2171 |
}
|
| 2172 |
}
|
| 2173 |
|
| 2174 |
-
// Click on empty space: deselect
|
|
|
|
| 2175 |
closeInfoPanel();
|
| 2176 |
});
|
| 2177 |
|
|
@@ -2362,6 +2407,7 @@ window.zoomOut = () => {
|
|
| 2362 |
};
|
| 2363 |
window.closeInfoPanel = () => {
|
| 2364 |
selectedId = null;
|
|
|
|
| 2365 |
document.getElementById('info-panel').classList.remove('visible');
|
| 2366 |
};
|
| 2367 |
|
|
|
|
| 233 |
morning: { top:'#4a90c8', mid:'#88b8d8', bot:'#c8e0f0' },
|
| 234 |
afternoon: { top:'#2878b8', mid:'#60a0d0', bot:'#88c8e8' },
|
| 235 |
evening: { top:'#1a1040', mid:'#884060', bot:'#e07840' },
|
| 236 |
+
night: { top:'#0a0e22', mid:'#101830', bot:'#182040' },
|
| 237 |
};
|
| 238 |
|
| 239 |
const LOCATION_POSITIONS = {
|
|
|
|
| 1737 |
|
| 1738 |
// Lighting
|
| 1739 |
if (isNight) {
|
| 1740 |
+
hemiLight.intensity = 0.35; hemiLight.color.set(0x334488);
|
| 1741 |
+
ambientLight.intensity = 0.25;
|
| 1742 |
+
sunLight.intensity = 0.2; sunLight.color.set(0x5577aa);
|
| 1743 |
+
ground.material.color.set(0x1a3a1a);
|
| 1744 |
+
gridHelper.material.opacity = 0.06;
|
| 1745 |
+
scene.fog = new THREE.FogExp2(0x0c0c20, 0.004);
|
| 1746 |
} else if (phase === 'evening') {
|
| 1747 |
hemiLight.intensity = 0.35; hemiLight.color.set(0xcc8855);
|
| 1748 |
ambientLight.intensity = 0.2;
|
|
|
|
| 1772 |
if (isNight) {
|
| 1773 |
o.material.color.set(BLDG_COLORS.windowLit);
|
| 1774 |
o.material.emissive = new THREE.Color(BLDG_COLORS.windowLit);
|
| 1775 |
+
o.material.emissiveIntensity = 0.8;
|
| 1776 |
} else {
|
| 1777 |
o.material.color.set(BLDG_COLORS.window);
|
| 1778 |
o.material.emissive = new THREE.Color(0x000000);
|
|
|
|
| 1782 |
});
|
| 1783 |
|
| 1784 |
const deepNight = phase === 'night';
|
| 1785 |
+
for (const [id, bldg] of buildingMeshes) {
|
| 1786 |
+
if (id === interiorBuildingId) continue;
|
| 1787 |
const btype = bldg.userData?.type;
|
| 1788 |
const isResidential = btype === 'house' || btype === 'apartment';
|
| 1789 |
if (!isResidential) continue;
|
|
|
|
| 2121 |
// CLICK / SELECTION
|
| 2122 |
// ============================================================
|
| 2123 |
let selectedId = null;
|
| 2124 |
+
let interiorBuildingId = null;
|
| 2125 |
+
|
| 2126 |
+
function enterInterior(buildingId) {
|
| 2127 |
+
exitInterior();
|
| 2128 |
+
interiorBuildingId = buildingId;
|
| 2129 |
+
const bldg = buildingMeshes.get(buildingId);
|
| 2130 |
+
if (!bldg) return;
|
| 2131 |
+
bldg.traverse(child => {
|
| 2132 |
+
if (child.isMesh && !child.userData?.isWindow && !child.userData?.isDoor) {
|
| 2133 |
+
child.userData._savedOpacity = child.material.opacity;
|
| 2134 |
+
child.userData._savedTransparent = child.material.transparent;
|
| 2135 |
+
child.userData._savedDepthWrite = child.material.depthWrite;
|
| 2136 |
+
child.material.transparent = true;
|
| 2137 |
+
child.material.opacity = 0.12;
|
| 2138 |
+
child.material.depthWrite = false;
|
| 2139 |
+
}
|
| 2140 |
+
if (child.isMesh && child.userData?.isWindow) {
|
| 2141 |
+
child.userData._savedOpacity = child.material.opacity;
|
| 2142 |
+
child.userData._savedTransparent = child.material.transparent;
|
| 2143 |
+
child.material.transparent = true;
|
| 2144 |
+
child.material.opacity = 0.15;
|
| 2145 |
+
}
|
| 2146 |
+
});
|
| 2147 |
+
smoothZoomTo(bldg.position, 8);
|
| 2148 |
+
}
|
| 2149 |
+
|
| 2150 |
+
function exitInterior() {
|
| 2151 |
+
if (!interiorBuildingId) return;
|
| 2152 |
+
const bldg = buildingMeshes.get(interiorBuildingId);
|
| 2153 |
+
if (bldg) {
|
| 2154 |
+
bldg.traverse(child => {
|
| 2155 |
+
if (child.isMesh && child.userData._savedOpacity !== undefined) {
|
| 2156 |
+
child.material.opacity = child.userData._savedOpacity;
|
| 2157 |
+
child.material.transparent = child.userData._savedTransparent;
|
| 2158 |
+
child.material.depthWrite = child.userData._savedDepthWrite ?? true;
|
| 2159 |
+
delete child.userData._savedOpacity;
|
| 2160 |
+
delete child.userData._savedTransparent;
|
| 2161 |
+
delete child.userData._savedDepthWrite;
|
| 2162 |
+
}
|
| 2163 |
+
});
|
| 2164 |
+
}
|
| 2165 |
+
interiorBuildingId = null;
|
| 2166 |
+
}
|
| 2167 |
const raycaster = new THREE.Raycaster();
|
| 2168 |
const mouse = new THREE.Vector2();
|
| 2169 |
let mouseDownPos = new THREE.Vector2();
|
|
|
|
| 2210 |
while (parent.parent && !parent.userData?.id) parent = parent.parent;
|
| 2211 |
if (parent.userData?.id) {
|
| 2212 |
selectBuilding(parent.userData.id);
|
| 2213 |
+
enterInterior(parent.userData.id);
|
| 2214 |
return;
|
| 2215 |
}
|
| 2216 |
}
|
| 2217 |
|
| 2218 |
+
// Click on empty space: deselect and exit interior
|
| 2219 |
+
exitInterior();
|
| 2220 |
closeInfoPanel();
|
| 2221 |
});
|
| 2222 |
|
|
|
|
| 2407 |
};
|
| 2408 |
window.closeInfoPanel = () => {
|
| 2409 |
selectedId = null;
|
| 2410 |
+
exitInterior();
|
| 2411 |
document.getElementById('info-panel').classList.remove('visible');
|
| 2412 |
};
|
| 2413 |
|