opencroc 1.8.1 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +755 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +128 -1
- package/dist/index.js +548 -0
- package/dist/index.js.map +1 -1
- package/dist/web/dist/assets/main-Ccg3eDNK.js +1 -0
- package/dist/web/dist/assets/office-runtime-B3iNctxE.css +1 -0
- package/dist/web/dist/assets/office-runtime-BsCh82Pj.js +183 -0
- package/dist/web/dist/assets/pixel-page-3BYGm7dH.js +470 -0
- package/dist/web/dist/assets/react-vendor-C8RhVn0h.js +49 -0
- package/dist/web/dist/assets/studio-page-BInoyoV2.css +1 -0
- package/dist/web/dist/assets/studio-page-o3SCvE_v.js +351 -0
- package/dist/web/dist/assets/three-addons-BdrPp04O.js +470 -0
- package/dist/web/dist/assets/three-core-CsxM1PCY.js +4057 -0
- package/dist/web/dist/index.html +15 -0
- package/package.json +11 -2
- package/dist/web/index-studio.html +0 -1644
- package/dist/web/index-v2-pixel.html +0 -1571
- package/dist/web/index.html +0 -573
- package/dist/web/js/agents.js +0 -465
- package/dist/web/js/camera.js +0 -125
- package/dist/web/js/dataviz.js +0 -288
- package/dist/web/js/effects.js +0 -345
- package/dist/web/js/engine.js +0 -489
- package/dist/web/js/office.js +0 -816
- package/dist/web/js/state.js +0 -37
- package/dist/web/js/ui.js +0 -384
- /package/dist/web/{assets → dist}/botreview/char_0.png +0 -0
- /package/dist/web/{assets → dist}/botreview/char_1.png +0 -0
- /package/dist/web/{assets → dist}/botreview/char_2.png +0 -0
- /package/dist/web/{assets → dist}/botreview/coffee-machine.gif +0 -0
- /package/dist/web/{assets → dist}/botreview/server.gif +0 -0
- /package/dist/web/{assets → dist}/botreview/walls.png +0 -0
- /package/dist/web/{assets → dist}/star/desk-v3.webp +0 -0
- /package/dist/web/{assets → dist}/star/office_bg_small.webp +0 -0
- /package/dist/web/{assets → dist}/star/star-idle-v5.png +0 -0
- /package/dist/web/{assets → dist}/star/star-working-spritesheet-grid.webp +0 -0
package/dist/web/js/office.js
DELETED
|
@@ -1,816 +0,0 @@
|
|
|
1
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
-
OpenCroc Studio 3D — Office Environment
|
|
3
|
-
Low-poly 3D office built from primitives
|
|
4
|
-
~3000 lines
|
|
5
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
6
|
-
|
|
7
|
-
import * as THREE from 'three';
|
|
8
|
-
import { getScene } from './engine.js';
|
|
9
|
-
|
|
10
|
-
let officeGroup = null;
|
|
11
|
-
let currentTheme = 'dark';
|
|
12
|
-
|
|
13
|
-
/* ─── Material Cache ───────────────────────────────────────────────────────── */
|
|
14
|
-
const MAT = {};
|
|
15
|
-
|
|
16
|
-
function initMaterials(theme) {
|
|
17
|
-
const dk = theme === 'dark';
|
|
18
|
-
MAT.floor = new THREE.MeshStandardMaterial({ color: dk ? 0x1a2332 : 0xe2e8f0, roughness: 0.8, metalness: 0.05 });
|
|
19
|
-
MAT.wall = new THREE.MeshStandardMaterial({ color: dk ? 0x1e293b : 0xf8fafc, roughness: 0.7, metalness: 0.0, transparent: true, opacity: 0.85 });
|
|
20
|
-
MAT.wallGlass = new THREE.MeshPhysicalMaterial({ color: dk ? 0x1e3a5f : 0xbfdbfe, roughness: 0.1, metalness: 0.1, transparent: true, opacity: 0.25, transmission: 0.6, thickness: 0.5, ior: 1.5 });
|
|
21
|
-
MAT.desk = new THREE.MeshStandardMaterial({ color: dk ? 0x2d3748 : 0xcbd5e1, roughness: 0.5, metalness: 0.2 });
|
|
22
|
-
MAT.deskTop = new THREE.MeshStandardMaterial({ color: dk ? 0x374151 : 0xdde4ed, roughness: 0.4, metalness: 0.15 });
|
|
23
|
-
MAT.chair = new THREE.MeshStandardMaterial({ color: dk ? 0x4a5568 : 0x94a3b8, roughness: 0.6, metalness: 0.1 });
|
|
24
|
-
MAT.screen = new THREE.MeshStandardMaterial({ color: dk ? 0x000000 : 0x111111, roughness: 0.1, metalness: 0.8 });
|
|
25
|
-
MAT.screenGlow= new THREE.MeshBasicMaterial({ color: dk ? 0x34d399 : 0x059669, transparent: true, opacity: 0.6 });
|
|
26
|
-
MAT.metal = new THREE.MeshStandardMaterial({ color: dk ? 0x64748b : 0x94a3b8, roughness: 0.3, metalness: 0.7 });
|
|
27
|
-
MAT.accent = new THREE.MeshStandardMaterial({ color: dk ? 0x34d399 : 0x059669, roughness: 0.4, metalness: 0.3, emissive: dk ? 0x34d399 : 0x059669, emissiveIntensity: dk ? 0.3 : 0.1 });
|
|
28
|
-
MAT.neon = new THREE.MeshBasicMaterial({ color: dk ? 0x34d399 : 0x059669, transparent: true, opacity: dk ? 0.8 : 0.4 });
|
|
29
|
-
MAT.neonBlue = new THREE.MeshBasicMaterial({ color: dk ? 0x60a5fa : 0x2563eb, transparent: true, opacity: dk ? 0.6 : 0.3 });
|
|
30
|
-
MAT.neonPurple= new THREE.MeshBasicMaterial({ color: dk ? 0xa78bfa : 0x7c3aed, transparent: true, opacity: dk ? 0.5 : 0.25 });
|
|
31
|
-
MAT.server = new THREE.MeshStandardMaterial({ color: dk ? 0x1a2332 : 0xcbd5e1, roughness: 0.3, metalness: 0.6 });
|
|
32
|
-
MAT.coffee = new THREE.MeshStandardMaterial({ color: dk ? 0x78350f : 0xa16207, roughness: 0.5, metalness: 0.1 });
|
|
33
|
-
MAT.plant = new THREE.MeshStandardMaterial({ color: dk ? 0x166534 : 0x22c55e, roughness: 0.8, metalness: 0.0 });
|
|
34
|
-
MAT.pot = new THREE.MeshStandardMaterial({ color: dk ? 0x92400e : 0xfbbf24, roughness: 0.6, metalness: 0.0 });
|
|
35
|
-
MAT.whiteboard= new THREE.MeshStandardMaterial({ color: dk ? 0xf8fafc : 0xffffff, roughness: 0.2, metalness: 0.05 });
|
|
36
|
-
MAT.frame = new THREE.MeshStandardMaterial({ color: dk ? 0x374151 : 0x64748b, roughness: 0.4, metalness: 0.5 });
|
|
37
|
-
MAT.carpet = new THREE.MeshStandardMaterial({ color: dk ? 0x1e1b4b : 0xc7d2fe, roughness: 0.95, metalness: 0.0 });
|
|
38
|
-
MAT.pillar = new THREE.MeshStandardMaterial({ color: dk ? 0x334155 : 0xe2e8f0, roughness: 0.5, metalness: 0.3 });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
42
|
-
createOffice — Build the full 3D office environment
|
|
43
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
44
|
-
export async function createOffice(theme) {
|
|
45
|
-
currentTheme = theme;
|
|
46
|
-
initMaterials(theme);
|
|
47
|
-
|
|
48
|
-
const scene = getScene();
|
|
49
|
-
officeGroup = new THREE.Group();
|
|
50
|
-
officeGroup.name = 'office';
|
|
51
|
-
|
|
52
|
-
buildFloor();
|
|
53
|
-
buildWalls();
|
|
54
|
-
buildGlassPartitions();
|
|
55
|
-
buildDesks(6);
|
|
56
|
-
buildServerRack();
|
|
57
|
-
buildCoffeeMachine();
|
|
58
|
-
buildPlants();
|
|
59
|
-
buildWhiteboard();
|
|
60
|
-
buildPillars();
|
|
61
|
-
buildCarpet();
|
|
62
|
-
buildCeilingLights();
|
|
63
|
-
buildNeonStrips();
|
|
64
|
-
buildCenterPlatform();
|
|
65
|
-
buildBookshelf();
|
|
66
|
-
buildWaterCooler();
|
|
67
|
-
buildDecorativeElements();
|
|
68
|
-
|
|
69
|
-
scene.add(officeGroup);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
73
|
-
Office Floor
|
|
74
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
75
|
-
function buildFloor() {
|
|
76
|
-
const geo = new THREE.BoxGeometry(28, 0.2, 20);
|
|
77
|
-
const floor = new THREE.Mesh(geo, MAT.floor);
|
|
78
|
-
floor.position.set(0, 0.1, 0);
|
|
79
|
-
floor.receiveShadow = true;
|
|
80
|
-
floor.name = 'office-floor';
|
|
81
|
-
officeGroup.add(floor);
|
|
82
|
-
|
|
83
|
-
// Floor edge trim (accent line)
|
|
84
|
-
const edgeGeo = new THREE.BoxGeometry(28.2, 0.05, 0.05);
|
|
85
|
-
const edgeFront = new THREE.Mesh(edgeGeo, MAT.neon);
|
|
86
|
-
edgeFront.position.set(0, 0.22, 10);
|
|
87
|
-
officeGroup.add(edgeFront);
|
|
88
|
-
const edgeBack = edgeFront.clone();
|
|
89
|
-
edgeBack.position.z = -10;
|
|
90
|
-
officeGroup.add(edgeBack);
|
|
91
|
-
|
|
92
|
-
const edgeSideGeo = new THREE.BoxGeometry(0.05, 0.05, 20.2);
|
|
93
|
-
const edgeLeft = new THREE.Mesh(edgeSideGeo, MAT.neon);
|
|
94
|
-
edgeLeft.position.set(-14, 0.22, 0);
|
|
95
|
-
officeGroup.add(edgeLeft);
|
|
96
|
-
const edgeRight = edgeLeft.clone();
|
|
97
|
-
edgeRight.position.x = 14;
|
|
98
|
-
officeGroup.add(edgeRight);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
102
|
-
Walls
|
|
103
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
104
|
-
function buildWalls() {
|
|
105
|
-
// Back wall
|
|
106
|
-
const backGeo = new THREE.BoxGeometry(28, 6, 0.15);
|
|
107
|
-
const backWall = new THREE.Mesh(backGeo, MAT.wall);
|
|
108
|
-
backWall.position.set(0, 3.2, -10);
|
|
109
|
-
backWall.castShadow = true;
|
|
110
|
-
backWall.receiveShadow = true;
|
|
111
|
-
officeGroup.add(backWall);
|
|
112
|
-
|
|
113
|
-
// Left wall
|
|
114
|
-
const sideGeo = new THREE.BoxGeometry(0.15, 6, 20);
|
|
115
|
-
const leftWall = new THREE.Mesh(sideGeo, MAT.wall);
|
|
116
|
-
leftWall.position.set(-14, 3.2, 0);
|
|
117
|
-
leftWall.castShadow = true;
|
|
118
|
-
leftWall.receiveShadow = true;
|
|
119
|
-
officeGroup.add(leftWall);
|
|
120
|
-
|
|
121
|
-
// Right wall (half + glass)
|
|
122
|
-
const rightLower = new THREE.Mesh(new THREE.BoxGeometry(0.15, 2, 20), MAT.wall);
|
|
123
|
-
rightLower.position.set(14, 1.2, 0);
|
|
124
|
-
rightLower.castShadow = true;
|
|
125
|
-
officeGroup.add(rightLower);
|
|
126
|
-
|
|
127
|
-
// Wall accent strips
|
|
128
|
-
const stripGeo = new THREE.BoxGeometry(28, 0.04, 0.04);
|
|
129
|
-
const strip1 = new THREE.Mesh(stripGeo, MAT.neon);
|
|
130
|
-
strip1.position.set(0, 5, -9.9);
|
|
131
|
-
officeGroup.add(strip1);
|
|
132
|
-
const strip2 = new THREE.Mesh(new THREE.BoxGeometry(0.04, 6, 0.04), MAT.neonBlue);
|
|
133
|
-
strip2.position.set(-13.9, 3.2, 9.5);
|
|
134
|
-
officeGroup.add(strip2);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
138
|
-
Glass Partitions
|
|
139
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
140
|
-
function buildGlassPartitions() {
|
|
141
|
-
// Partition between server area and desks
|
|
142
|
-
const partGeo = new THREE.BoxGeometry(0.08, 4, 8);
|
|
143
|
-
const part1 = new THREE.Mesh(partGeo, MAT.wallGlass);
|
|
144
|
-
part1.position.set(-5, 2.2, -3);
|
|
145
|
-
officeGroup.add(part1);
|
|
146
|
-
|
|
147
|
-
// Partition near center
|
|
148
|
-
const part2Geo = new THREE.BoxGeometry(8, 3.5, 0.08);
|
|
149
|
-
const part2 = new THREE.Mesh(part2Geo, MAT.wallGlass);
|
|
150
|
-
part2.position.set(3, 1.95, 3);
|
|
151
|
-
officeGroup.add(part2);
|
|
152
|
-
|
|
153
|
-
// Glass frame accents
|
|
154
|
-
const framGeo = new THREE.BoxGeometry(0.06, 4, 0.06);
|
|
155
|
-
const frame1 = new THREE.Mesh(framGeo, MAT.frame);
|
|
156
|
-
frame1.position.set(-5, 2.2, 1);
|
|
157
|
-
officeGroup.add(frame1);
|
|
158
|
-
const frame2 = frame1.clone();
|
|
159
|
-
frame2.position.z = -7;
|
|
160
|
-
officeGroup.add(frame2);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
164
|
-
Agent Desks — Each agent gets a desk with monitor and chair
|
|
165
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
166
|
-
export const DESK_POSITIONS = [];
|
|
167
|
-
|
|
168
|
-
function buildDesks(count) {
|
|
169
|
-
const rows = 2;
|
|
170
|
-
const cols = Math.ceil(count / rows);
|
|
171
|
-
const xStart = -2;
|
|
172
|
-
const zStart = -6;
|
|
173
|
-
const xSpacing = 4.5;
|
|
174
|
-
const zSpacing = 5;
|
|
175
|
-
|
|
176
|
-
for (let i = 0; i < count; i++) {
|
|
177
|
-
const row = Math.floor(i / cols);
|
|
178
|
-
const col = i % cols;
|
|
179
|
-
const x = xStart + col * xSpacing;
|
|
180
|
-
const z = zStart + row * zSpacing;
|
|
181
|
-
|
|
182
|
-
DESK_POSITIONS.push({ x, z });
|
|
183
|
-
buildSingleDesk(x, z, i);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function buildSingleDesk(x, z, idx) {
|
|
188
|
-
const desk = new THREE.Group();
|
|
189
|
-
desk.name = `desk-${idx}`;
|
|
190
|
-
|
|
191
|
-
// Desktop surface
|
|
192
|
-
const topGeo = new THREE.BoxGeometry(2.4, 0.08, 1.2);
|
|
193
|
-
const top = new THREE.Mesh(topGeo, MAT.deskTop);
|
|
194
|
-
top.position.set(0, 1.0, 0);
|
|
195
|
-
top.castShadow = true;
|
|
196
|
-
top.receiveShadow = true;
|
|
197
|
-
desk.add(top);
|
|
198
|
-
|
|
199
|
-
// Legs (4)
|
|
200
|
-
const legGeo = new THREE.BoxGeometry(0.08, 0.8, 0.08);
|
|
201
|
-
const positions = [
|
|
202
|
-
[-1.1, 0.6, -0.5], [1.1, 0.6, -0.5],
|
|
203
|
-
[-1.1, 0.6, 0.5], [1.1, 0.6, 0.5],
|
|
204
|
-
];
|
|
205
|
-
positions.forEach(p => {
|
|
206
|
-
const leg = new THREE.Mesh(legGeo, MAT.desk);
|
|
207
|
-
leg.position.set(...p);
|
|
208
|
-
leg.castShadow = true;
|
|
209
|
-
desk.add(leg);
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
// Monitor
|
|
213
|
-
const monitorGroup = new THREE.Group();
|
|
214
|
-
// Screen
|
|
215
|
-
const scrGeo = new THREE.BoxGeometry(1.0, 0.7, 0.04);
|
|
216
|
-
const scr = new THREE.Mesh(scrGeo, MAT.screen);
|
|
217
|
-
scr.position.set(0, 1.65, -0.3);
|
|
218
|
-
scr.castShadow = true;
|
|
219
|
-
monitorGroup.add(scr);
|
|
220
|
-
|
|
221
|
-
// Screen glow face
|
|
222
|
-
const glowGeo = new THREE.PlaneGeometry(0.92, 0.62);
|
|
223
|
-
const glow = new THREE.Mesh(glowGeo, MAT.screenGlow);
|
|
224
|
-
glow.position.set(0, 1.65, -0.278);
|
|
225
|
-
monitorGroup.add(glow);
|
|
226
|
-
|
|
227
|
-
// Monitor stand
|
|
228
|
-
const standGeo = new THREE.BoxGeometry(0.06, 0.28, 0.06);
|
|
229
|
-
const stand = new THREE.Mesh(standGeo, MAT.metal);
|
|
230
|
-
stand.position.set(0, 1.18, -0.3);
|
|
231
|
-
monitorGroup.add(stand);
|
|
232
|
-
|
|
233
|
-
// Monitor base
|
|
234
|
-
const baseGeo = new THREE.CylinderGeometry(0.18, 0.2, 0.04, 16);
|
|
235
|
-
const base = new THREE.Mesh(baseGeo, MAT.metal);
|
|
236
|
-
base.position.set(0, 1.04, -0.3);
|
|
237
|
-
monitorGroup.add(base);
|
|
238
|
-
|
|
239
|
-
desk.add(monitorGroup);
|
|
240
|
-
|
|
241
|
-
// Keyboard
|
|
242
|
-
const kbGeo = new THREE.BoxGeometry(0.6, 0.02, 0.2);
|
|
243
|
-
const kb = new THREE.Mesh(kbGeo, MAT.desk);
|
|
244
|
-
kb.position.set(0, 1.06, 0.15);
|
|
245
|
-
desk.add(kb);
|
|
246
|
-
|
|
247
|
-
// Mouse
|
|
248
|
-
const mouseGeo = new THREE.BoxGeometry(0.1, 0.02, 0.14);
|
|
249
|
-
const mouse = new THREE.Mesh(mouseGeo, MAT.desk);
|
|
250
|
-
mouse.position.set(0.5, 1.06, 0.15);
|
|
251
|
-
desk.add(mouse);
|
|
252
|
-
|
|
253
|
-
// Chair
|
|
254
|
-
const chairGroup = new THREE.Group();
|
|
255
|
-
// Seat
|
|
256
|
-
const seatGeo = new THREE.BoxGeometry(0.7, 0.08, 0.7);
|
|
257
|
-
const seat = new THREE.Mesh(seatGeo, MAT.chair);
|
|
258
|
-
seat.position.set(0, 0.7, 0.9);
|
|
259
|
-
seat.castShadow = true;
|
|
260
|
-
chairGroup.add(seat);
|
|
261
|
-
// Back rest
|
|
262
|
-
const backGeo = new THREE.BoxGeometry(0.7, 0.6, 0.06);
|
|
263
|
-
const back = new THREE.Mesh(backGeo, MAT.chair);
|
|
264
|
-
back.position.set(0, 1.04, 1.23);
|
|
265
|
-
back.castShadow = true;
|
|
266
|
-
chairGroup.add(back);
|
|
267
|
-
// Chair base
|
|
268
|
-
const cbaseGeo = new THREE.CylinderGeometry(0.04, 0.04, 0.5, 8);
|
|
269
|
-
const cbase = new THREE.Mesh(cbaseGeo, MAT.metal);
|
|
270
|
-
cbase.position.set(0, 0.45, 0.9);
|
|
271
|
-
chairGroup.add(cbase);
|
|
272
|
-
// Chair wheels (5-star base)
|
|
273
|
-
const wheelGeo = new THREE.CylinderGeometry(0.25, 0.28, 0.03, 5);
|
|
274
|
-
const wheel = new THREE.Mesh(wheelGeo, MAT.metal);
|
|
275
|
-
wheel.position.set(0, 0.2, 0.9);
|
|
276
|
-
chairGroup.add(wheel);
|
|
277
|
-
|
|
278
|
-
desk.add(chairGroup);
|
|
279
|
-
|
|
280
|
-
// Desk lamp
|
|
281
|
-
if (idx % 2 === 0) {
|
|
282
|
-
const lampGroup = new THREE.Group();
|
|
283
|
-
const lampBase = new THREE.Mesh(
|
|
284
|
-
new THREE.CylinderGeometry(0.1, 0.12, 0.04, 16), MAT.metal);
|
|
285
|
-
lampBase.position.set(-0.8, 1.06, -0.2);
|
|
286
|
-
lampGroup.add(lampBase);
|
|
287
|
-
const lampArm = new THREE.Mesh(
|
|
288
|
-
new THREE.CylinderGeometry(0.015, 0.015, 0.5, 8), MAT.metal);
|
|
289
|
-
lampArm.position.set(-0.8, 1.31, -0.2);
|
|
290
|
-
lampGroup.add(lampArm);
|
|
291
|
-
const lampHead = new THREE.Mesh(
|
|
292
|
-
new THREE.ConeGeometry(0.1, 0.12, 8), MAT.accent);
|
|
293
|
-
lampHead.position.set(-0.8, 1.58, -0.2);
|
|
294
|
-
lampHead.rotation.x = Math.PI;
|
|
295
|
-
lampGroup.add(lampHead);
|
|
296
|
-
desk.add(lampGroup);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Coffee mug (alternating desks)
|
|
300
|
-
if (idx % 3 === 1) {
|
|
301
|
-
const mugGeo = new THREE.CylinderGeometry(0.05, 0.04, 0.1, 12);
|
|
302
|
-
const mug = new THREE.Mesh(mugGeo, MAT.coffee);
|
|
303
|
-
mug.position.set(0.8, 1.09, 0.0);
|
|
304
|
-
desk.add(mug);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
desk.position.set(x, 0.2, z);
|
|
308
|
-
officeGroup.add(desk);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
312
|
-
Server Rack
|
|
313
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
314
|
-
function buildServerRack() {
|
|
315
|
-
const rack = new THREE.Group();
|
|
316
|
-
rack.name = 'server-rack';
|
|
317
|
-
|
|
318
|
-
// Main cabinet
|
|
319
|
-
const cabinetGeo = new THREE.BoxGeometry(1.0, 3.5, 0.8);
|
|
320
|
-
const cabinet = new THREE.Mesh(cabinetGeo, MAT.server);
|
|
321
|
-
cabinet.position.set(0, 1.95, 0);
|
|
322
|
-
cabinet.castShadow = true;
|
|
323
|
-
rack.add(cabinet);
|
|
324
|
-
|
|
325
|
-
// Server units (stacked)
|
|
326
|
-
for (let i = 0; i < 6; i++) {
|
|
327
|
-
const unitGeo = new THREE.BoxGeometry(0.9, 0.35, 0.7);
|
|
328
|
-
const unit = new THREE.Mesh(unitGeo, MAT.desk);
|
|
329
|
-
unit.position.set(0, 0.5 + i * 0.5, 0);
|
|
330
|
-
rack.add(unit);
|
|
331
|
-
|
|
332
|
-
// LED lights on each server unit
|
|
333
|
-
const ledColors = [MAT.neon, MAT.neonBlue, MAT.neon, MAT.neonBlue, MAT.neon, MAT.neonPurple];
|
|
334
|
-
for (let j = 0; j < 3; j++) {
|
|
335
|
-
const ledGeo = new THREE.BoxGeometry(0.03, 0.03, 0.01);
|
|
336
|
-
const led = new THREE.Mesh(ledGeo, ledColors[i]);
|
|
337
|
-
led.position.set(-0.3 + j * 0.15, 0.5 + i * 0.5, 0.36);
|
|
338
|
-
rack.add(led);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Status light on top
|
|
343
|
-
const statusLight = new THREE.Mesh(
|
|
344
|
-
new THREE.SphereGeometry(0.06, 8, 8), MAT.accent);
|
|
345
|
-
statusLight.position.set(0, 3.8, 0);
|
|
346
|
-
rack.add(statusLight);
|
|
347
|
-
|
|
348
|
-
rack.position.set(-10, 0.2, -6);
|
|
349
|
-
officeGroup.add(rack);
|
|
350
|
-
|
|
351
|
-
// Second rack
|
|
352
|
-
const rack2 = rack.clone();
|
|
353
|
-
rack2.position.set(-10, 0.2, -3);
|
|
354
|
-
rack2.name = 'server-rack-2';
|
|
355
|
-
officeGroup.add(rack2);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
359
|
-
Coffee Machine Area
|
|
360
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
361
|
-
function buildCoffeeMachine() {
|
|
362
|
-
const area = new THREE.Group();
|
|
363
|
-
area.name = 'coffee-area';
|
|
364
|
-
|
|
365
|
-
// Counter
|
|
366
|
-
const counterGeo = new THREE.BoxGeometry(2.5, 1.0, 0.8);
|
|
367
|
-
const counter = new THREE.Mesh(counterGeo, MAT.deskTop);
|
|
368
|
-
counter.position.set(0, 0.7, 0);
|
|
369
|
-
counter.castShadow = true;
|
|
370
|
-
counter.receiveShadow = true;
|
|
371
|
-
area.add(counter);
|
|
372
|
-
|
|
373
|
-
// Machine body
|
|
374
|
-
const machineGeo = new THREE.BoxGeometry(0.5, 0.6, 0.4);
|
|
375
|
-
const machine = new THREE.Mesh(machineGeo, MAT.server);
|
|
376
|
-
machine.position.set(-0.4, 1.5, 0);
|
|
377
|
-
machine.castShadow = true;
|
|
378
|
-
area.add(machine);
|
|
379
|
-
|
|
380
|
-
// Machine spout
|
|
381
|
-
const spoutGeo = new THREE.CylinderGeometry(0.02, 0.02, 0.15, 8);
|
|
382
|
-
const spout = new THREE.Mesh(spoutGeo, MAT.metal);
|
|
383
|
-
spout.position.set(-0.4, 1.13, 0.15);
|
|
384
|
-
area.add(spout);
|
|
385
|
-
|
|
386
|
-
// Cups
|
|
387
|
-
for (let i = 0; i < 3; i++) {
|
|
388
|
-
const cupGeo = new THREE.CylinderGeometry(0.04, 0.035, 0.08, 8);
|
|
389
|
-
const cup = new THREE.Mesh(cupGeo, MAT.coffee);
|
|
390
|
-
cup.position.set(0.3 + i * 0.15, 1.24, 0);
|
|
391
|
-
area.add(cup);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// Green indicator LED
|
|
395
|
-
const led = new THREE.Mesh(
|
|
396
|
-
new THREE.SphereGeometry(0.025, 8, 8), MAT.accent);
|
|
397
|
-
led.position.set(-0.15, 1.7, 0.21);
|
|
398
|
-
area.add(led);
|
|
399
|
-
|
|
400
|
-
area.position.set(11, 0.2, -7);
|
|
401
|
-
officeGroup.add(area);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
405
|
-
Plants
|
|
406
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
407
|
-
function buildPlants() {
|
|
408
|
-
const positions = [
|
|
409
|
-
[-12, 0.2, 8], [12, 0.2, 8], [-12, 0.2, -8], [8, 0.2, -8],
|
|
410
|
-
[0, 0.2, 9], [-7, 0.2, 9],
|
|
411
|
-
];
|
|
412
|
-
|
|
413
|
-
positions.forEach((pos, i) => {
|
|
414
|
-
const plant = new THREE.Group();
|
|
415
|
-
plant.name = `plant-${i}`;
|
|
416
|
-
|
|
417
|
-
// Pot
|
|
418
|
-
const potGeo = new THREE.CylinderGeometry(0.25, 0.2, 0.35, 8);
|
|
419
|
-
const pot = new THREE.Mesh(potGeo, MAT.pot);
|
|
420
|
-
pot.position.set(0, 0.175, 0);
|
|
421
|
-
pot.castShadow = true;
|
|
422
|
-
plant.add(pot);
|
|
423
|
-
|
|
424
|
-
// Leaves (spheres at different angles)
|
|
425
|
-
const leafMat = MAT.plant;
|
|
426
|
-
for (let j = 0; j < 5; j++) {
|
|
427
|
-
const leafGeo = new THREE.SphereGeometry(0.15 + Math.random() * 0.1, 6, 6);
|
|
428
|
-
const leaf = new THREE.Mesh(leafGeo, leafMat);
|
|
429
|
-
const angle = (j / 5) * Math.PI * 2;
|
|
430
|
-
leaf.position.set(
|
|
431
|
-
Math.cos(angle) * 0.15,
|
|
432
|
-
0.5 + Math.random() * 0.3,
|
|
433
|
-
Math.sin(angle) * 0.15
|
|
434
|
-
);
|
|
435
|
-
leaf.scale.y = 1.2 + Math.random() * 0.3;
|
|
436
|
-
plant.add(leaf);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// Center trunk
|
|
440
|
-
const trunkGeo = new THREE.CylinderGeometry(0.03, 0.04, 0.4, 6);
|
|
441
|
-
const trunk = new THREE.Mesh(trunkGeo, MAT.coffee);
|
|
442
|
-
trunk.position.set(0, 0.5, 0);
|
|
443
|
-
plant.add(trunk);
|
|
444
|
-
|
|
445
|
-
plant.position.set(...pos);
|
|
446
|
-
officeGroup.add(plant);
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
451
|
-
Whiteboard
|
|
452
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
453
|
-
function buildWhiteboard() {
|
|
454
|
-
const wb = new THREE.Group();
|
|
455
|
-
wb.name = 'whiteboard';
|
|
456
|
-
|
|
457
|
-
// Board
|
|
458
|
-
const boardGeo = new THREE.BoxGeometry(3, 2, 0.06);
|
|
459
|
-
const board = new THREE.Mesh(boardGeo, MAT.whiteboard);
|
|
460
|
-
board.position.set(0, 3.2, -9.9);
|
|
461
|
-
board.castShadow = true;
|
|
462
|
-
wb.add(board);
|
|
463
|
-
|
|
464
|
-
// Frame
|
|
465
|
-
const frameGeo = new THREE.BoxGeometry(3.1, 2.1, 0.04);
|
|
466
|
-
const frame = new THREE.Mesh(frameGeo, MAT.frame);
|
|
467
|
-
frame.position.set(0, 3.2, -9.95);
|
|
468
|
-
wb.add(frame);
|
|
469
|
-
|
|
470
|
-
// Colored marks on the board
|
|
471
|
-
const markColors = [0x34d399, 0x60a5fa, 0xf87171, 0xfbbf24];
|
|
472
|
-
for (let i = 0; i < 4; i++) {
|
|
473
|
-
const markGeo = new THREE.BoxGeometry(0.6, 0.04, 0.01);
|
|
474
|
-
const mark = new THREE.Mesh(markGeo, new THREE.MeshBasicMaterial({
|
|
475
|
-
color: markColors[i], transparent: true, opacity: 0.6,
|
|
476
|
-
}));
|
|
477
|
-
mark.position.set(-0.9 + i * 0.6, 3.5 - i * 0.2, -9.86);
|
|
478
|
-
wb.add(mark);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
officeGroup.add(wb);
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
485
|
-
Pillars
|
|
486
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
487
|
-
function buildPillars() {
|
|
488
|
-
const positions = [[-8, 0], [8, 0], [-8, -6], [8, -6]];
|
|
489
|
-
positions.forEach(([x, z], i) => {
|
|
490
|
-
const pillarGeo = new THREE.BoxGeometry(0.4, 6.2, 0.4);
|
|
491
|
-
const pillar = new THREE.Mesh(pillarGeo, MAT.pillar);
|
|
492
|
-
pillar.position.set(x, 3.3, z);
|
|
493
|
-
pillar.castShadow = true;
|
|
494
|
-
pillar.name = `pillar-${i}`;
|
|
495
|
-
officeGroup.add(pillar);
|
|
496
|
-
|
|
497
|
-
// Neon accent at pillar base
|
|
498
|
-
const neonGeo = new THREE.BoxGeometry(0.5, 0.04, 0.5);
|
|
499
|
-
const neon = new THREE.Mesh(neonGeo, i < 2 ? MAT.neon : MAT.neonBlue);
|
|
500
|
-
neon.position.set(x, 0.22, z);
|
|
501
|
-
officeGroup.add(neon);
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
506
|
-
Carpet
|
|
507
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
508
|
-
function buildCarpet() {
|
|
509
|
-
const carpetGeo = new THREE.BoxGeometry(10, 0.03, 7);
|
|
510
|
-
const carpet = new THREE.Mesh(carpetGeo, MAT.carpet);
|
|
511
|
-
carpet.position.set(2, 0.22, -3);
|
|
512
|
-
carpet.receiveShadow = true;
|
|
513
|
-
carpet.name = 'carpet';
|
|
514
|
-
officeGroup.add(carpet);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
518
|
-
Ceiling Lights
|
|
519
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
520
|
-
function buildCeilingLights() {
|
|
521
|
-
const positions = [[-4, -4], [4, -4], [-4, 3], [4, 3], [0, 0]];
|
|
522
|
-
positions.forEach(([x, z], i) => {
|
|
523
|
-
const lightGroup = new THREE.Group();
|
|
524
|
-
lightGroup.name = `ceiling-light-${i}`;
|
|
525
|
-
|
|
526
|
-
// Housing
|
|
527
|
-
const housingGeo = new THREE.BoxGeometry(1.5, 0.06, 0.4);
|
|
528
|
-
const housing = new THREE.Mesh(housingGeo, MAT.metal);
|
|
529
|
-
housing.position.set(0, 6.0, 0);
|
|
530
|
-
lightGroup.add(housing);
|
|
531
|
-
|
|
532
|
-
// Light panel (emitting)
|
|
533
|
-
const panelGeo = new THREE.BoxGeometry(1.4, 0.02, 0.35);
|
|
534
|
-
const panelMat = new THREE.MeshBasicMaterial({
|
|
535
|
-
color: currentTheme === 'dark' ? 0xddeeff : 0xfffef0,
|
|
536
|
-
transparent: true,
|
|
537
|
-
opacity: currentTheme === 'dark' ? 0.3 : 0.6,
|
|
538
|
-
});
|
|
539
|
-
const panel = new THREE.Mesh(panelGeo, panelMat);
|
|
540
|
-
panel.position.set(0, 5.97, 0);
|
|
541
|
-
panel.name = 'light-panel';
|
|
542
|
-
lightGroup.add(panel);
|
|
543
|
-
|
|
544
|
-
// Wire
|
|
545
|
-
const wireGeo = new THREE.CylinderGeometry(0.008, 0.008, 0.5, 4);
|
|
546
|
-
const wire = new THREE.Mesh(wireGeo, MAT.metal);
|
|
547
|
-
wire.position.set(-0.5, 6.25, 0);
|
|
548
|
-
lightGroup.add(wire);
|
|
549
|
-
const wire2 = wire.clone();
|
|
550
|
-
wire2.position.x = 0.5;
|
|
551
|
-
lightGroup.add(wire2);
|
|
552
|
-
|
|
553
|
-
lightGroup.position.set(x, 0, z);
|
|
554
|
-
officeGroup.add(lightGroup);
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
559
|
-
Neon Strips — Decorative glowing lines
|
|
560
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
561
|
-
function buildNeonStrips() {
|
|
562
|
-
// Floor neon strips (crossing pattern)
|
|
563
|
-
const stripGeo = new THREE.BoxGeometry(0.04, 0.02, 14);
|
|
564
|
-
const strip1 = new THREE.Mesh(stripGeo, MAT.neon);
|
|
565
|
-
strip1.position.set(-5.04, 0.23, -2);
|
|
566
|
-
officeGroup.add(strip1);
|
|
567
|
-
|
|
568
|
-
const strip2Geo = new THREE.BoxGeometry(12, 0.02, 0.04);
|
|
569
|
-
const strip2 = new THREE.Mesh(strip2Geo, MAT.neonBlue);
|
|
570
|
-
strip2.position.set(2, 0.23, 3.04);
|
|
571
|
-
officeGroup.add(strip2);
|
|
572
|
-
|
|
573
|
-
// Ceiling neon strip
|
|
574
|
-
const ceilStripGeo = new THREE.BoxGeometry(26, 0.03, 0.03);
|
|
575
|
-
const ceilStrip = new THREE.Mesh(ceilStripGeo, MAT.neonPurple);
|
|
576
|
-
ceilStrip.position.set(0, 6.15, 0);
|
|
577
|
-
officeGroup.add(ceilStrip);
|
|
578
|
-
|
|
579
|
-
const ceilStrip2Geo = new THREE.BoxGeometry(0.03, 0.03, 18);
|
|
580
|
-
const ceilStrip2 = new THREE.Mesh(ceilStrip2Geo, MAT.neon);
|
|
581
|
-
ceilStrip2.position.set(0, 6.15, 0);
|
|
582
|
-
officeGroup.add(ceilStrip2);
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
586
|
-
Center Platform — Hologram display base
|
|
587
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
588
|
-
function buildCenterPlatform() {
|
|
589
|
-
const platform = new THREE.Group();
|
|
590
|
-
platform.name = 'center-platform';
|
|
591
|
-
|
|
592
|
-
// Octagonal base
|
|
593
|
-
const baseGeo = new THREE.CylinderGeometry(1.5, 1.6, 0.15, 8);
|
|
594
|
-
const base = new THREE.Mesh(baseGeo, MAT.metal);
|
|
595
|
-
base.position.set(0, 0.28, 0);
|
|
596
|
-
base.receiveShadow = true;
|
|
597
|
-
platform.add(base);
|
|
598
|
-
|
|
599
|
-
// Inner ring
|
|
600
|
-
const innerGeo = new THREE.CylinderGeometry(1.0, 1.0, 0.2, 16);
|
|
601
|
-
const inner = new THREE.Mesh(innerGeo, MAT.accent);
|
|
602
|
-
inner.position.set(0, 0.32, 0);
|
|
603
|
-
platform.add(inner);
|
|
604
|
-
|
|
605
|
-
// Rotating accent ring
|
|
606
|
-
const ringGeo = new THREE.TorusGeometry(1.3, 0.02, 8, 32);
|
|
607
|
-
const ring = new THREE.Mesh(ringGeo, MAT.neon);
|
|
608
|
-
ring.rotation.x = Math.PI / 2;
|
|
609
|
-
ring.position.set(0, 0.4, 0);
|
|
610
|
-
ring.name = 'holo-ring';
|
|
611
|
-
platform.add(ring);
|
|
612
|
-
|
|
613
|
-
// Second ring (tilted)
|
|
614
|
-
const ring2 = new THREE.Mesh(
|
|
615
|
-
new THREE.TorusGeometry(1.1, 0.015, 8, 32), MAT.neonBlue);
|
|
616
|
-
ring2.rotation.x = Math.PI / 2;
|
|
617
|
-
ring2.rotation.z = Math.PI / 6;
|
|
618
|
-
ring2.position.set(0, 0.5, 0);
|
|
619
|
-
ring2.name = 'holo-ring-2';
|
|
620
|
-
platform.add(ring2);
|
|
621
|
-
|
|
622
|
-
officeGroup.add(platform);
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
626
|
-
Bookshelf
|
|
627
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
628
|
-
function buildBookshelf() {
|
|
629
|
-
const shelf = new THREE.Group();
|
|
630
|
-
shelf.name = 'bookshelf';
|
|
631
|
-
|
|
632
|
-
// Frame
|
|
633
|
-
const frameGeo = new THREE.BoxGeometry(2.0, 3.0, 0.4);
|
|
634
|
-
const frame = new THREE.Mesh(frameGeo, MAT.desk);
|
|
635
|
-
frame.position.set(0, 1.7, 0);
|
|
636
|
-
frame.castShadow = true;
|
|
637
|
-
shelf.add(frame);
|
|
638
|
-
|
|
639
|
-
// Shelves
|
|
640
|
-
for (let i = 0; i < 4; i++) {
|
|
641
|
-
const shelfGeo = new THREE.BoxGeometry(1.9, 0.04, 0.38);
|
|
642
|
-
const sh = new THREE.Mesh(shelfGeo, MAT.deskTop);
|
|
643
|
-
sh.position.set(0, 0.5 + i * 0.7, 0);
|
|
644
|
-
shelf.add(sh);
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// Books (colored blocks)
|
|
648
|
-
const bookColors = [0x60a5fa, 0xf87171, 0x34d399, 0xfbbf24, 0xa78bfa, 0xf472b6];
|
|
649
|
-
for (let row = 0; row < 3; row++) {
|
|
650
|
-
let bx = -0.8;
|
|
651
|
-
for (let j = 0; j < 5; j++) {
|
|
652
|
-
const w = 0.08 + Math.random() * 0.15;
|
|
653
|
-
const h = 0.25 + Math.random() * 0.15;
|
|
654
|
-
const bookGeo = new THREE.BoxGeometry(w, h, 0.25);
|
|
655
|
-
const bookMat = new THREE.MeshStandardMaterial({
|
|
656
|
-
color: bookColors[(row * 5 + j) % bookColors.length],
|
|
657
|
-
roughness: 0.8,
|
|
658
|
-
});
|
|
659
|
-
const book = new THREE.Mesh(bookGeo, bookMat);
|
|
660
|
-
book.position.set(bx + w / 2, 0.55 + row * 0.7 + h / 2, 0);
|
|
661
|
-
shelf.add(book);
|
|
662
|
-
bx += w + 0.02;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
shelf.position.set(-12.5, 0.2, -4);
|
|
667
|
-
shelf.rotation.y = Math.PI / 2;
|
|
668
|
-
officeGroup.add(shelf);
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
672
|
-
Water Cooler
|
|
673
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
674
|
-
function buildWaterCooler() {
|
|
675
|
-
const cooler = new THREE.Group();
|
|
676
|
-
cooler.name = 'water-cooler';
|
|
677
|
-
|
|
678
|
-
// Body
|
|
679
|
-
const bodyGeo = new THREE.BoxGeometry(0.4, 1.2, 0.35);
|
|
680
|
-
const body = new THREE.Mesh(bodyGeo, MAT.server);
|
|
681
|
-
body.position.set(0, 0.8, 0);
|
|
682
|
-
body.castShadow = true;
|
|
683
|
-
cooler.add(body);
|
|
684
|
-
|
|
685
|
-
// Water jug on top
|
|
686
|
-
const jugGeo = new THREE.CylinderGeometry(0.14, 0.16, 0.5, 12);
|
|
687
|
-
const jugMat = new THREE.MeshPhysicalMaterial({
|
|
688
|
-
color: 0x93c5fd, transmission: 0.8, roughness: 0.1,
|
|
689
|
-
thickness: 0.3, transparent: true, opacity: 0.5,
|
|
690
|
-
});
|
|
691
|
-
const jug = new THREE.Mesh(jugGeo, jugMat);
|
|
692
|
-
jug.position.set(0, 1.65, 0);
|
|
693
|
-
cooler.add(jug);
|
|
694
|
-
|
|
695
|
-
cooler.position.set(11, 0.2, -4);
|
|
696
|
-
officeGroup.add(cooler);
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
700
|
-
Decorative Elements
|
|
701
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
702
|
-
function buildDecorativeElements() {
|
|
703
|
-
// Wall clock
|
|
704
|
-
const clockGroup = new THREE.Group();
|
|
705
|
-
clockGroup.name = 'wall-clock';
|
|
706
|
-
const clockFace = new THREE.Mesh(
|
|
707
|
-
new THREE.CylinderGeometry(0.4, 0.4, 0.04, 24),
|
|
708
|
-
MAT.whiteboard);
|
|
709
|
-
clockFace.rotation.x = Math.PI / 2;
|
|
710
|
-
clockFace.position.set(-6, 4.5, -9.9);
|
|
711
|
-
clockGroup.add(clockFace);
|
|
712
|
-
|
|
713
|
-
const clockRim = new THREE.Mesh(
|
|
714
|
-
new THREE.TorusGeometry(0.4, 0.02, 8, 24),
|
|
715
|
-
MAT.frame);
|
|
716
|
-
clockRim.position.set(-6, 4.5, -9.88);
|
|
717
|
-
clockGroup.add(clockRim);
|
|
718
|
-
|
|
719
|
-
// Clock hands
|
|
720
|
-
const hourGeo = new THREE.BoxGeometry(0.02, 0.2, 0.01);
|
|
721
|
-
const hourHand = new THREE.Mesh(hourGeo, MAT.frame);
|
|
722
|
-
hourHand.position.set(-6, 4.6, -9.86);
|
|
723
|
-
hourHand.rotation.z = Math.PI / 4;
|
|
724
|
-
clockGroup.add(hourHand);
|
|
725
|
-
|
|
726
|
-
const minGeo = new THREE.BoxGeometry(0.015, 0.3, 0.01);
|
|
727
|
-
const minHand = new THREE.Mesh(minGeo, MAT.accent);
|
|
728
|
-
minHand.position.set(-6, 4.6, -9.84);
|
|
729
|
-
minHand.rotation.z = -Math.PI / 6;
|
|
730
|
-
clockGroup.add(minHand);
|
|
731
|
-
|
|
732
|
-
officeGroup.add(clockGroup);
|
|
733
|
-
|
|
734
|
-
// Ceiling fan
|
|
735
|
-
const fan = new THREE.Group();
|
|
736
|
-
fan.name = 'ceiling-fan';
|
|
737
|
-
const fanHub = new THREE.Mesh(
|
|
738
|
-
new THREE.CylinderGeometry(0.1, 0.1, 0.08, 12), MAT.metal);
|
|
739
|
-
fanHub.position.set(0, 6.1, 0);
|
|
740
|
-
fan.add(fanHub);
|
|
741
|
-
const fanRod = new THREE.Mesh(
|
|
742
|
-
new THREE.CylinderGeometry(0.02, 0.02, 0.4, 6), MAT.metal);
|
|
743
|
-
fanRod.position.set(0, 6.3, 0);
|
|
744
|
-
fan.add(fanRod);
|
|
745
|
-
|
|
746
|
-
for (let i = 0; i < 4; i++) {
|
|
747
|
-
const bladeGeo = new THREE.BoxGeometry(1.5, 0.02, 0.25);
|
|
748
|
-
const blade = new THREE.Mesh(bladeGeo, MAT.desk);
|
|
749
|
-
blade.position.set(0, 6.08, 0);
|
|
750
|
-
blade.rotation.y = (i / 4) * Math.PI * 2;
|
|
751
|
-
blade.translateX(0.75);
|
|
752
|
-
fan.add(blade);
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
fan.position.set(2, 0, -2);
|
|
756
|
-
officeGroup.add(fan);
|
|
757
|
-
|
|
758
|
-
// Door frame on side wall
|
|
759
|
-
const doorFrame = new THREE.Group();
|
|
760
|
-
doorFrame.name = 'door-frame';
|
|
761
|
-
const doorPost = new THREE.Mesh(
|
|
762
|
-
new THREE.BoxGeometry(0.1, 3, 0.1), MAT.frame);
|
|
763
|
-
doorPost.position.set(-13.95, 1.7, 5);
|
|
764
|
-
doorFrame.add(doorPost);
|
|
765
|
-
const doorPost2 = doorPost.clone();
|
|
766
|
-
doorPost2.position.z = 7;
|
|
767
|
-
doorFrame.add(doorPost2);
|
|
768
|
-
const doorLintel = new THREE.Mesh(
|
|
769
|
-
new THREE.BoxGeometry(0.1, 0.1, 2.1), MAT.frame);
|
|
770
|
-
doorLintel.position.set(-13.95, 3.2, 6);
|
|
771
|
-
doorFrame.add(doorLintel);
|
|
772
|
-
officeGroup.add(doorFrame);
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
776
|
-
Floor Y position getter
|
|
777
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
778
|
-
export function getFloorY() {
|
|
779
|
-
return 0.2;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
/* ═══════════════════════════════════════════════════════════════════════════════
|
|
783
|
-
Theme Update
|
|
784
|
-
═══════════════════════════════════════════════════════════════════════════════ */
|
|
785
|
-
export function updateOfficeLighting(theme) {
|
|
786
|
-
if (!officeGroup) return;
|
|
787
|
-
currentTheme = theme;
|
|
788
|
-
|
|
789
|
-
// Reload materials
|
|
790
|
-
initMaterials(theme);
|
|
791
|
-
|
|
792
|
-
// We rebuild the office to apply new materials
|
|
793
|
-
const scene = getScene();
|
|
794
|
-
scene.remove(officeGroup);
|
|
795
|
-
officeGroup = new THREE.Group();
|
|
796
|
-
officeGroup.name = 'office';
|
|
797
|
-
|
|
798
|
-
buildFloor();
|
|
799
|
-
buildWalls();
|
|
800
|
-
buildGlassPartitions();
|
|
801
|
-
buildDesks(6);
|
|
802
|
-
buildServerRack();
|
|
803
|
-
buildCoffeeMachine();
|
|
804
|
-
buildPlants();
|
|
805
|
-
buildWhiteboard();
|
|
806
|
-
buildPillars();
|
|
807
|
-
buildCarpet();
|
|
808
|
-
buildCeilingLights();
|
|
809
|
-
buildNeonStrips();
|
|
810
|
-
buildCenterPlatform();
|
|
811
|
-
buildBookshelf();
|
|
812
|
-
buildWaterCooler();
|
|
813
|
-
buildDecorativeElements();
|
|
814
|
-
|
|
815
|
-
scene.add(officeGroup);
|
|
816
|
-
}
|