[claude] World map overview mode — press Tab for bird's-eye view (#140) (#167)
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled

Co-authored-by: Claude (Opus 4.6) <claude@hermes.local>
Co-committed-by: Claude (Opus 4.6) <claude@hermes.local>
This commit was merged in pull request #167.
This commit is contained in:
2026-03-24 04:04:18 +00:00
committed by Timmy Time
parent 316ce63605
commit 4f853aae51
3 changed files with 72 additions and 3 deletions

34
app.js
View File

@@ -123,6 +123,27 @@ document.addEventListener('mousemove', (/** @type {MouseEvent} */ e) => {
mouseY = (e.clientY / window.innerHeight - 0.5) * 2;
});
// === OVERVIEW MODE (Tab — bird's-eye view of the whole Nexus) ===
let overviewMode = false;
let overviewT = 0; // 0 = normal view, 1 = overview
const NORMAL_CAM = new THREE.Vector3(0, 0, 5);
const OVERVIEW_CAM = new THREE.Vector3(0, 200, 0.1); // overhead; tiny Z offset avoids gimbal lock
const overviewIndicator = document.getElementById('overview-indicator');
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
overviewMode = !overviewMode;
if (overviewMode) {
overviewIndicator.classList.add('visible');
} else {
overviewIndicator.classList.remove('visible');
}
}
});
// === RESIZE HANDLER ===
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
@@ -141,12 +162,19 @@ function animate() {
requestAnimationFrame(animate);
const elapsed = clock.getElapsedTime();
// Slow auto-rotation
// Smooth camera transition for overview mode
const targetT = overviewMode ? 1 : 0;
overviewT += (targetT - overviewT) * 0.04;
camera.position.lerpVectors(NORMAL_CAM, OVERVIEW_CAM, overviewT);
camera.lookAt(0, 0, 0);
// Slow auto-rotation — suppressed during overview so the map stays readable
const rotationScale = 1 - overviewT;
targetRotX += (mouseY * 0.3 - targetRotX) * 0.02;
targetRotY += (mouseX * 0.3 - targetRotY) * 0.02;
stars.rotation.x = targetRotX + elapsed * 0.01;
stars.rotation.y = targetRotY + elapsed * 0.015;
stars.rotation.x = (targetRotX + elapsed * 0.01) * rotationScale;
stars.rotation.y = (targetRotY + elapsed * 0.015) * rotationScale;
constellationLines.rotation.x = stars.rotation.x;
constellationLines.rotation.y = stars.rotation.y;

View File

@@ -36,6 +36,11 @@
<audio id="ambient-sound" src="ambient.mp3" loop></audio>
</div>
<div id="overview-indicator">
<span>MAP VIEW</span>
<span class="overview-hint">[Tab] to exit</span>
</div>
<script type="module" src="app.js"></script>
</body>
</html>

View File

@@ -70,3 +70,39 @@ canvas {
outline: 2px dashed yellow;
outline-offset: 2px;
}
/* === OVERVIEW MODE === */
#overview-indicator {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: var(--color-primary);
font-family: var(--font-body);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
pointer-events: none;
z-index: 20;
border: 1px solid var(--color-primary);
padding: 4px 10px;
background: rgba(0, 0, 8, 0.6);
white-space: nowrap;
animation: overview-pulse 2s ease-in-out infinite;
}
#overview-indicator.visible {
display: block;
}
.overview-hint {
margin-left: 12px;
color: var(--color-text-muted);
font-size: 10px;
}
@keyframes overview-pulse {
0%, 100% { opacity: 0.7; }
50% { opacity: 1; }
}