sugakrit6 commited on
Commit
0da3634
·
verified ·
1 Parent(s): 0db74d9

Delete index.html

Browse files
Files changed (1) hide show
  1. index.html +0 -786
index.html DELETED
@@ -1,786 +0,0 @@
1
- import React, { useState, useEffect, useRef } from 'react';
2
- import { Volume2, VolumeX, Power, Camera, X, Lightbulb, Upload } from 'lucide-react';
3
-
4
- export default function FNAFGame() {
5
- const [gameState, setGameState] = useState('upload');
6
- const [currentView, setCurrentView] = useState('office');
7
- const [selectedCamera, setSelectedCamera] = useState('CAM1');
8
- const [power, setPower] = useState(100);
9
- const [hour, setHour] = useState(0);
10
- const [soundEnabled, setSoundEnabled] = useState(true);
11
- const [animatronicPositions, setAnimatronicPositions] = useState({
12
- char1: 'CAM1', // Starts in Left Hall
13
- char2: 'CAM1', // Starts in Left Hall
14
- char3: 'CAM3', // Starts in Left Corner
15
- char4: 'CAM2' // Invisible - doesn't show in cameras
16
- });
17
- const [leftLightOn, setLeftLightOn] = useState(false);
18
- const [rightLightOn, setRightLightOn] = useState(false);
19
- const [leftDoorClosed, setLeftDoorClosed] = useState(false);
20
- const [rightDoorClosed, setRightDoorClosed] = useState(false);
21
- const [jumpscareCharacter, setJumpscareCharacter] = useState(null);
22
- const [showTryAgain, setShowTryAgain] = useState(false);
23
-
24
- const [images, setImages] = useState({
25
- officeLeft: null,
26
- officeRight: null,
27
- officeBoth: null,
28
- jumpscare1: null,
29
- jumpscare2: null,
30
- jumpscare3: null,
31
- jumpscare4: null,
32
- cam1: null,
33
- cam2: null,
34
- cam3: null,
35
- // Specific animatronic in camera images
36
- char1_cam1: null, // Character 1 in Left Hall
37
- char2_cam1: null, // Character 2 in Left Hall
38
- char3_cam3: null // Character 3 in Left Corner
39
- // Character 4 doesn't appear in cameras (invisible/teleporter)
40
- });
41
-
42
- const cameras = {
43
- CAM1: { name: 'Left Hall' },
44
- CAM2: { name: 'Right Hall' },
45
- CAM3: { name: 'Left Corner' }
46
- };
47
-
48
- const handleImageUpload = (key, file) => {
49
- if (file) {
50
- const reader = new FileReader();
51
- reader.onload = (e) => {
52
- setImages(prev => ({ ...prev, [key]: e.target.result }));
53
- };
54
- reader.readAsDataURL(file);
55
- }
56
- };
57
-
58
- const playJumpscareSound = () => {
59
- if (!soundEnabled) return;
60
- const ctx = new (window.AudioContext || window.webkitAudioContext)();
61
- const oscillator = ctx.createOscillator();
62
- const gainNode = ctx.createGain();
63
-
64
- oscillator.connect(gainNode);
65
- gainNode.connect(ctx.destination);
66
-
67
- oscillator.type = 'sawtooth';
68
- oscillator.frequency.value = 80;
69
- gainNode.gain.setValueAtTime(0.8, ctx.currentTime);
70
- gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 2);
71
- oscillator.start(ctx.currentTime);
72
- oscillator.stop(ctx.currentTime + 2);
73
- };
74
-
75
- const playSound = (type) => {
76
- if (!soundEnabled) return;
77
- const ctx = new (window.AudioContext || window.webkitAudioContext)();
78
- const oscillator = ctx.createOscillator();
79
- const gainNode = ctx.createGain();
80
-
81
- oscillator.connect(gainNode);
82
- gainNode.connect(ctx.destination);
83
-
84
- switch(type) {
85
- case 'camera':
86
- oscillator.frequency.value = 800;
87
- gainNode.gain.setValueAtTime(0.2, ctx.currentTime);
88
- gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.2);
89
- oscillator.start(ctx.currentTime);
90
- oscillator.stop(ctx.currentTime + 0.2);
91
- break;
92
- case 'door':
93
- oscillator.frequency.value = 400;
94
- gainNode.gain.setValueAtTime(0.2, ctx.currentTime);
95
- gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.3);
96
- oscillator.start(ctx.currentTime);
97
- oscillator.stop(ctx.currentTime + 0.3);
98
- break;
99
- case 'light':
100
- oscillator.frequency.value = 600;
101
- gainNode.gain.setValueAtTime(0.15, ctx.currentTime);
102
- gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.1);
103
- oscillator.start(ctx.currentTime);
104
- oscillator.stop(ctx.currentTime + 0.1);
105
- break;
106
- case 'move':
107
- oscillator.frequency.value = 200;
108
- gainNode.gain.setValueAtTime(0.15, ctx.currentTime);
109
- gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.5);
110
- oscillator.start(ctx.currentTime);
111
- oscillator.stop(ctx.currentTime + 0.5);
112
- break;
113
- }
114
- };
115
-
116
- useEffect(() => {
117
- if (gameState !== 'playing') return;
118
-
119
- const interval = setInterval(() => {
120
- setPower(prev => {
121
- let drain = 0.15;
122
- if (currentView === 'camera') drain += 0.25;
123
- if (leftDoorClosed) drain += 0.15;
124
- if (rightDoorClosed) drain += 0.15;
125
- if (leftLightOn) drain += 0.1;
126
- if (rightLightOn) drain += 0.1;
127
-
128
- const newPower = Math.max(0, prev - drain);
129
- if (newPower === 0) {
130
- setGameState('gameover');
131
- }
132
- return newPower;
133
- });
134
- }, 1000);
135
-
136
- return () => clearInterval(interval);
137
- }, [gameState, currentView, leftDoorClosed, rightDoorClosed, leftLightOn, rightLightOn]);
138
-
139
- useEffect(() => {
140
- if (gameState !== 'playing') return;
141
-
142
- const interval = setInterval(() => {
143
- setHour(prev => {
144
- const newHour = prev + 1;
145
- if (newHour >= 6) {
146
- setGameState('win');
147
- }
148
- return newHour;
149
- });
150
- }, 90000);
151
-
152
- return () => clearInterval(interval);
153
- }, [gameState]);
154
-
155
- useEffect(() => {
156
- if (gameState !== 'playing') return;
157
-
158
- const interval = setInterval(() => {
159
- const moveChance = currentView === 'office' ? 0.3 : 0.1;
160
-
161
- setAnimatronicPositions(prev => {
162
- const updated = { ...prev };
163
- const characters = ['char1', 'char2', 'char3', 'char4'];
164
-
165
- characters.forEach(char => {
166
- if (Math.random() < moveChance) {
167
- const currentPos = updated[char];
168
-
169
- if (currentPos === 'CAM5') {
170
- if (!leftDoorClosed && currentView === 'office' && Math.random() < 0.6) {
171
- triggerJumpscare(char);
172
- return;
173
- }
174
- updated[char] = leftDoorClosed ? 'CAM1' : 'CAM5';
175
- } else if (currentPos === 'CAM6') {
176
- if (!rightDoorClosed && currentView === 'office' && Math.random() < 0.6) {
177
- triggerJumpscare(char);
178
- return;
179
- }
180
- updated[char] = rightDoorClosed ? 'CAM1' : 'CAM6';
181
- } else {
182
- const possibleMoves = ['CAM1', 'CAM2', 'CAM3', 'CAM4', 'CAM5', 'CAM6'];
183
- const validMoves = possibleMoves.filter(cam => cam !== currentPos);
184
- updated[char] = validMoves[Math.floor(Math.random() * validMoves.length)];
185
- playSound('move');
186
- }
187
- }
188
- });
189
-
190
- return updated;
191
- });
192
- }, 6000);
193
-
194
- return () => clearInterval(interval);
195
- }, [gameState, currentView, leftDoorClosed, rightDoorClosed]);
196
-
197
- const triggerJumpscare = (character) => {
198
- playJumpscareSound();
199
- setJumpscareCharacter(character);
200
- setGameState('jumpscare');
201
-
202
- setTimeout(() => {
203
- setShowTryAgain(true);
204
- }, 2000);
205
- };
206
-
207
- const startGame = () => {
208
- setGameState('playing');
209
- setPower(100);
210
- setHour(0);
211
- setCurrentView('office');
212
- setLeftDoorClosed(false);
213
- setRightDoorClosed(false);
214
- setLeftLightOn(false);
215
- setRightLightOn(false);
216
- setShowTryAgain(false);
217
- setJumpscareCharacter(null);
218
- setAnimatronicPositions({
219
- char1: 'CAM1',
220
- char2: 'CAM1',
221
- char3: 'CAM3',
222
- char4: 'CAM2'
223
- });
224
- };
225
-
226
- const toggleCamera = () => {
227
- if (currentView === 'office') {
228
- setCurrentView('camera');
229
- playSound('camera');
230
- } else {
231
- setCurrentView('office');
232
- playSound('camera');
233
- }
234
- };
235
-
236
- const toggleDoor = (side) => {
237
- playSound('door');
238
- if (side === 'left') {
239
- setLeftDoorClosed(!leftDoorClosed);
240
- } else {
241
- setRightDoorClosed(!rightDoorClosed);
242
- }
243
- };
244
-
245
- const toggleLight = (side) => {
246
- playSound('light');
247
- if (side === 'left') {
248
- setLeftLightOn(!leftLightOn);
249
- } else {
250
- setRightLightOn(!rightLightOn);
251
- }
252
- };
253
-
254
- const getOfficeImage = () => {
255
- if (leftLightOn && rightLightOn && images.officeBoth) return images.officeBoth;
256
- if (leftLightOn && images.officeLeft) return images.officeLeft;
257
- if (rightLightOn && images.officeRight) return images.officeRight;
258
- return images.officeBoth || images.officeLeft || images.officeRight;
259
- };
260
-
261
- const getJumpscareImage = () => {
262
- switch(jumpscareCharacter) {
263
- case 'char1': return images.jumpscare1;
264
- case 'char2': return images.jumpscare2;
265
- case 'char3': return images.jumpscare3;
266
- case 'char4': return images.jumpscare4;
267
- default: return images.jumpscare1;
268
- }
269
- };
270
-
271
- // Upload screen
272
- if (gameState === 'upload') {
273
- return (
274
- <div className="w-full min-h-screen bg-gradient-to-b from-gray-900 to-black p-6 overflow-y-auto">
275
- <div className="max-w-6xl mx-auto">
276
- <h1 className="text-5xl font-bold text-red-600 mb-2 text-center">NIGHT SHIFT</h1>
277
- <p className="text-gray-400 mb-8 text-center text-lg">Upload Your Images (Drag & Drop)</p>
278
-
279
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
280
- {/* Office Images */}
281
- <div className="bg-gray-800 rounded-lg p-4">
282
- <h3 className="text-white font-bold mb-2">Office - Left Light</h3>
283
- <input
284
- type="file"
285
- accept="image/*"
286
- onChange={(e) => handleImageUpload('officeLeft', e.target.files[0])}
287
- className="hidden"
288
- id="officeLeft"
289
- />
290
- <label htmlFor="officeLeft" className="cursor-pointer block">
291
- {images.officeLeft ? (
292
- <img src={images.officeLeft} alt="Office Left" className="w-full h-32 object-cover rounded mb-2" />
293
- ) : (
294
- <div className="w-full h-32 bg-gray-700 rounded mb-2 flex items-center justify-center">
295
- <Upload className="text-gray-500" size={32} />
296
- </div>
297
- )}
298
- <p className="text-gray-400 text-sm text-center">Click to upload</p>
299
- </label>
300
- </div>
301
-
302
- <div className="bg-gray-800 rounded-lg p-4">
303
- <h3 className="text-white font-bold mb-2">Office - Right Light</h3>
304
- <input
305
- type="file"
306
- accept="image/*"
307
- onChange={(e) => handleImageUpload('officeRight', e.target.files[0])}
308
- className="hidden"
309
- id="officeRight"
310
- />
311
- <label htmlFor="officeRight" className="cursor-pointer block">
312
- {images.officeRight ? (
313
- <img src={images.officeRight} alt="Office Right" className="w-full h-32 object-cover rounded mb-2" />
314
- ) : (
315
- <div className="w-full h-32 bg-gray-700 rounded mb-2 flex items-center justify-center">
316
- <Upload className="text-gray-500" size={32} />
317
- </div>
318
- )}
319
- <p className="text-gray-400 text-sm text-center">Click to upload</p>
320
- </label>
321
- </div>
322
-
323
- <div className="bg-gray-800 rounded-lg p-4">
324
- <h3 className="text-white font-bold mb-2">Office - Both Lights</h3>
325
- <input
326
- type="file"
327
- accept="image/*"
328
- onChange={(e) => handleImageUpload('officeBoth', e.target.files[0])}
329
- className="hidden"
330
- id="officeBoth"
331
- />
332
- <label htmlFor="officeBoth" className="cursor-pointer block">
333
- {images.officeBoth ? (
334
- <img src={images.officeBoth} alt="Office Both" className="w-full h-32 object-cover rounded mb-2" />
335
- ) : (
336
- <div className="w-full h-32 bg-gray-700 rounded mb-2 flex items-center justify-center">
337
- <Upload className="text-gray-500" size={32} />
338
- </div>
339
- )}
340
- <p className="text-gray-400 text-sm text-center">Click to upload</p>
341
- </label>
342
- </div>
343
-
344
- {/* Jumpscare Images */}
345
- {[1, 2, 3, 4].map(num => (
346
- <div key={num} className="bg-gray-800 rounded-lg p-4">
347
- <h3 className="text-white font-bold mb-2">Jumpscare {num}</h3>
348
- <input
349
- type="file"
350
- accept="image/*"
351
- onChange={(e) => handleImageUpload(`jumpscare${num}`, e.target.files[0])}
352
- className="hidden"
353
- id={`jumpscare${num}`}
354
- />
355
- <label htmlFor={`jumpscare${num}`} className="cursor-pointer block">
356
- {images[`jumpscare${num}`] ? (
357
- <img src={images[`jumpscare${num}`]} alt={`Jumpscare ${num}`} className="w-full h-32 object-cover rounded mb-2" />
358
- ) : (
359
- <div className="w-full h-32 bg-gray-700 rounded mb-2 flex items-center justify-center">
360
- <Upload className="text-gray-500" size={32} />
361
- </div>
362
- )}
363
- <p className="text-gray-400 text-sm text-center">Click to upload</p>
364
- </label>
365
- </div>
366
- ))}
367
-
368
- {/* Camera Images */}
369
- {[1, 2, 3].map(num => (
370
- <div key={num} className="bg-gray-800 rounded-lg p-4">
371
- <h3 className="text-white font-bold mb-2">CAM{num} - {cameras[`CAM${num}`].name} (Empty)</h3>
372
- <input
373
- type="file"
374
- accept="image/*"
375
- onChange={(e) => handleImageUpload(`cam${num}`, e.target.files[0])}
376
- className="hidden"
377
- id={`cam${num}`}
378
- />
379
- <label htmlFor={`cam${num}`} className="cursor-pointer block">
380
- {images[`cam${num}`] ? (
381
- <img src={images[`cam${num}`]} alt={`Camera ${num}`} className="w-full h-32 object-cover rounded mb-2" />
382
- ) : (
383
- <div className="w-full h-32 bg-gray-700 rounded mb-2 flex items-center justify-center">
384
- <Upload className="text-gray-500" size={32} />
385
- </div>
386
- )}
387
- <p className="text-gray-400 text-sm text-center">Click to upload</p>
388
- </label>
389
- </div>
390
- ))}
391
-
392
- {/* Animatronic in Camera Images */}
393
- <div className="col-span-full">
394
- <h2 className="text-2xl font-bold text-red-500 mb-4 mt-6">Animatronics in Cameras</h2>
395
- </div>
396
-
397
- <div className="bg-gray-700 rounded-lg p-4">
398
- <h3 className="text-xl font-bold text-yellow-400 mb-4">Animatronic 1 (in Left Hall)</h3>
399
- <input
400
- type="file"
401
- accept="image/*"
402
- onChange={(e) => handleImageUpload('char1_cam1', e.target.files[0])}
403
- className="hidden"
404
- id="char1_cam1"
405
- />
406
- <label htmlFor="char1_cam1" className="cursor-pointer block">
407
- {images.char1_cam1 ? (
408
- <img src={images.char1_cam1} alt="Char 1 CAM1" className="w-full h-40 object-cover rounded mb-2" />
409
- ) : (
410
- <div className="w-full h-40 bg-gray-800 rounded mb-2 flex items-center justify-center">
411
- <Upload className="text-gray-500" size={32} />
412
- </div>
413
- )}
414
- <p className="text-gray-400 text-sm text-center">Click to upload</p>
415
- </label>
416
- </div>
417
-
418
- <div className="bg-gray-700 rounded-lg p-4">
419
- <h3 className="text-xl font-bold text-yellow-400 mb-4">Animatronic 2 (in Left Hall)</h3>
420
- <input
421
- type="file"
422
- accept="image/*"
423
- onChange={(e) => handleImageUpload('char2_cam1', e.target.files[0])}
424
- className="hidden"
425
- id="char2_cam1"
426
- />
427
- <label htmlFor="char2_cam1" className="cursor-pointer block">
428
- {images.char2_cam1 ? (
429
- <img src={images.char2_cam1} alt="Char 2 CAM1" className="w-full h-40 object-cover rounded mb-2" />
430
- ) : (
431
- <div className="w-full h-40 bg-gray-800 rounded mb-2 flex items-center justify-center">
432
- <Upload className="text-gray-500" size={32} />
433
- </div>
434
- )}
435
- <p className="text-gray-400 text-sm text-center">Click to upload</p>
436
- </label>
437
- </div>
438
-
439
- <div className="bg-gray-700 rounded-lg p-4">
440
- <h3 className="text-xl font-bold text-yellow-400 mb-4">Animatronic 3 (in Left Corner)</h3>
441
- <input
442
- type="file"
443
- accept="image/*"
444
- onChange={(e) => handleImageUpload('char3_cam3', e.target.files[0])}
445
- className="hidden"
446
- id="char3_cam3"
447
- />
448
- <label htmlFor="char3_cam3" className="cursor-pointer block">
449
- {images.char3_cam3 ? (
450
- <img src={images.char3_cam3} alt="Char 3 CAM3" className="w-full h-40 object-cover rounded mb-2" />
451
- ) : (
452
- <div className="w-full h-40 bg-gray-800 rounded mb-2 flex items-center justify-center">
453
- <Upload className="text-gray-500" size={32} />
454
- </div>
455
- )}
456
- <p className="text-gray-400 text-sm text-center">Click to upload</p>
457
- </label>
458
- </div>
459
-
460
- <div className="bg-gray-700 rounded-lg p-4">
461
- <h3 className="text-xl font-bold text-yellow-400 mb-4">Animatronic 4 (Doesn't Show in Cameras)</h3>
462
- <div className="w-full h-40 bg-gray-800 rounded flex items-center justify-center">
463
- <p className="text-gray-500 text-center">This character is invisible<br/>and never appears in cameras!</p>
464
- </div>
465
- </div>
466
- </div>
467
-
468
- <div className="mt-8 text-center">
469
- <button
470
- onClick={() => setGameState('menu')}
471
- className="bg-red-600 hover:bg-red-700 text-white px-12 py-4 rounded-lg text-2xl font-bold"
472
- >
473
- START GAME →
474
- </button>
475
- <p className="text-gray-500 mt-4">You can skip images - placeholders will be used</p>
476
- </div>
477
- </div>
478
- </div>
479
- );
480
- }
481
-
482
- // Menu
483
- if (gameState === 'menu') {
484
- return (
485
- <div className="w-full h-screen bg-black flex items-center justify-center">
486
- <div className="text-center">
487
- <h1 className="text-6xl font-bold text-red-600 mb-4 animate-pulse">
488
- NIGHT SHIFT
489
- </h1>
490
- <p className="text-gray-400 mb-8 text-xl">Survive Until 6 AM</p>
491
- <div className="space-y-4">
492
- <button
493
- onClick={startGame}
494
- className="block mx-auto bg-red-600 hover:bg-red-700 text-white px-8 py-4 rounded text-2xl font-bold"
495
- >
496
- START NIGHT
497
- </button>
498
- <button
499
- onClick={() => setGameState('upload')}
500
- className="block mx-auto bg-gray-700 hover:bg-gray-600 text-white px-8 py-3 rounded text-lg"
501
- >
502
- Change Images
503
- </button>
504
- </div>
505
- <div className="mt-8">
506
- <button
507
- onClick={() => setSoundEnabled(!soundEnabled)}
508
- className="text-gray-400 hover:text-white"
509
- >
510
- {soundEnabled ? <Volume2 size={32} /> : <VolumeX size={32} />}
511
- </button>
512
- </div>
513
- </div>
514
- </div>
515
- );
516
- }
517
-
518
- // Jumpscare
519
- if (gameState === 'jumpscare') {
520
- const jumpImg = getJumpscareImage();
521
- return (
522
- <div className="w-full h-screen bg-black flex items-center justify-center relative overflow-hidden">
523
- {jumpImg ? (
524
- <img
525
- src={jumpImg}
526
- alt="Jumpscare"
527
- className="absolute inset-0 w-full h-full object-contain animate-pulse"
528
- style={{
529
- filter: 'blur(2px)',
530
- imageRendering: 'pixelated',
531
- animation: 'shake 0.1s infinite'
532
- }}
533
- />
534
- ) : (
535
- <div className="text-9xl animate-pulse">💀</div>
536
- )}
537
- {showTryAgain && (
538
- <>
539
- <div
540
- className="absolute inset-0 bg-red-600"
541
- style={{ animation: 'fadeIn 1s ease-in' }}
542
- />
543
- <div className="relative z-20 text-center">
544
- <h1 className="text-6xl font-bold text-white mb-8">
545
- TRY AGAIN
546
- </h1>
547
- <button
548
- onClick={() => {
549
- setShowTryAgain(false);
550
- setGameState('menu');
551
- }}
552
- className="bg-white text-black px-8 py-4 rounded text-xl font-bold hover:bg-gray-200"
553
- >
554
- Back to Menu
555
- </button>
556
- </div>
557
- </>
558
- )}
559
- <style>{`
560
- @keyframes shake {
561
- 0%, 100% { transform: translate(0, 0) rotate(0deg); }
562
- 25% { transform: translate(-5px, 5px) rotate(-2deg); }
563
- 50% { transform: translate(5px, -5px) rotate(2deg); }
564
- 75% { transform: translate(-5px, -5px) rotate(-1deg); }
565
- }
566
- @keyframes fadeIn {
567
- from { opacity: 0; }
568
- to { opacity: 1; }
569
- }
570
- `}</style>
571
- </div>
572
- );
573
- }
574
-
575
- // Game over
576
- if (gameState === 'gameover') {
577
- return (
578
- <div className="w-full h-screen bg-black flex items-center justify-center">
579
- <div className="text-center">
580
- <h1 className="text-5xl font-bold text-red-600 mb-4">POWER OUT</h1>
581
- <p className="text-gray-400 mb-8 text-xl">You ran out of power...</p>
582
- <button
583
- onClick={() => setGameState('menu')}
584
- className="bg-red-600 hover:bg-red-700 text-white px-6 py-3 rounded text-xl"
585
- >
586
- Main Menu
587
- </button>
588
- </div>
589
- </div>
590
- );
591
- }
592
-
593
- // Win
594
- if (gameState === 'win') {
595
- return (
596
- <div className="w-full h-screen bg-black flex items-center justify-center">
597
- <div className="text-center">
598
- <h1 className="text-5xl font-bold text-green-500 mb-4">6 AM</h1>
599
- <p className="text-gray-400 mb-8 text-xl">You survived the night!</p>
600
- <button
601
- onClick={() => setGameState('menu')}
602
- className="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded text-xl"
603
- >
604
- Main Menu
605
- </button>
606
- </div>
607
- </div>
608
- );
609
- }
610
-
611
- // Office view
612
- if (currentView === 'office') {
613
- const officeImg = getOfficeImage();
614
- return (
615
- <div className="w-full h-screen bg-black relative overflow-hidden">
616
- {officeImg ? (
617
- <img
618
- src={officeImg}
619
- alt="Office"
620
- className="absolute inset-0 w-full h-full object-cover"
621
- />
622
- ) : (
623
- <div className="absolute inset-0 bg-gradient-to-b from-gray-800 to-black" />
624
- )}
625
-
626
- <div className="absolute top-4 left-4 text-white z-10">
627
- <div className="bg-black bg-opacity-75 p-3 rounded">
628
- <div className="flex items-center gap-2 mb-2">
629
- <Power size={20} />
630
- <span className="font-mono text-xl">{Math.floor(power)}%</span>
631
- </div>
632
- <div className="text-sm text-gray-400">
633
- {hour} AM - {6 - hour} hours left
634
- </div>
635
- </div>
636
- </div>
637
-
638
- <div className="absolute left-4 top-1/2 transform -translate-y-1/2 z-10 space-y-4">
639
- <button
640
- onClick={() => toggleLight('left')}
641
- className={`px-4 py-3 rounded font-bold flex items-center gap-2 ${
642
- leftLightOn ? 'bg-yellow-500 text-black' : 'bg-gray-700 text-white'
643
- }`}
644
- >
645
- <Lightbulb size={20} />
646
- Light
647
- </button>
648
- <button
649
- onClick={() => toggleDoor('left')}
650
- className={`px-4 py-3 rounded font-bold ${
651
- leftDoorClosed ? 'bg-red-600 text-white' : 'bg-green-600 text-white'
652
- }`}
653
- >
654
- Door<br/>{leftDoorClosed ? 'CLOSED' : 'OPEN'}
655
- </button>
656
- </div>
657
-
658
- <div className="absolute right-4 top-1/2 transform -translate-y-1/2 z-10 space-y-4">
659
- <button
660
- onClick={() => toggleLight('right')}
661
- className={`px-4 py-3 rounded font-bold flex items-center gap-2 ${
662
- rightLightOn ? 'bg-yellow-500 text-black' : 'bg-gray-700 text-white'
663
- }`}
664
- >
665
- <Lightbulb size={20} />
666
- Light
667
- </button>
668
- <button
669
- onClick={() => toggleDoor('right')}
670
- className={`px-4 py-3 rounded font-bold ${
671
- rightDoorClosed ? 'bg-red-600 text-white' : 'bg-green-600 text-white'
672
- }`}
673
- >
674
- Door<br/>{rightDoorClosed ? 'CLOSED' : 'OPEN'}
675
- </button>
676
- </div>
677
-
678
- <button
679
- onClick={toggleCamera}
680
- className="absolute bottom-8 left-1/2 transform -translate-x-1/2 bg-green-600 hover:bg-green-700 text-white px-8 py-4 rounded-lg text-xl font-bold flex items-center gap-2 z-10"
681
- >
682
- <Camera size={24} />
683
- CAMERAS
684
- </button>
685
- </div>
686
- );
687
- }
688
-
689
- // Camera view
690
- const animatronicsInView = Object.entries(animatronicPositions)
691
- .filter(([char, pos]) => pos === selectedCamera)
692
- .map(([char]) => char);
693
-
694
- return (
695
- <div className="w-full h-screen bg-black relative">
696
- <div className="absolute inset-0 flex items-center justify-center p-8">
697
- <div className="w-full max-w-4xl">
698
- <div className="bg-gray-900 border-4 border-green-500 rounded-lg overflow-hidden aspect-video relative">
699
- {/* Base camera background */}
700
- {images[`cam${selectedCamera.slice(-1)}`] ? (
701
- <img
702
- src={images[`cam${selectedCamera.slice(-1)}`]}
703
- alt={`Camera ${selectedCamera}`}
704
- className="absolute inset-0 w-full h-full object-cover"
705
- />
706
- ) : (
707
- <div className="absolute inset-0 bg-gray-800" />
708
- )}
709
-
710
- {/* Show animatronic image if present */}
711
- {animatronicsInView.length > 0 && animatronicsInView.map(char => {
712
- const animImage = images[`${char}_${selectedCamera.toLowerCase()}`];
713
- return animImage ? (
714
- <img
715
- key={char}
716
- src={animImage}
717
- alt={`${char} in ${selectedCamera}`}
718
- className="absolute inset-0 w-full h-full object-cover"
719
- />
720
- ) : null;
721
- })}
722
-
723
- <div className="absolute inset-0 bg-gradient-to-b from-transparent via-green-500 to-transparent opacity-10 animate-pulse pointer-events-none" />
724
-
725
- <div className="absolute top-4 left-4 text-green-400 font-mono z-20">
726
- {selectedCamera}
727
- </div>
728
- <div className="absolute top-4 right-4 text-green-400 font-mono animate-pulse z-20">
729
- REC ●
730
- </div>
731
-
732
- {animatronicsInView.length > 0 && (
733
- <div className="absolute bottom-4 left-4 right-4 text-center z-20">
734
- <p className="text-red-500 text-xl font-bold animate-pulse">
735
- ⚠️ MOVEMENT DETECTED
736
- </p>
737
- </div>
738
- )}
739
- </div>
740
- </div>
741
- </div>
742
-
743
- <div className="absolute bottom-8 left-8 right-8">
744
- <div className="grid grid-cols-3 gap-4">
745
- {Object.keys(cameras).map(cam => {
746
- const count = Object.values(animatronicPositions).filter(pos => pos === cam).length;
747
- return (
748
- <button
749
- key={cam}
750
- onClick={() => {
751
- setSelectedCamera(cam);
752
- playSound('camera');
753
- }}
754
- className={`p-4 rounded ${
755
- selectedCamera === cam
756
- ? 'bg-green-600 text-white'
757
- : 'bg-gray-800 text-gray-400 hover:bg-gray-700'
758
- } ${count > 0 ? 'border-2 border-red-500' : ''}`}
759
- >
760
- <div className="font-bold">{cam}</div>
761
- {count > 0 && <div className="text-xs text-red-400 mt-1">{count} here</div>}
762
- </button>
763
- );
764
- })}
765
- </div>
766
- </div>
767
-
768
- <button
769
- onClick={toggleCamera}
770
- className="absolute top-4 right-4 bg-red-600 hover:bg-red-700 text-white p-3 rounded-full"
771
- >
772
- <X size={24} />
773
- </button>
774
-
775
- <div className="absolute top-4 left-4 text-white">
776
- <div className="bg-black bg-opacity-75 p-3 rounded">
777
- <div className="flex items-center gap-2 mb-2">
778
- <Power size={20} />
779
- <span className="font-mono text-xl">{Math.floor(power)}%</span>
780
- </div>
781
- <div className="text-sm text-gray-400">{hour} AM</div>
782
- </div>
783
- </div>
784
- </div>
785
- );
786
- }