ginipick commited on
Commit
5ec2448
·
verified ·
1 Parent(s): 12bcf64

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +366 -456
index.html CHANGED
@@ -1,506 +1,416 @@
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>Personalized Baby Name Generator</title>
7
  <style>
8
- :root {
9
- --primary: #FF9FB0;
10
- --secondary: #A6D9F7;
11
- --accent: #B6E6BD;
12
- --dark: #2D3748;
13
- --light: #F7FAFC;
14
- --shadow: rgba(0, 0, 0, 0.1);
15
- }
16
-
17
- * {
18
- margin: 0;
19
- padding: 0;
20
- box-sizing: border-box;
21
- font-family: 'Segoe UI', Arial, sans-serif;
22
- }
23
-
24
- body {
25
- background: linear-gradient(135deg, #f6f8fc 0%, #fff 100%);
26
- color: var(--dark);
27
- min-height: 100vh;
28
- padding: 2rem;
29
- }
30
-
31
- .container {
32
- max-width: 1000px;
33
- margin: 0 auto;
34
- }
35
-
36
- .header {
37
- text-align: center;
38
- padding: 2rem;
39
- background: white;
40
- border-radius: 1rem;
41
- box-shadow: 0 4px 6px var(--shadow);
42
- margin-bottom: 2rem;
43
- }
44
-
45
- .header h1 {
46
- color: var(--primary);
47
- font-size: 2.5rem;
48
- margin-bottom: 0.5rem;
49
- }
50
-
51
- .generator-form {
52
- display: grid;
53
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
54
- gap: 2rem;
55
- }
56
-
57
- .form-section {
58
- background: white;
59
- padding: 1.5rem;
60
- border-radius: 1rem;
61
- box-shadow: 0 4px 6px var(--shadow);
62
- }
63
-
64
- .form-section h2 {
65
- color: var(--secondary);
66
- margin-bottom: 1rem;
67
- font-size: 1.5rem;
68
- }
69
-
70
- .input-group {
71
- margin-bottom: 1rem;
72
- }
73
-
74
- .input-group label {
75
- display: block;
76
- margin-bottom: 0.5rem;
77
- color: var(--dark);
78
- font-weight: 500;
79
- }
80
-
81
- select, input {
82
  width: 100%;
83
- padding: 0.75rem;
84
- border: 2px solid #E2E8F0;
85
- border-radius: 0.5rem;
86
- font-size: 1rem;
87
- transition: all 0.3s ease;
88
- }
89
-
90
- select:focus, input:focus {
91
- border-color: var(--primary);
92
- outline: none;
93
- box-shadow: 0 0 0 3px rgba(255, 159, 176, 0.2);
94
- }
95
-
96
- .traits-container {
97
- display: grid;
98
- grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
99
- gap: 0.5rem;
100
- margin-top: 0.5rem;
101
- }
102
-
103
- .trait-chip {
104
- padding: 0.5rem;
105
- background: var(--light);
106
- border: 1px solid #E2E8F0;
107
- border-radius: 2rem;
108
- cursor: pointer;
109
- text-align: center;
110
- transition: all 0.3s ease;
111
  }
 
 
 
 
 
 
 
112
 
113
- .trait-chip.selected {
114
- background: var(--primary);
115
- color: white;
116
- border-color: var(--primary);
117
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
- .generate-btn {
120
- background: var(--primary);
121
- color: white;
122
- border: none;
123
- padding: 1rem 2rem;
124
- border-radius: 0.5rem;
125
- font-size: 1.1rem;
126
- font-weight: 600;
127
- cursor: pointer;
128
- width: 100%;
129
- transition: all 0.3s ease;
130
- margin-top: 1rem;
131
- }
132
 
133
- .generate-btn:hover {
134
- transform: translateY(-2px);
135
- box-shadow: 0 4px 12px rgba(255, 159, 176, 0.3);
136
- }
137
 
138
- .results-section {
139
- margin-top: 2rem;
140
- background: white;
141
- padding: 2rem;
142
- border-radius: 1rem;
143
- box-shadow: 0 4px 6px var(--shadow);
144
- }
145
 
146
- .name-card {
147
- background: var(--light);
148
- padding: 1.5rem;
149
- border-radius: 0.5rem;
150
- margin-bottom: 1rem;
151
- display: flex;
152
- justify-content: space-between;
153
- align-items: center;
154
- transition: all 0.3s ease;
155
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
- .name-card:hover {
158
- transform: translateX(5px);
159
- background: #F0F7FF;
 
 
 
 
 
160
  }
161
 
162
- .name-details h3 {
163
- color: var(--primary);
164
- font-size: 1.5rem;
165
- margin-bottom: 0.5rem;
166
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
- .name-meaning {
169
- font-size: 0.9rem;
170
- color: #666;
 
 
 
 
 
 
 
171
  }
172
 
173
- .personality-tags {
174
- display: flex;
175
- gap: 0.5rem;
176
- flex-wrap: wrap;
177
- margin-top: 0.5rem;
178
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
 
180
- .personality-tag {
181
- background: var(--secondary);
182
- color: white;
183
- padding: 0.25rem 0.75rem;
184
- border-radius: 1rem;
185
- font-size: 0.8rem;
186
- }
187
 
188
- .favorite-btn {
189
- background: none;
190
- border: none;
191
- font-size: 1.5rem;
192
- cursor: pointer;
193
- transition: all 0.3s ease;
194
- }
195
 
196
- .favorite-btn:hover {
197
- transform: scale(1.2);
198
  }
199
 
200
- .favorites-section {
201
- margin-top: 2rem;
202
- background: white;
203
- padding: 2rem;
204
- border-radius: 1rem;
205
- box-shadow: 0 4px 6px var(--shadow);
206
  }
207
 
208
- .favorites-section h2 {
209
- color: var(--primary);
210
- margin-bottom: 1rem;
211
  }
212
 
213
- @keyframes fadeIn {
214
- from { opacity: 0; transform: translateY(10px); }
215
- to { opacity: 1; transform: translateY(0); }
216
- }
217
 
218
- .name-card {
219
- animation: fadeIn 0.5s ease forwards;
220
- }
 
 
 
 
221
 
222
- @media (max-width: 768px) {
223
- .container {
224
- padding: 1rem;
 
 
 
 
225
  }
226
 
227
- .generator-form {
228
- grid-template-columns: 1fr;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  }
230
- }
231
- </style>
232
- </head>
233
- <body>
234
- <div class="container">
235
- <div class="header">
236
- <h1>👶 Personalized Baby Name Generator</h1>
237
- <p>Create the perfect name based on your family's unique characteristics</p>
238
- </div>
239
-
240
- <div class="generator-form">
241
- <div class="form-section">
242
- <h2>Basic Information</h2>
243
- <div class="input-group">
244
- <label for="gender">Baby's Gender</label>
245
- <select id="gender">
246
- <option value="all">All</option>
247
- <option value="boy">Boy</option>
248
- <option value="girl">Girl</option>
249
- <option value="neutral">Gender Neutral</option>
250
- </select>
251
- </div>
252
-
253
- <div class="input-group">
254
- <label for="origin">Cultural Background</label>
255
- <select id="origin" multiple>
256
- <option value="english">English</option>
257
- <option value="french">French</option>
258
- <option value="spanish">Spanish</option>
259
- <option value="italian">Italian</option>
260
- <option value="greek">Greek</option>
261
- <option value="celtic">Celtic</option>
262
- <option value="nordic">Nordic</option>
263
- <option value="hebrew">Hebrew</option>
264
- <option value="arabic">Arabic</option>
265
- <option value="persian">Persian</option>
266
- <option value="indian">Indian</option>
267
- <option value="chinese">Chinese</option>
268
- <option value="japanese">Japanese</option>
269
- <option value="korean">Korean</option>
270
- </select>
271
- </div>
272
- </div>
273
-
274
- <div class="form-section">
275
- <h2>Mother's Characteristics</h2>
276
- <div class="input-group">
277
- <label>Select Personality Traits</label>
278
- <div class="traits-container" id="motherTraits">
279
- <div class="trait-chip" data-trait="creative">Creative</div>
280
- <div class="trait-chip" data-trait="intelligent">Intelligent</div>
281
- <div class="trait-chip" data-trait="caring">Caring</div>
282
- <div class="trait-chip" data-trait="strong">Strong</div>
283
- <div class="trait-chip" data-trait="artistic">Artistic</div>
284
- <div class="trait-chip" data-trait="adventurous">Adventurous</div>
285
- <div class="trait-chip" data-trait="peaceful">Peaceful</div>
286
- <div class="trait-chip" data-trait="wise">Wise</div>
287
- </div>
288
- </div>
289
- </div>
290
-
291
- <div class="form-section">
292
- <h2>Father's Characteristics</h2>
293
- <div class="input-group">
294
- <label>Select Personality Traits</label>
295
- <div class="traits-container" id="fatherTraits">
296
- <div class="trait-chip" data-trait="protective">Protective</div>
297
- <div class="trait-chip" data-trait="loyal">Loyal</div>
298
- <div class="trait-chip" data-trait="brave">Brave</div>
299
- <div class="trait-chip" data-trait="gentle">Gentle</div>
300
- <div class="trait-chip" data-trait="ambitious">Ambitious</div>
301
- <div class="trait-chip" data-trait="wise">Wise</div>
302
- <div class="trait-chip" data-trait="humorous">Humorous</div>
303
- <div class="trait-chip" data-trait="athletic">Athletic</div>
304
- </div>
305
- </div>
306
- </div>
307
- </div>
308
-
309
- <button class="generate-btn" onclick="generateNames()">Generate Perfect Names</button>
310
-
311
- <div class="results-section" id="results">
312
- <!-- Generated names will appear here -->
313
- </div>
314
-
315
- <div class="favorites-section">
316
- <h2>❤️ Favorite Names</h2>
317
- <div id="favoritesList"></div>
318
- </div>
319
- </div>
320
 
321
- <script>
322
- // Extended name database with meanings and trait associations
323
- const nameDatabase = {
324
- boy: {
325
- creative: ['Leonardo', 'Byron', 'Vincent', 'Aiden'],
326
- intelligent: ['Solomon', 'Ethan', 'Adrian', 'Theodore'],
327
- strong: ['Alexander', 'Thor', 'Viktor', 'Bruno'],
328
- protective: ['William', 'Guardian', 'Ward', 'Reign'],
329
- brave: ['Valor', 'Leo', 'Wyatt', 'Ethan'],
330
- gentle: ['Oliver', 'Liam', 'Noah', 'Benjamin'],
331
- wise: ['Sage', 'Solomon', 'Alvis', 'Kenneth']
332
- },
333
- girl: {
334
- creative: ['Luna', 'Aurora', 'Aria', 'Maya'],
335
- intelligent: ['Sophia', 'Athena', 'Claire', 'Ada'],
336
- caring: ['Grace', 'Hannah', 'Lily', 'Mira'],
337
- artistic: ['Melody', 'Violet', 'Iris', 'Aria'],
338
- peaceful: ['Serena', 'Dove', 'Paz', 'Shanti'],
339
- wise: ['Sophia', 'Minerva', 'Sage', 'Alena']
340
- },
341
- neutral: {
342
- creative: ['Alex', 'River', 'Sky', 'Phoenix'],
343
- strong: ['Morgan', 'Kai', 'Atlas', 'Storm'],
344
- wise: ['Sage', 'Quinn', 'Blair', 'Eden'],
345
- peaceful: ['Harmony', 'Peace', 'Robin', 'Dawn']
346
  }
347
- };
348
-
349
- // Name meanings database
350
- const nameMeanings = {
351
- 'Alexander': 'Defender of the people',
352
- 'Sophia': 'Wisdom',
353
- 'Luna': 'Moon',
354
- 'Ethan': 'Strong, enduring',
355
- 'Grace': 'Elegance and divine favor',
356
- // Add more meanings as needed
357
- };
358
-
359
- let favorites = new Set();
360
- let selectedTraits = {
361
- mother: new Set(),
362
- father: new Set()
363
- };
364
-
365
- // Setup trait selection
366
- document.querySelectorAll('.trait-chip').forEach(chip => {
367
- chip.addEventListener('click', () => {
368
- const parent = chip.parentElement.id;
369
- const trait = chip.dataset.trait;
370
- const traitSet = parent === 'motherTraits' ? selectedTraits.mother : selectedTraits.father;
371
-
372
- chip.classList.toggle('selected');
373
- if (traitSet.has(trait)) {
374
- traitSet.delete(trait);
375
- } else {
376
- traitSet.add(trait);
377
- }
378
- });
379
- });
380
-
381
- function generateNames() {
382
- const gender = document.getElementById('gender').value;
383
- const origins = Array.from(document.getElementById('origin').selectedOptions).map(option => option.value);
384
-
385
- let names = new Set();
386
- const traits = [...selectedTraits.mother, ...selectedTraits.father];
387
-
388
- // Generate names based on selected traits
389
- traits.forEach(trait => {
390
- if (gender === 'all' || gender === 'neutral') {
391
- if (nameDatabase.neutral[trait]) {
392
- nameDatabase.neutral[trait].forEach(name => names.add(name));
393
- }
394
- }
395
- if (gender === 'all' || gender === 'boy') {
396
- if (nameDatabase.boy[trait]) {
397
- nameDatabase.boy[trait].forEach(name => names.add(name));
398
- }
399
- }
400
- if (gender === 'all' || gender === 'girl') {
401
- if (nameDatabase.girl[trait]) {
402
- nameDatabase.girl[trait].forEach(name => names.add(name));
403
- }
404
- }
405
- });
406
-
407
- displayResults(Array.from(names));
408
  }
409
 
410
- function displayResults(names) {
411
- const resultsDiv = document.getElementById('results');
412
- resultsDiv.innerHTML = '<h2>Suggested Names</h2>';
413
-
414
- if (names.length === 0) {
415
- resultsDiv.innerHTML += '<p>No names match your criteria. Try selecting different traits.</p>';
416
- return;
417
  }
418
-
419
- names.forEach((name, index) => {
420
- const nameCard = document.createElement('div');
421
- nameCard.className = 'name-card';
422
- nameCard.style.animationDelay = `${index * 0.1}s`;
423
-
424
- const relatedTraits = findRelatedTraits(name);
425
- const meaning = nameMeanings[name] || 'A beautiful name';
426
-
427
- nameCard.innerHTML = `
428
- <div class="name-details">
429
- <h3>${name}</h3>
430
- <div class="name-meaning">${meaning}</div>
431
- <div class="personality-tags">
432
- ${relatedTraits.map(trait =>
433
- `<span class="personality-tag">${trait}</span>`
434
- ).join('')}
435
- </div>
436
- </div>
437
- <button class="favorite-btn" onclick="toggleFavorite('${name}')">
438
- ${favorites.has(name) ? '❤️' : '🤍'}
439
- </button>
440
- `;
441
-
442
- resultsDiv.appendChild(nameCard);
443
- });
444
  }
445
 
446
- function findRelatedTraits(name) {
447
- let traits = new Set();
448
-
449
- Object.entries(nameDatabase).forEach(([gender, traitGroups]) => {
450
- Object.entries(traitGroups).forEach(([trait, names]) => {
451
- if (names.includes(name)) {
452
- traits.add(trait);
453
- }
454
- });
455
- });
456
 
457
- return Array.from(traits);
 
 
 
 
458
  }
459
 
460
- function toggleFavorite(name) {
461
- if (favorites.has(name)) {
462
- favorites.delete(name);
463
- } else {
464
- favorites.add(name);
 
 
 
 
465
  }
466
- updateFavorites();
467
- generateNames(); // Refresh current results
468
  }
469
 
470
- function updateFavorites() {
471
- const favoritesList = document.getElementById('favoritesList');
472
- favoritesList.innerHTML = '';
473
-
474
- if (favorites.size === 0) {
475
- favoritesList.innerHTML = '<p>No favorite names yet</p>';
476
- return;
477
  }
 
478
 
479
- [...favorites].forEach(name => {
480
- const nameCard = document.createElement('div');
481
- nameCard.className = 'name-card';
482
- const relatedTraits = findRelatedTraits(name);
483
- const meaning = nameMeanings[name] || 'A beautiful name';
484
-
485
- nameCard.innerHTML = `
486
- <div class="name-details">
487
- <h3>${name}</h3>
488
- <div class="name-meaning">${meaning}</div>
489
- <div class="personality-tags">
490
- ${relatedTraits.map(trait =>
491
- `<span class="personality-tag">${trait}</span>`
492
- ).join('')}
493
- </div>
494
- </div>
495
- <button class="favorite-btn" onclick="toggleFavorite('${name}')">❤️</button>
496
- `;
497
-
498
- favoritesList.appendChild(nameCard);
499
- });
500
  }
501
 
502
- // Initialize with empty results
503
- generateNames();
 
 
 
 
504
  </script>
505
  </body>
506
  </html>
 
1
  <!DOCTYPE html>
2
+ <html>
3
  <head>
4
+ <title>Forest Explorer</title>
 
 
5
  <style>
6
+ body { margin: 0; background: black; overflow: hidden; }
7
+ canvas { width: 100vw; height: 100vh; }
8
+ .ui {
9
+ position: fixed;
10
+ color: white;
11
+ text-shadow: 2px 2px 2px rgba(0,0,0,0.5);
12
+ pointer-events: none;
13
+ font-family: Arial, sans-serif;
14
+ }
15
+ #stamina {
16
+ bottom: 20px;
17
+ left: 20px;
18
+ width: 200px;
19
+ height: 5px;
20
+ background: rgba(0,0,0,0.5);
21
+ border-radius: 3px;
22
+ }
23
+ #stamina-bar {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  width: 100%;
25
+ height: 100%;
26
+ background: #4CAF50;
27
+ border-radius: 3px;
28
+ transition: width 0.2s;
29
+ }
30
+ #crosshair {
31
+ top: 50%;
32
+ left: 50%;
33
+ transform: translate(-50%, -50%);
34
+ font-size: 20px;
35
+ }
36
+ #flashlight-status {
37
+ top: 20px;
38
+ right: 20px;
39
+ }
40
+ .vignette {
41
+ position: fixed;
42
+ top: 0;
43
+ left: 0;
44
+ width: 100%;
45
+ height: 100%;
46
+ background: radial-gradient(circle, transparent 50%, rgba(0,0,0,0.4) 100%);
47
+ pointer-events: none;
 
 
 
 
 
48
  }
49
+ </style>
50
+ </head>
51
+ <body>
52
+ <div id="stamina" class="ui"><div id="stamina-bar"></div></div>
53
+ <div id="crosshair" class="ui">+</div>
54
+ <div id="flashlight-status" class="ui">Flashlight [F]</div>
55
+ <div class="vignette"></div>
56
 
57
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
58
+ <script>
59
+ const SPAWN_POSITION = new THREE.Vector3(0, 1.7, 30); // Spawn point
60
+ const CAVE_ENTRANCE = new THREE.Vector3(0, 1.7, -15); // Cave entrance position
61
+
62
+ let camera, scene, renderer, clock;
63
+ let player = {
64
+ position: SPAWN_POSITION.clone(),
65
+ velocity: new THREE.Vector3(),
66
+ speed: {
67
+ walk: 3.5,
68
+ sprint: 7,
69
+ current: 3.5
70
+ },
71
+ stamina: 100,
72
+ headBob: {
73
+ value: 0,
74
+ intensity: 0.07,
75
+ speed: 8
76
+ },
77
+ inCave: false
78
+ };
79
 
80
+ let controls = {
81
+ forward: false,
82
+ backward: false,
83
+ left: false,
84
+ right: false,
85
+ sprint: false
86
+ };
 
 
 
 
 
 
87
 
88
+ let flashlight;
89
+ let isFlashlightOn = false;
 
 
90
 
91
+ // Initialize game
92
+ init();
93
+ animate();
 
 
 
 
94
 
95
+ async function init() {
96
+ // Setup basic scene
97
+ scene = new THREE.Scene();
98
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
99
+ clock = new THREE.Clock();
100
+
101
+ // Setup renderer
102
+ renderer = new THREE.WebGLRenderer({antialias: true});
103
+ renderer.setSize(window.innerWidth, window.innerHeight);
104
+ renderer.shadowMap.enabled = true;
105
+ renderer.shadowMap.type = THREE.PCFSoftShadowMap;
106
+ document.body.appendChild(renderer.domElement);
107
+
108
+ // Setup scene elements
109
+ createForest();
110
+ createCave();
111
+ setupLighting();
112
+ setupParticles();
113
+ setupAudio();
114
+
115
+ // Initialize player
116
+ camera.position.copy(player.position);
117
+ document.addEventListener('keydown', onKeyDown);
118
+ document.addEventListener('keyup', onKeyUp);
119
+ document.addEventListener('mousemove', onMouseMove);
120
+ document.addEventListener('click', () => document.body.requestPointerLock());
121
+ }
122
+
123
+ function createForest() {
124
+ // Ground
125
+ const ground = new THREE.Mesh(
126
+ new THREE.PlaneGeometry(200, 200),
127
+ new THREE.MeshStandardMaterial({
128
+ color: 0x33aa33,
129
+ roughness: 0.8
130
+ })
131
+ );
132
+ ground.rotation.x = -Math.PI/2;
133
+ ground.receiveShadow = true;
134
+ scene.add(ground);
135
+
136
+ // Trees
137
+ for(let i = 0; i < 500; i++) {
138
+ const distance = Math.random() * 80 + 20;
139
+ const angle = Math.random() * Math.PI * 2;
140
+ const x = Math.cos(angle) * distance;
141
+ const z = Math.sin(angle) * distance;
142
+
143
+ if(Math.abs(x) > 10 || z > 0) { // Keep path to cave clear
144
+ createTree(x, z);
145
+ }
146
+ }
147
 
148
+ // Flowers and grass
149
+ for(let i = 0; i < 1000; i++) {
150
+ const x = Math.random() * 180 - 90;
151
+ const z = Math.random() * 180 - 90;
152
+ if(Math.abs(x) > 5 || z > 0) {
153
+ createVegetation(x, z);
154
+ }
155
+ }
156
  }
157
 
158
+ function createTree(x, z) {
159
+ const trunk = new THREE.Mesh(
160
+ new THREE.CylinderGeometry(0.5, 0.7, 5),
161
+ new THREE.MeshStandardMaterial({color: 0x885533})
162
+ );
163
+ const leaves = new THREE.Mesh(
164
+ new THREE.SphereGeometry(2),
165
+ new THREE.MeshStandardMaterial({color: 0x227722})
166
+ );
167
+
168
+ trunk.position.set(x, 2.5, z);
169
+ leaves.position.set(x, 6, z);
170
+
171
+ trunk.castShadow = true;
172
+ leaves.castShadow = true;
173
+
174
+ scene.add(trunk);
175
+ scene.add(leaves);
176
+ }
177
+
178
+ function createVegetation(x, z) {
179
+ const color = Math.random() > 0.5 ? 0xff99cc : 0xffff99;
180
+ const flower = new THREE.Mesh(
181
+ new THREE.SphereGeometry(0.2),
182
+ new THREE.MeshStandardMaterial({
183
+ color: color,
184
+ emissive: color,
185
+ emissiveIntensity: 0.2
186
+ })
187
+ );
188
+ flower.position.set(x, 0.2, z);
189
+ scene.add(flower);
190
+ }
191
+
192
+ function createCave() {
193
+ // Main tunnel
194
+ const points = [];
195
+ for(let i = 0; i < 10; i++) {
196
+ points.push(
197
+ new THREE.Vector3(
198
+ Math.sin(i/2) * 2,
199
+ Math.cos(i/3) * 1.5,
200
+ -15 - i * 5
201
+ )
202
+ );
203
+ }
204
+
205
+ const tunnelGeometry = new THREE.TubeGeometry(
206
+ new THREE.CatmullRomCurve3(points),
207
+ 60,
208
+ 3,
209
+ 8,
210
+ false
211
+ );
212
+
213
+ const caveMaterial = new THREE.MeshStandardMaterial({
214
+ color: 0x333333,
215
+ roughness: 1,
216
+ side: THREE.BackSide
217
+ });
218
+
219
+ const tunnel = new THREE.Mesh(tunnelGeometry, caveMaterial);
220
+ scene.add(tunnel);
221
+
222
+ // Cave markings
223
+ const markingGeometry = new THREE.CircleGeometry(0.3, 16);
224
+ const markingMaterial = new THREE.MeshStandardMaterial({
225
+ color: 0xff0000,
226
+ emissive: 0xff0000,
227
+ emissiveIntensity: 0.5
228
+ });
229
 
230
+ for(let i = 0; i < 15; i++) {
231
+ const marking = new THREE.Mesh(markingGeometry, markingMaterial);
232
+ marking.position.set(
233
+ Math.random() * 4 - 2,
234
+ Math.random() * 2 + 1,
235
+ -20 - Math.random() * 30
236
+ );
237
+ marking.rotation.y = Math.random() * Math.PI;
238
+ scene.add(marking);
239
+ }
240
  }
241
 
242
+ function setupLighting() {
243
+ // Forest lighting
244
+ const ambientLight = new THREE.AmbientLight(0x666666);
245
+ scene.add(ambientLight);
246
+
247
+ const sunLight = new THREE.DirectionalLight(0xffffbb, 1);
248
+ sunLight.position.set(50, 100, 50);
249
+ sunLight.castShadow = true;
250
+ scene.add(sunLight);
251
+
252
+ // Flashlight
253
+ flashlight = new THREE.SpotLight(0xffffff, 1);
254
+ flashlight.angle = Math.PI/6;
255
+ flashlight.penumbra = 0.1;
256
+ flashlight.decay = 2;
257
+ flashlight.distance = 30;
258
+ flashlight.visible = false;
259
+ camera.add(flashlight);
260
+ scene.add(camera);
261
+ }
262
+
263
+ function setupParticles() {
264
+ // Pollen/leaves particle system
265
+ const particleCount = 1000;
266
+ const positions = new Float32Array(particleCount * 3);
267
+ const colors = new Float32Array(particleCount * 3);
268
+
269
+ for(let i = 0; i < particleCount * 3; i += 3) {
270
+ positions[i] = Math.random() * 200 - 100;
271
+ positions[i+1] = Math.random() * 20;
272
+ positions[i+2] = Math.random() * 200 - 100;
273
+
274
+ colors[i] = 1;
275
+ colors[i+1] = 1;
276
+ colors[i+2] = 0.8;
277
+ }
278
 
279
+ const geometry = new THREE.BufferGeometry();
280
+ geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
281
+ geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
 
 
 
 
282
 
283
+ const material = new THREE.PointsMaterial({
284
+ size: 0.1,
285
+ vertexColors: true,
286
+ transparent: true,
287
+ opacity: 0.6
288
+ });
 
289
 
290
+ const particles = new THREE.Points(geometry, material);
291
+ scene.add(particles);
292
  }
293
 
294
+ function setupAudio() {
295
+ // Implement audio setup
 
 
 
 
296
  }
297
 
298
+ function update(delta) {
299
+ updatePlayer(delta);
300
+ updateEnvironment();
301
  }
302
 
303
+ function updatePlayer(delta) {
304
+ if(!document.pointerLockElement) return;
 
 
305
 
306
+ // Movement direction
307
+ const direction = new THREE.Vector3();
308
+ if(controls.forward) direction.z -= 1;
309
+ if(controls.backward) direction.z += 1;
310
+ if(controls.left) direction.x -= 1;
311
+ if(controls.right) direction.x += 1;
312
+ direction.normalize();
313
 
314
+ // Speed and stamina
315
+ if(controls.sprint && player.stamina > 0 && direction.length() > 0) {
316
+ player.speed.current = player.speed.sprint;
317
+ player.stamina = Math.max(0, player.stamina - delta * 30);
318
+ } else {
319
+ player.speed.current = player.speed.walk;
320
+ player.stamina = Math.min(100, player.stamina + delta * 10);
321
  }
322
 
323
+ document.getElementById('stamina-bar').style.width =
324
+ player.stamina + '%';
325
+
326
+ // Move player
327
+ if(direction.length() > 0) {
328
+ const moveX = direction.x * player.speed.current * delta;
329
+ const moveZ = direction.z * player.speed.current * delta;
330
+
331
+ camera.position.x += moveX * Math.cos(camera.rotation.y) +
332
+ moveZ * Math.sin(camera.rotation.y);
333
+ camera.position.z += moveZ * Math.cos(camera.rotation.y) -
334
+ moveX * Math.sin(camera.rotation.y);
335
+
336
+ // Head bob
337
+ player.headBob.value += delta * player.headBob.speed;
338
+ camera.position.y = player.position.y +
339
+ Math.sin(player.headBob.value) * player.headBob.intensity;
340
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
+ // Update flashlight
343
+ if(isFlashlightOn) {
344
+ flashlight.position.copy(camera.position);
345
+ flashlight.rotation.copy(camera.rotation);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  }
348
 
349
+ function updateEnvironment() {
350
+ // Check if entering/leaving cave
351
+ const inCaveNow = camera.position.z < -15;
352
+ if(inCaveNow !== player.inCave) {
353
+ player.inCave = inCaveNow;
354
+ transitionEnvironment();
 
355
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
  }
357
 
358
+ function transitionEnvironment() {
359
+ if(player.inCave) {
360
+ scene.fog = new THREE.FogExp2(0x000000, 0.15);
361
+ scene.background = new THREE.Color(0x000000);
362
+ } else {
363
+ scene.fog = null;
364
+ scene.background = new THREE.Color(0x88ccff);
365
+ }
366
+ }
 
367
 
368
+ function animate() {
369
+ requestAnimationFrame(animate);
370
+ const delta = clock.getDelta();
371
+ update(delta);
372
+ renderer.render(scene, camera);
373
  }
374
 
375
+ // Event handlers
376
+ function onKeyDown(event) {
377
+ switch(event.code) {
378
+ case 'KeyW': controls.forward = true; break;
379
+ case 'KeyS': controls.backward = true; break;
380
+ case 'KeyA': controls.left = true; break;
381
+ case 'KeyD': controls.right = true; break;
382
+ case 'ShiftLeft': controls.sprint = true; break;
383
+ case 'KeyF': toggleFlashlight(); break;
384
  }
 
 
385
  }
386
 
387
+ function onKeyUp(event) {
388
+ switch(event.code) {
389
+ case 'KeyW': controls.forward = false; break;
390
+ case 'KeyS': controls.backward = false; break;
391
+ case 'KeyA': controls.left = false; break;
392
+ case 'KeyD': controls.right = false; break;
393
+ case 'ShiftLeft': controls.sprint = false; break;
394
  }
395
+ }
396
 
397
+ function onMouseMove(event) {
398
+ if(document.pointerLockElement) {
399
+ camera.rotation.y -= event.movementX * 0.002;
400
+ camera.rotation.x = Math.max(
401
+ -Math.PI/2,
402
+ Math.min(Math.PI/2,
403
+ camera.rotation.x - event.movementY * 0.002)
404
+ );
405
+ }
 
 
 
 
 
 
 
 
 
 
 
 
406
  }
407
 
408
+ function toggleFlashlight() {
409
+ isFlashlightOn = !isFlashlightOn;
410
+ flashlight.visible = isFlashlightOn;
411
+ document.getElementById('flashlight-status').textContent =
412
+ `Flashlight [F] ${isFlashlightOn ? 'ON' : 'OFF'}`;
413
+ }
414
  </script>
415
  </body>
416
  </html>