diff --git a/src/features/retro-office/RetroOffice3D.tsx b/src/features/retro-office/RetroOffice3D.tsx
index 3376725..98f77b9 100644
--- a/src/features/retro-office/RetroOffice3D.tsx
+++ b/src/features/retro-office/RetroOffice3D.tsx
@@ -2704,12 +2704,13 @@ export function RetroOffice3D({
target: [number, number, number];
zoom?: number;
} | null>(null);
+ const [sceneMode, setSceneMode] = useState<"city" | "office">("city");
+ const cityScapeMode = sceneMode === "city";
const LOCAL_CAMERA_TARGET = useMemo(
() =>
toWorld(LOCAL_OFFICE_CANVAS_WIDTH / 2, LOCAL_OFFICE_CANVAS_HEIGHT / 2),
[],
);
- const cityScapeMode = true;
const cityCameraTarget = LOCAL_CAMERA_TARGET;
const CAM_POS = useMemo<[number, number, number]>(() => {
const activeTarget = cityScapeMode ? cityCameraTarget : LOCAL_CAMERA_TARGET;
@@ -2728,6 +2729,12 @@ export function RetroOffice3D({
() => ({ pos: CAM_POS, target: cameraTarget, zoom: cameraZoom }),
[CAM_POS, cameraTarget, cameraZoom]
);
+ const handleEnterOfficeFromCity = useCallback(() => {
+ setSceneMode("office");
+ }, []);
+ const handleReturnToCity = useCallback(() => {
+ setSceneMode("city");
+ }, []);
const canvasResetKey = useMemo(
() =>
[
@@ -5460,7 +5467,10 @@ export function RetroOffice3D({
/>
{/* Floor + walls — always visible, no async loading. */}
-
+
{/* Wall pictures — procedural, no async loading. */}
@@ -7373,6 +7383,17 @@ export function RetroOffice3D({
)}
) : null}
+ {!immersiveOverlayActive && !cityScapeMode ? (
+
+
+
+ ) : null}
{!readOnly && settingsModalOpen ? (
diff --git a/src/features/retro-office/scene/environment.tsx b/src/features/retro-office/scene/environment.tsx
index 92d6289..e27adfc 100644
--- a/src/features/retro-office/scene/environment.tsx
+++ b/src/features/retro-office/scene/environment.tsx
@@ -1,6 +1,6 @@
"use client";
-import { memo, useMemo, useRef, type ReactNode } from "react";
+import { memo, useMemo, useRef, useState, type ReactNode } from "react";
import { useFrame } from "@react-three/fiber";
import type * as THREE from "three";
import {
@@ -653,8 +653,17 @@ function RoadTile({
);
}
-function FullCityScene({ centerX, centerZ }: { centerX: number; centerZ: number }) {
+function FullCityScene({
+ centerX,
+ centerZ,
+ onEnterHeadquarters,
+}: {
+ centerX: number;
+ centerZ: number;
+ onEnterHeadquarters?: () => void;
+}) {
const cityGrid = useMemo(() => buildCityGrid(), []);
+ const [hqHovered, setHqHovered] = useState(false);
const baseOffsetX = centerX - ((CITY_GRID_COLUMNS - 1) * CITY_GRID_CELL_SIZE) / 2;
const baseOffsetZ = centerZ - ((CITY_GRID_ROWS - 1) * CITY_GRID_CELL_SIZE) / 2;
const cityWidth = CITY_GRID_COLUMNS * CITY_GRID_CELL_SIZE;
@@ -753,7 +762,29 @@ function FullCityScene({ centerX, centerZ }: { centerX: number; centerZ: number
/>
);
})}
-
+ {
+ event.stopPropagation();
+ setHqHovered(true);
+ }}
+ onPointerOut={(event) => {
+ event.stopPropagation();
+ setHqHovered(false);
+ }}
+ onClick={(event) => {
+ event.stopPropagation();
+ onEnterHeadquarters?.();
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{
export const FloorAndWalls = memo(function FloorAndWalls({
showRemoteOffice = true,
+ onEnterHeadquarters,
}: {
showRemoteOffice?: boolean;
+ onEnterHeadquarters?: () => void;
}) {
const districtWidth = CANVAS_W * SCALE;
const districtHeight = CANVAS_H * SCALE;
@@ -919,7 +968,13 @@ export const FloorAndWalls = memo(function FloorAndWalls({
const groundHeight = showRemoteOffice ? districtHeight : localOfficeHeight;
if (showRemoteOffice) {
- return ;
+ return (
+
+ );
}
return (