akhaliq HF Staff commited on
Commit
8bbedc5
·
verified ·
1 Parent(s): 0b1bdf4

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. index.html +107 -19
  2. js/voxel-scene.js +486 -0
index.html CHANGED
@@ -1,19 +1,107 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Voxel Pagoda Garden</title>
7
+ <meta name="description" content="A beautiful voxel art scene featuring a pagoda in a garden with cherry blossoms">
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ background: linear-gradient(to bottom, #87CEEB, #98FB98);
17
+ font-family: 'Arial', sans-serif;
18
+ overflow: hidden;
19
+ }
20
+
21
+ #header {
22
+ position: absolute;
23
+ top: 20px;
24
+ left: 20px;
25
+ z-index: 100;
26
+ color: white;
27
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
28
+ }
29
+
30
+ #header h1 {
31
+ font-size: 2rem;
32
+ margin-bottom: 10px;
33
+ }
34
+
35
+ #header a {
36
+ color: #FFD700;
37
+ text-decoration: none;
38
+ font-weight: bold;
39
+ }
40
+
41
+ #header a:hover {
42
+ text-decoration: underline;
43
+ }
44
+
45
+ #container {
46
+ width: 100vw;
47
+ height: 100vh;
48
+ }
49
+
50
+ #info {
51
+ position: absolute;
52
+ bottom: 20px;
53
+ left: 20px;
54
+ color: white;
55
+ text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
56
+ background: rgba(0,0,0,0.3);
57
+ padding: 10px;
58
+ border-radius: 5px;
59
+ }
60
+
61
+ #controls {
62
+ position: absolute;
63
+ top: 20px;
64
+ right: 20px;
65
+ color: white;
66
+ text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
67
+ background: rgba(0,0,0,0.3);
68
+ padding: 10px;
69
+ border-radius: 5px;
70
+ }
71
+
72
+ .control-btn {
73
+ background: rgba(255,255,255,0.2);
74
+ border: none;
75
+ color: white;
76
+ padding: 5px 10px;
77
+ margin: 5px;
78
+ border-radius: 3px;
79
+ cursor: pointer;
80
+ }
81
+
82
+ .control-btn:hover {
83
+ background: rgba(255,255,255,0.3);
84
+ }
85
+ </style>
86
+ </head>
87
+ <body>
88
+ <div id="header">
89
+ <h1>Voxel Pagoda Garden</h1>
90
+ <p>Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a></p>
91
+ </div>
92
+
93
+ <div id="container"></div>
94
+
95
+ <div id="info">
96
+ <p>Drag to rotate • Scroll to zoom • Explore the pagoda and garden</p>
97
+ </div>
98
+
99
+ <div id="controls">
100
+ <button class="control-btn" id="dayNight">Toggle Day/Night</button>
101
+ <button class="control-btn" id="blossoms">Toggle Blossoms</button>
102
+ </div>
103
+
104
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
105
+ <script src="js/voxel-scene.js"></script>
106
+ </body>
107
+ </html>
js/voxel-scene.js ADDED
@@ -0,0 +1,486 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Main voxel scene script
2
+ document.addEventListener('DOMContentLoaded', function() {
3
+ // Scene setup
4
+ const scene = new THREE.Scene();
5
+ const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
6
+ const renderer = new THREE.WebGLRenderer({ antialias: true });
7
+
8
+ renderer.setSize(window.innerWidth, window.innerHeight);
9
+ renderer.setClearColor(0x87CEEB);
10
+ renderer.shadowMap.enabled = true;
11
+ renderer.shadowMap.type = THREE.PCFSoftShadowMap;
12
+
13
+ document.getElementById('container').appendChild(renderer.domElement);
14
+
15
+ // Lighting
16
+ const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
17
+ scene.add(ambientLight);
18
+
19
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
20
+ directionalLight.position.set(50, 50, 25);
21
+ directionalLight.castShadow = true;
22
+ directionalLight.shadow.mapSize.width = 2048;
23
+ directionalLight.shadow.mapSize.height = 2048;
24
+ scene.add(directionalLight);
25
+
26
+ // Voxel materials
27
+ const materials = {
28
+ wood: new THREE.MeshLambertMaterial({ color: 0x8B4513 }),
29
+ roof: new THREE.MeshLambertMaterial({ color: 0x8B0000 }),
30
+ stone: new THREE.MeshLambertMaterial({ color: 0x808080 }),
31
+ grass: new THREE.MeshLambertMaterial({ color: 0x32CD32 }),
32
+ water: new THREE.MeshLambertMaterial({ color: 0x1E90FF, transparent: true, opacity: 0.8 }),
33
+ blossom: new THREE.MeshLambertMaterial({ color: 0xFFB6C1 }),
34
+ trunk: new THREE.MeshLambertMaterial({ color: 0x8B4513 }),
35
+ leaves: new THREE.MeshLambertMaterial({ color: 0x228B22 }),
36
+ gold: new THREE.MeshLambertMaterial({ color: 0xFFD700 })
37
+ };
38
+
39
+ // Voxel size
40
+ const voxelSize = 0.5;
41
+
42
+ // Function to create a voxel
43
+ function createVoxel(x, y, z, material) {
44
+ const geometry = new THREE.BoxGeometry(voxelSize, voxelSize, voxelSize);
45
+ const voxel = new THREE.Mesh(geometry, material);
46
+ voxel.position.set(x * voxelSize, y * voxelSize, z * voxelSize);
47
+ voxel.castShadow = true;
48
+ voxel.receiveShadow = true;
49
+ return voxel;
50
+ }
51
+
52
+ // Function to create a group of voxels (building blocks)
53
+ function createVoxelStructure(structure, baseX, baseY, baseZ, material) {
54
+ const group = new THREE.Group();
55
+
56
+ for (let y = 0; y < structure.length; y++) {
57
+ for (let x = 0; x < structure[y].length; x++) {
58
+ for (let z = 0; z < structure[y][x].length; z++) {
59
+ if (structure[y][x][z] === 1) {
60
+ const voxel = createVoxel(baseX + x, baseY + y, baseZ + z, material);
61
+ group.add(voxel);
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ return group;
68
+ }
69
+
70
+ // Create ground
71
+ function createGround() {
72
+ const groundGroup = new THREE.Group();
73
+
74
+ // Grass
75
+ for (let x = -30; x <= 30; x++) {
76
+ for (let z = -30; z <= 30; z++) {
77
+ if (Math.random() > 0.3) {
78
+ const grass = createVoxel(x, 0, z, materials.grass);
79
+ groundGroup.add(grass);
80
+ }
81
+ }
82
+ }
83
+
84
+ // Pond
85
+ for (let x = -5; x <= 5; x++) {
86
+ for (let z = 15; z <= 25; z++) {
87
+ const water = createVoxel(x, 0, z, materials.water);
88
+ groundGroup.add(water);
89
+ }
90
+ }
91
+
92
+ // Stone path
93
+ for (let x = -2; x <= 2; x++) {
94
+ for (let z = -15; z <= 15; z++) {
95
+ if (Math.abs(x) <= 1 || z % 3 === 0) {
96
+ const stone = createVoxel(x, 0, z, materials.stone);
97
+ groundGroup.add(stone);
98
+ }
99
+ }
100
+ }
101
+
102
+ return groundGroup;
103
+ }
104
+
105
+ // Create pagoda
106
+ function createPagoda() {
107
+ const pagodaGroup = new THREE.Group();
108
+
109
+ // Base platform
110
+ const baseStructure = [
111
+ [ // Layer 0
112
+ [1,1,1,1,1,1,1],
113
+ [1,1,1,1,1,1,1],
114
+ [1,1,1,1,1,1,1],
115
+ [1,1,1,1,1,1,1],
116
+ [1,1,1,1,1,1,1],
117
+ [1,1,1,1,1,1,1],
118
+ [1,1,1,1,1,1,1]
119
+ ]
120
+ ];
121
+
122
+ const base = createVoxelStructure(baseStructure, -3, 1, -3, materials.stone);
123
+ pagodaGroup.add(base);
124
+
125
+ // First level
126
+ const level1Walls = [
127
+ [ // Layer 0-3
128
+ [1,1,1,1,1,1,1],
129
+ [1,0,0,0,0,0,1],
130
+ [1,0,0,0,0,0,1],
131
+ [1,0,0,0,0,0,1],
132
+ [1,0,0,0,0,0,1],
133
+ [1,0,0,0,0,0,1],
134
+ [1,1,1,1,1,1,1]
135
+ ],
136
+ [ // Repeat for height
137
+ [1,1,1,1,1,1,1],
138
+ [1,0,0,0,0,0,1],
139
+ [1,0,0,0,0,0,1],
140
+ [1,0,0,0,0,0,1],
141
+ [1,0,0,0,0,0,1],
142
+ [1,0,0,0,0,0,1],
143
+ [1,1,1,1,1,1,1]
144
+ ],
145
+ [ // Repeat for height
146
+ [1,1,1,1,1,1,1],
147
+ [1,0,0,0,0,0,1],
148
+ [1,0,0,0,0,0,1],
149
+ [1,0,0,0,0,0,1],
150
+ [1,0,0,0,0,0,1],
151
+ [1,0,0,0,0,0,1],
152
+ [1,1,1,1,1,1,1]
153
+ ]
154
+ ];
155
+
156
+ const walls1 = createVoxelStructure(level1Walls, -3, 2, -3, materials.wood);
157
+ pagodaGroup.add(walls1);
158
+
159
+ // First level roof
160
+ const roof1Structure = [
161
+ [ // Layer 0
162
+ [0,0,1,1,1,0,0],
163
+ [0,1,1,1,1,1,0],
164
+ [1,1,1,1,1,1,1],
165
+ [1,1,1,1,1,1,1],
166
+ [1,1,1,1,1,1,1],
167
+ [0,1,1,1,1,1,0],
168
+ [0,0,1,1,1,0,0]
169
+ ],
170
+ [ // Layer 1
171
+ [0,0,0,1,0,0,0],
172
+ [0,0,1,1,1,0,0],
173
+ [0,1,1,1,1,1,0],
174
+ [1,1,1,1,1,1,1],
175
+ [0,1,1,1,1,1,0],
176
+ [0,0,1,1,1,0,0],
177
+ [0,0,0,1,0,0,0]
178
+ ]
179
+ ];
180
+
181
+ const roof1 = createVoxelStructure(roof1Structure, -3, 5, -3, materials.roof);
182
+ pagodaGroup.add(roof1);
183
+
184
+ // Second level (smaller)
185
+ const level2Walls = [
186
+ [ // Layer 0-2
187
+ [0,0,1,1,1,0,0],
188
+ [0,1,0,0,0,1,0],
189
+ [1,0,0,0,0,0,1],
190
+ [1,0,0,0,0,0,1],
191
+ [1,0,0,0,0,0,1],
192
+ [0,1,0,0,0,1,0],
193
+ [0,0,1,1,1,0,0]
194
+ ],
195
+ [ // Repeat for height
196
+ [0,0,1,1,1,0,0],
197
+ [0,1,0,0,0,1,0],
198
+ [1,0,0,0,0,0,1],
199
+ [1,0,0,0,0,0,1],
200
+ [1,0,0,0,0,0,1],
201
+ [0,1,0,0,0,1,0],
202
+ [0,0,1,1,1,0,0]
203
+ ]
204
+ ];
205
+
206
+ const walls2 = createVoxelStructure(level2Walls, -2, 7, -2, materials.wood);
207
+ pagodaGroup.add(walls2);
208
+
209
+ // Second level roof
210
+ const roof2Structure = [
211
+ [ // Layer 0
212
+ [0,0,0,1,0,0,0],
213
+ [0,0,1,1,1,0,0],
214
+ [0,1,1,1,1,1,0],
215
+ [1,1,1,1,1,1,1],
216
+ [0,1,1,1,1,1,0],
217
+ [0,0,1,1,1,0,0],
218
+ [0,0,0,1,0,0,0]
219
+ ],
220
+ [ // Layer 1
221
+ [0,0,0,0,0,0,0],
222
+ [0,0,0,1,0,0,0],
223
+ [0,0,1,1,1,0,0],
224
+ [0,1,1,1,1,1,0],
225
+ [0,0,1,1,1,0,0],
226
+ [0,0,0,1,0,0,0],
227
+ [0,0,0,0,0,0,0]
228
+ ]
229
+ ];
230
+
231
+ const roof2 = createVoxelStructure(roof2Structure, -2, 9, -2, materials.roof);
232
+ pagodaGroup.add(roof2);
233
+
234
+ // Third level (even smaller)
235
+ const level3Walls = [
236
+ [ // Layer 0-2
237
+ [0,0,0,1,0,0,0],
238
+ [0,0,1,0,1,0,0],
239
+ [0,1,0,0,0,1,0],
240
+ [1,0,0,0,0,0,1],
241
+ [0,1,0,0,0,1,0],
242
+ [0,0,1,0,1,0,0],
243
+ [0,0,0,1,0,0,0]
244
+ ],
245
+ [ // Repeat for height
246
+ [0,0,0,1,0,0,0],
247
+ [0,0,1,0,1,0,0],
248
+ [0,1,0,0,0,1,0],
249
+ [1,0,0,0,0,0,1],
250
+ [0,1,0,0,0,1,0],
251
+ [0,0,1,0,1,0,0],
252
+ [0,0,0,1,0,0,0]
253
+ ]
254
+ ];
255
+
256
+ const walls3 = createVoxelStructure(level3Walls, -1, 11, -1, materials.wood);
257
+ pagodaGroup.add(walls3);
258
+
259
+ // Third level roof
260
+ const roof3Structure = [
261
+ [ // Layer 0
262
+ [0,0,0,0,0,0,0],
263
+ [0,0,0,1,0,0,0],
264
+ [0,0,1,1,1,0,0],
265
+ [0,1,1,1,1,1,0],
266
+ [0,0,1,1,1,0,0],
267
+ [0,0,0,1,0,0,0],
268
+ [0,0,0,0,0,0,0]
269
+ ],
270
+ [ // Layer 1
271
+ [0,0,0,0,0,0,0],
272
+ [0,0,0,0,0,0,0],
273
+ [0,0,0,1,0,0,0],
274
+ [0,0,1,1,1,0,0],
275
+ [0,0,0,1,0,0,0],
276
+ [0,0,0,0,0,0,0],
277
+ [0,0,0,0,0,0,0]
278
+ ]
279
+ ];
280
+
281
+ const roof3 = createVoxelStructure(roof3Structure, -1, 13, -1, materials.roof);
282
+ pagodaGroup.add(roof3);
283
+
284
+ // Spire
285
+ for (let i = 0; i < 5; i++) {
286
+ const spire = createVoxel(0, 15 + i, 0, materials.gold);
287
+ pagodaGroup.add(spire);
288
+ }
289
+
290
+ return pagodaGroup;
291
+ }
292
+
293
+ // Create cherry blossom trees
294
+ function createCherryBlossomTree(x, z) {
295
+ const treeGroup = new THREE.Group();
296
+
297
+ // Trunk
298
+ for (let i = 0; i < 4; i++) {
299
+ const trunkPiece = createVoxel(x, i + 1, z, materials.trunk);
300
+ treeGroup.add(trunkPiece);
301
+ }
302
+
303
+ // Leaves and blossoms (spherical shape)
304
+ for (let y = 4; y < 8; y++) {
305
+ for (let dx = -2; dx <= 2; dx++) {
306
+ for (let dz = -2; dz <= 2; dz++) {
307
+ const distance = Math.sqrt(dx*dx + dz*dz + (y-6)*(y-6));
308
+ if (distance < 2.5) {
309
+ // Randomly choose between leaves and blossoms
310
+ const material = Math.random() > 0.7 ? materials.blossom : materials.leaves;
311
+ const leaf = createVoxel(x + dx, y, z + dz, material);
312
+ treeGroup.add(leaf);
313
+ }
314
+ }
315
+ }
316
+ }
317
+
318
+ return treeGroup;
319
+ }
320
+
321
+ // Create garden elements
322
+ function createGarden() {
323
+ const gardenGroup = new THREE.Group();
324
+
325
+ // Create several cherry blossom trees around the pagoda
326
+ const treePositions = [
327
+ [-10, -10], [10, -10], [-10, 10], [10, 10],
328
+ [-15, 0], [15, 0], [0, -15], [0, 15],
329
+ [-8, 5], [8, -5], [-5, -8], [5, 8]
330
+ ];
331
+
332
+ treePositions.forEach(pos => {
333
+ const tree = createCherryBlossomTree(pos[0], pos[1]);
334
+ gardenGroup.add(tree);
335
+ });
336
+
337
+ // Create some decorative rocks
338
+ for (let i = 0; i < 10; i++) {
339
+ const rockX = Math.random() * 20 - 10;
340
+ const rockZ = Math.random() * 20 - 10;
341
+
342
+ // Small cluster of rocks
343
+ for (let j = 0; j < 3; j++) {
344
+ const rock = createVoxel(
345
+ rockX + Math.random() * 2 - 1,
346
+ 1,
347
+ rockZ + Math.random() * 2 - 1,
348
+ materials.stone
349
+ );
350
+ gardenGroup.add(rock);
351
+ }
352
+ }
353
+
354
+ return gardenGroup;
355
+ }
356
+
357
+ // Add everything to the scene
358
+ const ground = createGround();
359
+ scene.add(ground);
360
+
361
+ const pagoda = createPagoda();
362
+ scene.add(pagoda);
363
+
364
+ const garden = createGarden();
365
+ scene.add(garden);
366
+
367
+ // Camera position
368
+ camera.position.set(15, 10, 15);
369
+ camera.lookAt(0, 5, 0);
370
+
371
+ // Controls
372
+ let isDragging = false;
373
+ let previousMousePosition = {
374
+ x: 0,
375
+ y: 0
376
+ };
377
+
378
+ // Mouse events for camera control
379
+ document.addEventListener('mousedown', (e) => {
380
+ isDragging = true;
381
+ });
382
+
383
+ document.addEventListener('mousemove', (e) => {
384
+ if (!isDragging) return;
385
+
386
+ const deltaMove = {
387
+ x: e.clientX - previousMousePosition.x,
388
+ y: e.clientY - previousMousePosition.y
389
+ };
390
+
391
+ // Rotate camera around the scene center
392
+ const radius = Math.sqrt(
393
+ camera.position.x * camera.position.x +
394
+ camera.position.z * camera.position.z
395
+ );
396
+
397
+ let theta = Math.atan2(camera.position.z, camera.position.x) + deltaMove.x * 0.01;
398
+ let phi = Math.atan2(Math.sqrt(camera.position.x * camera.position.x + camera.position.z * camera.position.z), camera.position.y) + deltaMove.y * 0.01;
399
+
400
+ // Limit vertical rotation
401
+ phi = Math.max(0.1, Math.min(Math.PI / 2, phi));
402
+
403
+ camera.position.x = radius * Math.sin(phi) * Math.cos(theta);
404
+ camera.position.y = radius * Math.cos(phi);
405
+ camera.position.z = radius * Math.sin(phi) * Math.sin(theta);
406
+
407
+ camera.lookAt(0, 5, 0);
408
+
409
+ previousMousePosition = {
410
+ x: e.clientX,
411
+ y: e.clientY
412
+ };
413
+ });
414
+
415
+ document.addEventListener('mouseup', () => {
416
+ isDragging = false;
417
+ });
418
+
419
+ document.addEventListener('wheel', (e) => {
420
+ // Zoom in/out
421
+ const zoomSpeed = 0.1;
422
+ const direction = e.deltaY > 0 ? 1 : -1;
423
+
424
+ camera.position.x += camera.position.x * direction * zoomSpeed;
425
+ camera.position.y += camera.position.y * direction * zoomSpeed;
426
+ camera.position.z += camera.position.z * direction * zoomSpeed;
427
+
428
+ camera.lookAt(0, 5, 0);
429
+ });
430
+
431
+ // Store initial mouse position
432
+ document.addEventListener('mousemove', (e) => {
433
+ previousMousePosition = {
434
+ x: e.clientX,
435
+ y: e.clientY
436
+ };
437
+ });
438
+
439
+ // Day/Night toggle
440
+ let isNight = false;
441
+ document.getElementById('dayNight').addEventListener('click', () => {
442
+ isNight = !isNight;
443
+
444
+ if (isNight) {
445
+ renderer.setClearColor(0x000033);
446
+ directionalLight.intensity = 0.3;
447
+ ambientLight.intensity = 0.2;
448
+ } else {
449
+ renderer.setClearColor(0x87CEEB);
450
+ directionalLight.intensity = 1;
451
+ ambientLight.intensity = 0.6;
452
+ }
453
+ });
454
+
455
+ // Blossoms toggle
456
+ let blossomsVisible = true;
457
+ document.getElementById('blossoms').addEventListener('click', () => {
458
+ blossomsVisible = !blossomsVisible;
459
+
460
+ // Toggle visibility of blossom materials
461
+ scene.traverse((child) => {
462
+ if (child.isMesh && child.material === materials.blossom) {
463
+ child.visible = blossomsVisible;
464
+ }
465
+ });
466
+ });
467
+
468
+ // Handle window resize
469
+ window.addEventListener('resize', () => {
470
+ camera.aspect = window.innerWidth / window.innerHeight;
471
+ camera.updateProjectionMatrix();
472
+ renderer.setSize(window.innerWidth, window.innerHeight);
473
+ });
474
+
475
+ // Animation loop
476
+ function animate() {
477
+ requestAnimationFrame(animate);
478
+
479
+ // Gentle rotation of the scene
480
+ scene.rotation.y += 0.001;
481
+
482
+ renderer.render(scene, camera);
483
+ }
484
+
485
+ animate();
486
+ });