Ezequield commited on
Commit
322bfb3
·
verified ·
1 Parent(s): a18768c

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +774 -715
index.html CHANGED
@@ -1,759 +1,818 @@
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>SONY VIDEO SYSTEM 2003</title>
7
- <!-- Importing FontAwesome for Icons -->
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- <style>
11
- :root {
12
- --sony-silver: #d4d4d4;
13
- --sony-dark-silver: #a6a6a6;
14
- --sony-black: #1a1a1a;
15
- --sony-blue: #0044cc;
16
- --neon-blue: #00f3ff;
17
- --crt-green: #33ff00;
18
- --rec-red: #ff0000;
19
- --glass-reflection: rgba(255, 255, 255, 0.4);
20
- --plastic-shadow: rgba(0, 0, 0, 0.5);
21
- }
22
-
23
- * {
24
- box-sizing: border-box;
25
- user-select: none;
26
- }
27
-
28
- body {
29
- margin: 0;
30
- padding: 0;
31
- background-color: #050505;
32
- background-image:
33
- radial-gradient(circle at 50% 50%, #1a1a1a 0%, #000000 100%);
34
- font-family: "Courier New", Courier, monospace;
35
- height: 100vh;
36
- display: flex;
37
- justify-content: center;
38
- align-items: center;
39
- overflow: hidden;
40
- color: white;
41
- }
42
-
43
- /* --- Header / Branding --- */
44
- .top-bar {
45
- position: absolute;
46
- top: 0;
47
- left: 0;
48
- width: 100%;
49
- padding: 10px 20px;
50
- display: flex;
51
- justify-content: space-between;
52
- align-items: center;
53
- z-index: 100;
54
- background: rgba(0,0,0,0.3);
55
- border-bottom: 1px solid #333;
56
- }
57
-
58
- .brand-title {
59
- font-weight: bold;
60
- letter-spacing: 2px;
61
- color: var(--sony-silver);
62
- text-shadow: 0 0 5px rgba(255,255,255,0.5);
63
- }
64
-
65
- .anycoder-link {
66
- color: var(--neon-blue);
67
- text-decoration: none;
68
- font-size: 0.8rem;
69
- opacity: 0.8;
70
- transition: opacity 0.3s;
71
- }
72
- .anycoder-link:hover {
73
- opacity: 1;
74
- text-shadow: 0 0 8px var(--neon-blue);
75
- }
76
-
77
- /* --- Main Device Container --- */
78
- .vcr-device {
79
- width: 90%;
80
- max-width: 800px;
81
- background: linear-gradient(135deg, #e0e0e0 0%, #b0b0b0 50%, #909090 100%);
82
- border-radius: 20px;
83
- padding: 20px;
84
- box-shadow:
85
- 0 20px 50px rgba(0,0,0,0.8),
86
- inset 0 1px 0 rgba(255,255,255,0.8),
87
- inset 0 -1px 0 rgba(0,0,0,0.2);
88
- display: flex;
89
- flex-direction: column;
90
- gap: 15px;
91
- position: relative;
92
- transform-style: preserve-3d;
93
- perspective: 1000px;
94
- }
95
-
96
- /* Screws for realism */
97
- .screw {
98
- width: 12px;
99
- height: 12px;
100
- background: radial-gradient(circle, #555 30%, #333 100%);
101
- border-radius: 50%;
102
- position: absolute;
103
- box-shadow: inset 0 1px 2px rgba(0,0,0,0.8);
104
- }
105
- .screw::after {
106
- content: '';
107
- position: absolute;
108
- top: 50%;
109
- left: 50%;
110
- width: 80%;
111
- height: 2px;
112
- background: #111;
113
- transform: translate(-50%, -50%) rotate(45deg);
114
- }
115
- .screw.tl { top: 10px; left: 10px; }
116
- .screw.tr { top: 10px; right: 10px; }
117
- .screw.bl { bottom: 10px; left: 10px; }
118
- .screw.br { bottom: 10px; right: 10px; }
119
-
120
- /* --- Screen Area --- */
121
- .screen-bezel {
122
- background: #000;
123
- border-radius: 10px;
124
- padding: 15px;
125
- box-shadow: inset 0 0 20px rgba(0,0,0,1);
126
- position: relative;
127
- overflow: hidden;
128
- }
129
-
130
- .screen-crt {
131
- width: 100%;
132
- aspect-ratio: 4/3;
133
- background: #050505;
134
- border-radius: 4px; /* Slight curve */
135
- position: relative;
136
- overflow: hidden;
137
- border: 1px solid #333;
138
- }
139
-
140
- /* Video Element */
141
- video {
142
- width: 100%;
143
- height: 100%;
144
- object-fit: contain;
145
- display: none;
146
- filter: contrast(1.1) saturate(1.2) brightness(0.9);
147
- }
148
-
149
- /* CRT Effects */
150
- .scanlines {
151
- position: absolute;
152
- top: 0;
153
- left: 0;
154
- width: 100%;
155
- height: 100%;
156
- background: linear-gradient(
157
- to bottom,
158
- rgba(255,255,255,0),
159
- rgba(255,255,255,0) 50%,
160
- rgba(0,0,0,0.2) 50%,
161
- rgba(0,0,0,0.2)
162
- );
163
- background-size: 100% 4px;
164
- pointer-events: none;
165
- z-index: 10;
166
- }
167
-
168
- .screen-glow {
169
- position: absolute;
170
- top: 0;
171
- left: 0;
172
- width: 100%;
173
- height: 100%;
174
- background: radial-gradient(circle, rgba(0,0,0,0) 60%, rgba(0,0,0,0.6) 100%);
175
- box-shadow: inset 0 0 3rem rgba(0,0,0,0.7);
176
- pointer-events: none;
177
- z-index: 11;
178
- }
179
-
180
- .no-signal-text {
181
- position: absolute;
182
- top: 50%;
183
- left: 50%;
184
- transform: translate(-50%, -50%);
185
- color: #555;
186
- font-size: 1.5rem;
187
- text-transform: uppercase;
188
- letter-spacing: 5px;
189
- animation: flicker 2s infinite;
190
- z-index: 5;
191
- text-align: center;
192
- }
193
-
194
- /* --- Control Panel --- */
195
- .control-panel {
196
- background: linear-gradient(to bottom, #cfcfcf, #a0a0a0);
197
- border-radius: 8px;
198
- padding: 15px;
199
- display: flex;
200
- flex-wrap: wrap;
201
- justify-content: space-between;
202
- align-items: center;
203
- box-shadow:
204
- inset 0 1px 0 rgba(255,255,255,0.5),
205
- inset 0 -1px 0 rgba(0,0,0,0.2),
206
- 0 5px 10px rgba(0,0,0,0.3);
207
- border-top: 1px solid #ddd;
208
- }
209
-
210
- .brand-logo {
211
- font-weight: 900;
212
- font-style: italic;
213
- font-size: 1.8rem;
214
- color: transparent;
215
- background: linear-gradient(to bottom, #333 0%, #000 100%);
216
- -webkit-background-clip: text;
217
- text-shadow: 1px 1px 0 rgba(255,255,255,0.2);
218
- margin-right: 20px;
219
- }
220
-
221
- .lcd-display {
222
- background: #2a2a2a;
223
- color: var(--crt-green);
224
- font-family: "VT323", monospace;
225
- padding: 8px 15px;
226
- border-radius: 4px;
227
- border: 2px inset #444;
228
- font-size: 1.2rem;
229
- min-width: 120px;
230
- text-align: center;
231
- box-shadow: 0 0 5px rgba(51, 255, 0, 0.2);
232
- text-shadow: 0 0 2px rgba(51, 255, 0, 0.8);
233
- }
234
-
235
- .status-icons {
236
- display: flex;
237
- gap: 5px;
238
- font-size: 0.7rem;
239
- color: #333;
240
- margin-top: 5px;
241
- }
242
- .status-icons span {
243
- opacity: 0.3;
244
- }
245
- .status-icons span.active {
246
- opacity: 1;
247
- color: var(--rec-red);
248
- font-weight: bold;
249
- }
250
-
251
- /* --- Buttons --- */
252
- .buttons-group {
253
- display: flex;
254
- gap: 10px;
255
- align-items: center;
256
- }
257
-
258
- .vcr-btn {
259
- width: 50px;
260
- height: 50px;
261
- border-radius: 50%;
262
- border: none;
263
- background: radial-gradient(circle at 30% 30%, #f0f0f0, #999);
264
- box-shadow:
265
- 0 4px 0 #555,
266
- 0 5px 5px rgba(0,0,0,0.3);
267
- color: #222;
268
- font-size: 1.2rem;
269
- cursor: pointer;
270
- transition: transform 0.1s, box-shadow 0.1s;
271
- position: relative;
272
- display: flex;
273
- justify-content: center;
274
- align-items: center;
275
- }
276
-
277
- .vcr-btn:active {
278
- transform: translateY(4px);
279
- box-shadow:
280
- 0 0 0 #555,
281
- inset 0 2px 5px rgba(0,0,0,0.5);
282
- }
283
-
284
- .vcr-btn:disabled {
285
- filter: grayscale(1);
286
- opacity: 0.6;
287
- cursor: not-allowed;
288
- }
289
-
290
- .vcr-btn.record {
291
- background: radial-gradient(circle at 30% 30%, #ff6666, #cc0000);
292
- color: white;
293
- }
294
-
295
- .vcr-btn.eject {
296
- width: 30px;
297
- height: 30px;
298
- font-size: 0.8rem;
299
- background: #444;
300
- color: #ccc;
301
- border-radius: 4px;
302
- margin-left: 10px;
303
- box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), 0 2px 0 #111;
304
- }
305
-
306
- /* --- Tape Slot (Upload) --- */
307
- .tape-slot-container {
308
- width: 100%;
309
- height: 60px;
310
- background: #222;
311
- border-radius: 4px;
312
- position: relative;
313
- overflow: hidden;
314
- margin-top: 10px;
315
- border: 1px solid #444;
316
- display: flex;
317
- align-items: center;
318
- justify-content: center;
319
- box-shadow: inset 0 5px 10px #000;
320
- }
321
-
322
- .tape-label {
323
- color: #666;
324
- font-size: 0.8rem;
325
- text-transform: uppercase;
326
- letter-spacing: 2px;
327
- z-index: 2;
328
- pointer-events: none;
329
- }
330
-
331
- #fileInput {
332
- position: absolute;
333
- width: 100%;
334
- height: 100%;
335
- opacity: 0;
336
- cursor: pointer;
337
- z-index: 10;
338
- }
339
-
340
- /* Tape Animation */
341
- .tape-visual {
342
- position: absolute;
343
- top: 0;
344
- left: 0;
345
- width: 100%;
346
- height: 100%;
347
- background: #111;
348
- display: flex;
349
- justify-content: center;
350
- align-items: center;
351
- transform: translateY(-100%);
352
- transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1);
353
- z-index: 5;
354
- }
355
-
356
- .tape-visual.inserted {
357
- transform: translateY(0);
358
- }
359
-
360
- .tape-body {
361
- width: 80%;
362
- height: 40px;
363
- background: linear-gradient(to bottom, #333 0%, #111 100%);
364
- border-radius: 4px;
365
- position: relative;
366
- border: 1px solid #555;
367
- }
368
-
369
- .tape-body::before {
370
- content: 'SONY Hi8';
371
- position: absolute;
372
- top: 5px;
373
- left: 10px;
374
- font-size: 0.6rem;
375
- color: #aaa;
376
- font-style: italic;
377
- }
378
-
379
- .tape-body::after {
380
- content: '';
381
- position: absolute;
382
- top: 5px;
383
- right: 10px;
384
- width: 20px;
385
- height: 20px;
386
- background: #444;
387
- border-radius: 50%;
388
- border: 2px solid #222;
389
- }
390
-
391
- /* Progress Bar */
392
- .progress-container {
393
- width: 100%;
394
- height: 6px;
395
- background: #333;
396
- margin-top: 10px;
397
- border-radius: 3px;
398
- overflow: hidden;
399
- position: relative;
400
- }
401
-
402
- .progress-bar {
403
- height: 100%;
404
- background: var(--neon-blue);
405
- width: 0%;
406
- box-shadow: 0 0 10px var(--neon-blue);
407
- }
408
-
409
- .tracking-line {
410
- position: absolute;
411
- top: 0;
412
- left: 0;
413
- width: 100%;
414
- height: 2px;
415
- background: rgba(255,255,255,0.1);
416
- animation: tracking 4s linear infinite;
417
- opacity: 0.5;
418
- }
419
-
420
- /* --- Animations --- */
421
- @keyframes flicker {
422
- 0% { opacity: 0.8; }
423
- 5% { opacity: 0.5; }
424
- 10% { opacity: 0.8; }
425
- 15% { opacity: 1; }
426
- 20% { opacity: 0.8; }
427
- 100% { opacity: 0.8; }
428
- }
429
-
430
- @keyframes tracking {
431
- 0% { top: 0%; opacity: 0; }
432
- 10% { opacity: 0.5; }
433
- 90% { opacity: 0.5; }
434
- 100% { top: 100%; opacity: 0; }
435
- }
436
-
437
- /* --- Responsive Design --- */
438
- @media (max-width: 600px) {
439
- .vcr-device {
440
- width: 95%;
441
- padding: 10px;
442
- }
443
- .brand-logo {
444
- font-size: 1.2rem;
445
- }
446
- .vcr-btn {
447
- width: 40px;
448
- height: 40px;
449
- font-size: 1rem;
450
- }
451
- .lcd-display {
452
- font-size: 1rem;
453
- min-width: 90px;
454
- }
455
- .control-panel {
456
- gap: 10px;
457
- }
458
- }
459
- </style>
460
  </head>
461
- <body>
462
-
463
- <!-- Header / Branding -->
464
- <header class="top-bar">
465
- <div class="brand-title">SONY 2003 WEB INTERFACE</div>
466
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
467
- Built with anycoder <i class="fas fa-external-link-alt"></i>
468
- </a>
469
- </header>
470
-
471
- <!-- Main Device -->
472
- <main class="vcr-device">
473
- <!-- Decorative Screws -->
474
- <div class="screw tl"></div>
475
- <div class="screw tr"></div>
476
- <div class="screw bl"></div>
477
- <div class="screw br"></div>
478
-
479
- <!-- Screen Section -->
480
- <div class="screen-bezel">
481
- <div class="screen-crt" id="screenArea">
482
- <div class="scanlines"></div>
483
- <div class="screen-glow"></div>
484
- <div class="tracking-line"></div>
485
-
486
- <div class="no-signal-text" id="noSignal">
487
- NO SIGNAL<br>
488
- <span style="font-size: 0.8rem; color: #444;">INSERT CASSETTE</span>
489
- </div>
490
-
491
- <video id="videoPlayer" playsinline></video>
492
- </div>
493
- </div>
494
 
495
- <!-- Tape Slot / Upload Area -->
496
- <div class="tape-slot-container">
497
- <div class="tape-label">INSERT VIDEO TAPE</div>
498
- <input type="file" id="fileInput" accept="video/*">
499
-
500
- <!-- Visual representation of the tape -->
501
- <div class="tape-visual" id="tapeVisual">
502
- <div class="tape-body"></div>
503
- </div>
504
- </div>
505
 
506
- <!-- Controls -->
507
- <div class="control-panel">
508
- <div style="display: flex; flex-direction: column; gap: 5px;">
509
- <div class="brand-logo">SONY</div>
510
- <div class="status-icons">
511
- <span id="spStatus">SP</span> |
512
- <span id="lpStatus">LP</span> |
513
- <span id="recStatus" class="active">●</span> REC
514
- </div>
515
- </div>
516
-
517
- <!-- LCD Display -->
518
- <div class="lcd-display" id="lcdDisplay">
519
- 00:00:00
520
- </div>
521
-
522
- <!-- Buttons -->
523
- <div class="buttons-group">
524
- <button class="vcr-btn" id="btnRewind" title="Rewind" disabled>
525
- <i class="fas fa-backward"></i>
526
- </button>
527
- <button class="vcr-btn" id="btnPlay" title="Play" disabled>
528
- <i class="fas fa-play"></i>
529
- </button>
530
- <button class="vcr-btn record" id="btnRec" title="Record" disabled>
531
- <i class="fas fa-circle"></i>
532
- </button>
533
- <button class="vcr-btn" id="btnStop" title="Stop" disabled>
534
- <i class="fas fa-stop"></i>
535
- </button>
536
- <button class="vcr-btn" id="btnForward" title="Forward" disabled>
537
- <i class="fas fa-forward"></i>
538
- </button>
539
- <button class="vcr-btn eject" id="btnEject" title="Eject" disabled>
540
- <i class="fas fa-eject"></i>
541
- </button>
542
- </div>
543
  </div>
544
 
545
- <!-- Progress Bar -->
546
- <div class="progress-container">
547
- <div class="progress-bar" id="progressBar"></div>
 
548
  </div>
549
- </main>
550
-
551
- <script>
552
- // --- Elements ---
553
- const fileInput = document.getElementById('fileInput');
554
- const videoPlayer = document.getElementById('videoPlayer');
555
- const noSignal = document.getElementById('noSignal');
556
- const tapeVisual = document.getElementById('tapeVisual');
557
- const lcdDisplay = document.getElementById('lcdDisplay');
558
- const progressBar = document.getElementById('progressBar');
559
- const recStatus = document.getElementById('recStatus');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
 
561
- // Buttons
562
- const btnPlay = document.getElementById('btnPlay');
563
- const btnStop = document.getElementById('btnStop');
564
- const btnRewind = document.getElementById('btnRewind');
565
- const btnForward = document.getElementById('btnForward');
566
- const btnEject = document.getElementById('btnEject');
567
-
568
- // State
569
- let isVideoLoaded = false;
570
- let isPlaying = false;
571
- let updateTimer;
572
-
573
- // --- Utility: Format Time ---
574
- function formatTime(seconds) {
575
- const h = Math.floor(seconds / 3600);
576
- const m = Math.floor((seconds % 3600) / 60);
577
- const s = Math.floor(seconds % 60);
578
-
579
- const hh = h < 10 ? '0' + h : h;
580
- const mm = m < 10 ? '0' + m : m;
581
- const ss = s < 10 ? '0' + s : s;
582
-
583
- return `${hh}:${mm}:${ss}`;
584
- }
585
-
586
- // --- Event: File Upload (Insert Tape) ---
587
- fileInput.addEventListener('change', function(e) {
588
- const file = e.target.files[0];
589
- if (!file) return;
590
-
591
- // 1. Visual Feedback: Insert Tape
592
- tapeVisual.classList.add('inserted');
593
- noSignal.innerHTML = "READING TAPE...<br><span style='font-size:0.7rem'>HI-8 MP</span>";
594
-
595
- // 2. Simulate Loading Delay (Mechanical feel)
596
- setTimeout(() => {
597
- const fileURL = URL.createObjectURL(file);
598
- videoPlayer.src = fileURL;
599
- videoPlayer.load();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
 
601
- isVideoLoaded = true;
602
- noSignal.style.display = 'none';
 
 
 
 
 
603
  videoPlayer.style.display = 'block';
 
604
 
605
- // Enable controls
606
  btnPlay.disabled = false;
607
  btnStop.disabled = false;
608
- btnRewind.disabled = false;
609
- btnForward.disabled = false;
610
  btnEject.disabled = false;
611
 
612
- // Reset LCD
613
- lcdDisplay.textContent = "00:00:00";
614
- lcdDisplay.style.color = "var(--crt-green)";
615
-
616
- // Auto play for immediate feedback
617
  togglePlay();
618
-
619
- }, 1200); // 1.2s mechanical delay
620
- });
621
-
622
- // --- Event: Eject ---
623
- btnEject.addEventListener('click', function() {
624
- if (!isVideoLoaded) return;
625
-
626
- // Stop video
627
- videoPlayer.pause();
628
- videoPlayer.currentTime = 0;
629
- isPlaying = false;
630
- updatePlayButtonIcon();
631
-
632
- // UI Reset
633
- videoPlayer.style.display = 'none';
634
- noSignal.style.display = 'block';
635
- noSignal.innerHTML = "NO SIGNAL<br><span style='font-size: 0.8rem; color: #444;'>INSERT CASSETTE</span>";
636
-
637
- tapeVisual.classList.remove('inserted');
638
-
639
- // Disable Controls
640
- btnPlay.disabled = true;
641
- btnStop.disabled = true;
642
- btnRewind.disabled = true;
643
- btnForward.disabled = true;
644
- btnEject.disabled = true;
645
 
646
- progressBar.style.width = '0%';
647
- lcdDisplay.textContent = "--:--:--";
648
 
649
- // Clear Input
650
- fileInput.value = '';
651
- isVideoLoaded = false;
652
- });
653
 
654
- // --- Event: Play/Pause ---
655
- function togglePlay() {
656
- if (!isVideoLoaded) return;
657
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
658
  if (videoPlayer.paused) {
659
- videoPlayer.play()
660
- .then(() => {
661
- isPlaying = true;
662
- updatePlayButtonIcon();
663
- startTracking();
664
- })
665
- .catch(err => console.error("Play error:", err));
666
  } else {
667
  videoPlayer.pause();
668
  isPlaying = false;
669
- updatePlayButtonIcon();
670
  stopTracking();
671
  }
 
 
 
 
 
 
 
 
 
 
 
672
  }
 
 
673
 
674
- btnPlay.addEventListener('click', togglePlay);
675
 
676
- function updatePlayButtonIcon() {
677
- btnPlay.innerHTML = isPlaying ? '<i class="fas fa-pause"></i>' : '<i class="fas fa-play"></i>';
678
- }
679
 
680
- // --- Event: Stop ---
681
- btnStop.addEventListener('click', function() {
682
- if (!isVideoLoaded) return;
683
  videoPlayer.pause();
684
  videoPlayer.currentTime = 0;
685
- isPlaying = false;
686
- updatePlayButtonIcon();
687
- stopTracking();
688
- progressBar.style.width = '0%';
689
- lcdDisplay.textContent = "00:00:00";
690
- });
691
-
692
- // --- Event: Rewind / Forward (Simulation) ---
693
- btnRewind.addEventListener('click', function() {
694
- if (!isVideoLoaded) return;
695
- videoPlayer.currentTime = Math.max(0, videoPlayer.currentTime - 10);
696
- showLcdMessage("REW <<");
697
- });
698
-
699
- btnForward.addEventListener('click', function() {
700
- if (!isVideoLoaded) return;
701
- videoPlayer.currentTime = Math.min(videoPlayer.duration, videoPlayer.currentTime + 10);
702
- showLcdMessage("FWD >>");
703
- });
704
-
705
- // --- Time Tracking & Progress ---
706
- function startTracking() {
707
- clearInterval(updateTimer);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
708
  updateTimer = setInterval(() => {
709
  if (!videoPlayer.paused) {
710
- const current = videoPlayer.currentTime;
711
- const duration = videoPlayer.duration || 1;
712
-
713
- // Update LCD
714
- lcdDisplay.textContent = formatTime(current);
715
-
716
- // Update Progress Bar
717
- const pct = (current / duration) * 100;
718
  progressBar.style.width = `${pct}%`;
719
  }
720
  }, 100);
721
  }
722
-
723
- function stopTracking() {
724
- clearInterval(updateTimer);
725
- }
726
-
727
- // --- LCD Message Helper ---
728
- let msgTimeout;
729
- function showLcdMessage(msg) {
730
- lcdDisplay.textContent = msg;
731
- lcdDisplay.style.color = "white";
732
- clearTimeout(msgTimeout);
733
- msgTimeout = setTimeout(() => {
734
- lcdDisplay.textContent = formatTime(videoPlayer.currentTime);
735
- lcdDisplay.style.color = "var(--crt-green)";
736
- }, 1000);
737
- }
738
-
739
- // --- Video Ended Event ---
740
- videoPlayer.addEventListener('ended', () => {
741
- isPlaying = false;
742
- updatePlayButtonIcon();
743
- stopTracking();
744
- showLcdMessage("END");
745
- });
746
-
747
- // --- Random CRT Flicker Effect on Screen ---
748
- setInterval(() => {
749
- if (isVideoLoaded && isPlaying) {
750
- const opacity = Math.random() * 0.05;
751
- videoPlayer.style.opacity = 1 - opacity;
752
- } else {
753
- videoPlayer.style.opacity = 1;
754
  }
755
- }, 500);
756
-
757
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
758
  </body>
759
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
+
4
  <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>SORA 2 BETA | AI VIDEO SYNTHESIZER</title>
8
+ <!-- Importing FontAwesome for Icons -->
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+
11
+ <style>
12
+ :root {
13
+ /* New "Sora Beta" Palette */
14
+ --chassis-dark: #1a1b1e;
15
+ --chassis-light: #2c2e33;
16
+ --accent-cyan: #00f0ff;
17
+ --accent-glow: rgba(0, 240, 255, 0.4);
18
+ --alert-red: #ff2a2a;
19
+ --lcd-bg: #0f1115;
20
+ --lcd-text: #00f0ff;
21
+ --glass-reflection: rgba(255, 255, 255, 0.05);
22
+ --metal-gradient: linear-gradient(135deg, #2b2b2b 0%, #1a1a1a 50%, #0f0f0f 100%);
23
+ }
24
+
25
+ * {
26
+ box-sizing: border-box;
27
+ user-select: none;
28
+ }
29
+
30
+ body {
31
+ margin: 0;
32
+ padding: 0;
33
+ background-color: #000;
34
+ background-image:
35
+ radial-gradient(circle at 50% 50%, #1a1a1a 0%, #000000 100%);
36
+ font-family: "Courier New", Courier, monospace;
37
+ height: 100vh;
38
+ display: flex;
39
+ justify-content: center;
40
+ align-items: center;
41
+ overflow: hidden;
42
+ color: white;
43
+ }
44
+
45
+ /* --- Header / Branding --- */
46
+ .top-bar {
47
+ position: absolute;
48
+ top: 0;
49
+ left: 0;
50
+ width: 100%;
51
+ padding: 10px 20px;
52
+ display: flex;
53
+ justify-content: space-between;
54
+ align-items: center;
55
+ z-index: 100;
56
+ background: rgba(0, 0, 0, 0.6);
57
+ border-bottom: 1px solid #333;
58
+ backdrop-filter: blur(5px);
59
+ }
60
+
61
+ .brand-title {
62
+ font-weight: 800;
63
+ letter-spacing: 3px;
64
+ color: var(--accent-cyan);
65
+ text-shadow: 0 0 10px var(--accent-glow);
66
+ font-size: 1.1rem;
67
+ }
68
+
69
+ .beta-badge {
70
+ background: var(--accent-cyan);
71
+ color: #000;
72
+ font-size: 0.6rem;
73
+ padding: 2px 6px;
74
+ border-radius: 2px;
75
+ font-weight: bold;
76
+ margin-left: 8px;
77
+ vertical-align: middle;
78
+ }
79
+
80
+ .anycoder-link {
81
+ color: #666;
82
+ text-decoration: none;
83
+ font-size: 0.8rem;
84
+ transition: color 0.3s;
85
+ }
86
+
87
+ .anycoder-link:hover {
88
+ color: white;
89
+ }
90
+
91
+ /* --- Main Device Container --- */
92
+ .vcr-device {
93
+ width: 90%;
94
+ max-width: 850px;
95
+ background: var(--metal-gradient);
96
+ border-radius: 12px;
97
+ padding: 25px;
98
+ box-shadow:
99
+ 0 30px 60px rgba(0, 0, 0, 0.9),
100
+ inset 0 1px 0 rgba(255, 255, 255, 0.1),
101
+ inset 0 -1px 0 rgba(0, 0, 0, 0.5);
102
+ display: flex;
103
+ flex-direction: column;
104
+ gap: 20px;
105
+ position: relative;
106
+ border: 1px solid #333;
107
+ }
108
+
109
+ /* Screws */
110
+ .screw {
111
+ width: 10px;
112
+ height: 10px;
113
+ background: #111;
114
+ border-radius: 50%;
115
+ position: absolute;
116
+ box-shadow: inset 0 1px 2px #000;
117
+ border: 1px solid #333;
118
+ }
119
+ .screw.tl { top: 15px; left: 15px; }
120
+ .screw.tr { top: 15px; right: 15px; }
121
+ .screw.bl { bottom: 15px; left: 15px; }
122
+ .screw.br { bottom: 15px; right: 15px; }
123
+
124
+ /* --- Screen Area --- */
125
+ .screen-bezel {
126
+ background: #000;
127
+ border-radius: 6px;
128
+ padding: 10px;
129
+ box-shadow: inset 0 0 15px rgba(0,0,0,1);
130
+ position: relative;
131
+ border: 1px solid #333;
132
+ }
133
+
134
+ .screen-crt {
135
+ width: 100%;
136
+ aspect-ratio: 16/9; /* Modern aspect ratio for AI video */
137
+ background: #080808;
138
+ border-radius: 2px;
139
+ position: relative;
140
+ overflow: hidden;
141
+ border: 1px solid #222;
142
+ }
143
+
144
+ /* Media Elements */
145
+ video, img.source-image {
146
+ width: 100%;
147
+ height: 100%;
148
+ object-fit: cover;
149
+ display: none;
150
+ }
151
+
152
+ /* Generated Video Simulation (Ken Burns Effect) */
153
+ .simulated-video {
154
+ width: 100%;
155
+ height: 100%;
156
+ object-fit: cover;
157
+ display: block;
158
+ }
159
+
160
+ .animating-pan {
161
+ animation: panZoom 10s infinite alternate ease-in-out;
162
+ }
163
+
164
+ @keyframes panZoom {
165
+ 0% { transform: scale(1) translate(0, 0); }
166
+ 100% { transform: scale(1.1) translate(-2%, -2%); }
167
+ }
168
+
169
+ /* CRT Effects */
170
+ .scanlines {
171
+ position: absolute;
172
+ top: 0; left: 0; width: 100%; height: 100%;
173
+ background: linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,0) 50%, rgba(0,0,0,0.3) 50%, rgba(0,0,0,0.3));
174
+ background-size: 100% 4px;
175
+ pointer-events: none;
176
+ z-index: 10;
177
+ }
178
+
179
+ .screen-glow {
180
+ position: absolute;
181
+ top: 0; left: 0; width: 100%; height: 100%;
182
+ background: radial-gradient(circle, rgba(0,0,0,0) 50%, rgba(0,0,0,0.8) 100%);
183
+ box-shadow: inset 0 0 2rem rgba(0,0,0,0.9);
184
+ pointer-events: none;
185
+ z-index: 11;
186
+ }
187
+
188
+ .no-signal-text {
189
+ position: absolute;
190
+ top: 50%; left: 50%;
191
+ transform: translate(-50%, -50%);
192
+ color: var(--accent-cyan);
193
+ font-size: 1.2rem;
194
+ text-transform: uppercase;
195
+ letter-spacing: 3px;
196
+ opacity: 0.5;
197
+ z-index: 5;
198
+ text-align: center;
199
+ display: flex;
200
+ flex-direction: column;
201
+ align-items: center;
202
+ gap: 10px;
203
+ }
204
+
205
+ .loader-ring {
206
+ width: 40px; height: 40px;
207
+ border: 2px solid transparent;
208
+ border-top-color: var(--accent-cyan);
209
+ border-radius: 50%;
210
+ animation: spin 1s linear infinite;
211
+ display: none;
212
+ }
213
+
214
+ @keyframes spin { 100% { transform: rotate(360deg); } }
215
+
216
+ /* --- Prompt Input Terminal --- */
217
+ .prompt-container {
218
+ background: #111;
219
+ border: 1px solid #333;
220
+ border-radius: 4px;
221
+ padding: 8px 12px;
222
+ display: flex;
223
+ align-items: center;
224
+ gap: 10px;
225
+ box-shadow: inset 0 2px 5px rgba(0,0,0,0.5);
226
+ }
227
+
228
+ .prompt-icon {
229
+ color: var(--accent-cyan);
230
+ font-size: 0.9rem;
231
+ }
232
+
233
+ .prompt-input {
234
+ background: transparent;
235
+ border: none;
236
+ color: #ccc;
237
+ font-family: "Courier New", monospace;
238
+ font-size: 0.9rem;
239
+ flex-grow: 1;
240
+ outline: none;
241
+ text-transform: uppercase;
242
+ }
243
+
244
+ .prompt-input::placeholder {
245
+ color: #444;
246
+ }
247
+
248
+ /* --- Control Panel --- */
249
+ .control-panel {
250
+ background: linear-gradient(to bottom, #252525, #151515);
251
+ border-radius: 6px;
252
+ padding: 15px;
253
+ display: flex;
254
+ flex-wrap: wrap;
255
+ justify-content: space-between;
256
+ align-items: center;
257
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.05), 0 5px 15px rgba(0,0,0,0.5);
258
+ border-top: 1px solid #444;
259
+ }
260
+
261
+ .brand-logo {
262
+ font-weight: 900;
263
+ font-size: 1.5rem;
264
+ color: #fff;
265
+ letter-spacing: 2px;
266
+ margin-right: 20px;
267
+ text-shadow: 0 0 5px rgba(255,255,255,0.2);
268
+ }
269
+
270
+ .lcd-display {
271
+ background: var(--lcd-bg);
272
+ color: var(--lcd-text);
273
+ font-family: "VT323", monospace;
274
+ padding: 10px 15px;
275
+ border-radius: 2px;
276
+ border: 1px solid #333;
277
+ font-size: 1.4rem;
278
+ min-width: 140px;
279
+ text-align: center;
280
+ box-shadow: 0 0 10px rgba(0, 240, 255, 0.1);
281
+ text-shadow: 0 0 5px rgba(0, 240, 255, 0.5);
282
+ position: relative;
283
+ overflow: hidden;
284
+ }
285
+
286
+ /* --- Buttons --- */
287
+ .buttons-group {
288
+ display: flex;
289
+ gap: 12px;
290
+ align-items: center;
291
+ }
292
+
293
+ .vcr-btn {
294
+ width: 55px;
295
+ height: 55px;
296
+ border-radius: 50%;
297
+ border: 1px solid #111;
298
+ background: linear-gradient(145deg, #333, #222);
299
+ box-shadow: 0 4px 0 #000, 0 5px 10px rgba(0,0,0,0.5);
300
+ color: #888;
301
+ font-size: 1.2rem;
302
+ cursor: pointer;
303
+ transition: all 0.1s;
304
+ position: relative;
305
+ display: flex;
306
+ justify-content: center;
307
+ align-items: center;
308
+ }
309
+
310
+ .vcr-btn:active:not(:disabled) {
311
+ transform: translateY(4px);
312
+ box-shadow: 0 0 0 #000;
313
+ }
314
+
315
+ .vcr-btn:disabled {
316
+ opacity: 0.3;
317
+ cursor: not-allowed;
318
+ filter: grayscale(1);
319
+ }
320
+
321
+ /* Special Button: Generate */
322
+ .vcr-btn.generate {
323
+ background: linear-gradient(145deg, #0044aa, #002266);
324
+ color: white;
325
+ box-shadow: 0 4px 0 #001133, 0 0 15px rgba(0, 240, 255, 0.3);
326
+ border: 1px solid #0066ff;
327
+ }
328
+
329
+ .vcr-btn.generate:hover:not(:disabled) {
330
+ box-shadow: 0 4px 0 #001133, 0 0 25px rgba(0, 240, 255, 0.6);
331
+ }
332
+
333
+ .vcr-btn.eject {
334
+ width: 35px;
335
+ height: 35px;
336
+ font-size: 0.9rem;
337
+ background: #222;
338
+ border-radius: 4px;
339
+ color: #666;
340
+ }
341
+
342
+ /* --- Input Slot --- */
343
+ .tape-slot-container {
344
+ width: 100%;
345
+ height: 50px;
346
+ background: #0a0a0a;
347
+ border-radius: 4px;
348
+ position: relative;
349
+ overflow: hidden;
350
+ border: 1px solid #333;
351
+ display: flex;
352
+ align-items: center;
353
+ justify-content: center;
354
+ box-shadow: inset 0 5px 10px #000;
355
+ }
356
+
357
+ .tape-label {
358
+ color: var(--accent-cyan);
359
+ font-size: 0.75rem;
360
+ text-transform: uppercase;
361
+ letter-spacing: 2px;
362
+ z-index: 2;
363
+ pointer-events: none;
364
+ opacity: 0.7;
365
+ }
366
+
367
+ #fileInput {
368
+ position: absolute;
369
+ width: 100%;
370
+ height: 100%;
371
+ opacity: 0;
372
+ cursor: pointer;
373
+ z-index: 10;
374
+ }
375
+
376
+ .tape-visual {
377
+ position: absolute;
378
+ top: 0; left: 0; width: 100%; height: 100%;
379
+ background: #111;
380
+ display: flex;
381
+ justify-content: center;
382
+ align-items: center;
383
+ transform: translateY(-100%);
384
+ transition: transform 0.4s cubic-bezier(0.25, 1, 0.5, 1);
385
+ z-index: 5;
386
+ border-bottom: 2px solid var(--accent-cyan);
387
+ }
388
+ .tape-visual.inserted { transform: translateY(0); }
389
 
390
+ .tape-body {
391
+ width: 70%; height: 30px;
392
+ background: #222;
393
+ border-radius: 2px;
394
+ position: relative;
395
+ border: 1px solid #444;
396
+ display: flex;
397
+ align-items: center;
398
+ justify-content: center;
399
+ color: #555;
400
+ font-size: 0.6rem;
401
+ font-family: sans-serif;
402
+ }
403
+
404
+ /* Progress Bar */
405
+ .progress-container {
406
+ width: 100%; height: 4px;
407
+ background: #222;
408
+ margin-top: 15px;
409
+ border-radius: 2px;
410
+ overflow: hidden;
411
+ position: relative;
412
+ }
413
+ .progress-bar {
414
+ height: 100%;
415
+ background: var(--accent-cyan);
416
+ width: 0%;
417
+ box-shadow: 0 0 10px var(--accent-cyan);
418
+ }
419
+
420
+ /* Glitch Animation for Generation */
421
+ .glitch-overlay {
422
+ position: absolute;
423
+ top: 0; left: 0; width: 100%; height: 100%;
424
+ background: rgba(0, 240, 255, 0.1);
425
+ z-index: 20;
426
+ display: none;
427
+ mix-blend-mode: overlay;
428
+ }
429
+
430
+ @keyframes glitch-anim {
431
+ 0% { clip-path: inset(10% 0 80% 0); transform: translate(-2px, 2px); }
432
+ 20% { clip-path: inset(80% 0 10% 0); transform: translate(2px, -2px); }
433
+ 40% { clip-path: inset(40% 0 40% 0); transform: translate(-2px, 2px); }
434
+ 60% { clip-path: inset(10% 0 60% 0); transform: translate(2px, -2px); }
435
+ 80% { clip-path: inset(50% 0 20% 0); transform: translate(-2px, 2px); }
436
+ 100% { clip-path: inset(20% 0 50% 0); transform: translate(2px, -2px); }
437
+ }
438
+
439
+ .glitching {
440
+ display: block;
441
+ animation: glitch-anim 0.2s infinite linear;
442
+ }
443
+
444
+ /* Responsive */
445
+ @media (max-width: 600px) {
446
+ .vcr-device { padding: 15px; width: 95%; }
447
+ .control-panel { gap: 15px; justify-content: center; }
448
+ .brand-logo { display: none; } /* Hide logo on mobile to save space */
449
+ .vcr-btn { width: 45px; height: 45px; font-size: 1rem; }
450
+ }
451
+ </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
  </head>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
 
454
+ <body>
 
 
 
 
 
 
 
 
 
455
 
456
+ <header class="top-bar">
457
+ <div class="brand-title">
458
+ SORA 2 <span class="beta-badge">BETA</span>
459
+ </div>
460
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
461
+ Built with anycoder <i class="fas fa-external-link-alt"></i>
462
+ </a>
463
+ </header>
464
+
465
+ <main class="vcr-device">
466
+ <div class="screw tl"></div><div class="screw tr"></div>
467
+ <div class="screw bl"></div><div class="screw br"></div>
468
+
469
+ <!-- Screen Section -->
470
+ <div class="screen-bezel">
471
+ <div class="screen-crt" id="screenArea">
472
+ <div class="scanlines"></div>
473
+ <div class="screen-glow"></div>
474
+ <div class="glitch-overlay" id="glitchOverlay"></div>
475
+
476
+ <div class="no-signal-text" id="noSignal">
477
+ <i class="fas fa-cube fa-2x"></i>
478
+ <br>WAITING FOR INPUT
479
+ <div style="font-size: 0.7rem; margin-top:5px; color:#555;">IMG OR VIDEO FILE</div>
480
+ <div class="loader-ring" id="loaderRing"></div>
 
 
 
 
 
 
 
 
 
 
 
 
481
  </div>
482
 
483
+ <!-- Media Containers -->
484
+ <img id="sourceImage" class="source-image" alt="Source">
485
+ <div id="simulatedContainer" style="width:100%; height:100%; display:none; overflow:hidden;">
486
+ <img id="simulatedImage" class="simulated-video" alt="Generated">
487
  </div>
488
+ <video id="videoPlayer" playsinline loop></video>
489
+ </div>
490
+ </div>
491
+
492
+ <!-- Prompt Input -->
493
+ <div class="prompt-container">
494
+ <i class="fas fa-terminal prompt-icon"></i>
495
+ <input type="text" class="prompt-input" id="promptInput" placeholder="Describe video motion (e.g. 'Drone shot zooming in')..." autocomplete="off">
496
+ </div>
497
+
498
+ <!-- Input Slot -->
499
+ <div class="tape-slot-container">
500
+ <div class="tape-label">UPLOAD SOURCE MEDIA</div>
501
+ <input type="file" id="fileInput" accept="image/*,video/*">
502
+
503
+ <div class="tape-visual" id="tapeVisual">
504
+ <div class="tape-body">DATA CASSETTE</div>
505
+ </div>
506
+ </div>
507
+
508
+ <!-- Controls -->
509
+ <div class="control-panel">
510
+ <div class="brand-logo">SORA</div>
511
+
512
+ <div class="lcd-display" id="lcdDisplay">
513
+ IDLE
514
+ </div>
515
+
516
+ <div class="buttons-group">
517
+ <!-- Generate Button (formerly Record) -->
518
+ <button class="vcr-btn generate" id="btnGenerate" title="Generate Video" disabled>
519
+ <i class="fas fa-wand-magic-sparkles"></i>
520
+ </button>
521
 
522
+ <button class="vcr-btn" id="btnPlay" title="Play" disabled>
523
+ <i class="fas fa-play"></i>
524
+ </button>
525
+
526
+ <button class="vcr-btn" id="btnStop" title="Stop" disabled>
527
+ <i class="fas fa-stop"></i>
528
+ </button>
529
+
530
+ <button class="vcr-btn eject" id="btnEject" title="Eject" disabled>
531
+ <i class="fas fa-eject"></i>
532
+ </button>
533
+ </div>
534
+ </div>
535
+
536
+ <!-- Progress Bar -->
537
+ <div class="progress-container">
538
+ <div class="progress-bar" id="progressBar"></div>
539
+ </div>
540
+ </main>
541
+
542
+ <script>
543
+ // --- Elements ---
544
+ const fileInput = document.getElementById('fileInput');
545
+ const promptInput = document.getElementById('promptInput');
546
+ const videoPlayer = document.getElementById('videoPlayer');
547
+ const sourceImage = document.getElementById('sourceImage');
548
+ const simulatedContainer = document.getElementById('simulatedContainer');
549
+ const simulatedImage = document.getElementById('simulatedImage');
550
+ const noSignal = document.getElementById('noSignal');
551
+ const tapeVisual = document.getElementById('tapeVisual');
552
+ const lcdDisplay = document.getElementById('lcdDisplay');
553
+ const progressBar = document.getElementById('progressBar');
554
+ const glitchOverlay = document.getElementById('glitchOverlay');
555
+ const loaderRing = document.getElementById('loaderRing');
556
+
557
+ // Buttons
558
+ const btnPlay = document.getElementById('btnPlay');
559
+ const btnStop = document.getElementById('btnStop');
560
+ const btnGenerate = document.getElementById('btnGenerate');
561
+ const btnEject = document.getElementById('btnEject');
562
+
563
+ // State
564
+ let isMediaLoaded = false;
565
+ let mediaType = null; // 'image' or 'video'
566
+ let isGenerated = false;
567
+ let isPlaying = false;
568
+ let updateTimer;
569
+
570
+ // --- Utility: Format Time ---
571
+ function formatTime(seconds) {
572
+ const h = Math.floor(seconds / 3600);
573
+ const m = Math.floor((seconds % 3600) / 60);
574
+ const s = Math.floor(seconds % 60);
575
+ return `${h.toString().padStart(2,'0')}:${m.toString().padStart(2,'0')}:${s.toString().padStart(2,'0')}`;
576
+ }
577
+
578
+ // --- Event: File Upload ---
579
+ fileInput.addEventListener('change', function(e) {
580
+ const file = e.target.files[0];
581
+ if (!file) return;
582
+
583
+ // Reset State
584
+ resetSystem();
585
+
586
+ // Visual Feedback
587
+ tapeVisual.classList.add('inserted');
588
+ noSignal.style.display = 'none';
589
+ loaderRing.style.display = 'block';
590
+ lcdDisplay.textContent = "LOADING";
591
+ lcdDisplay.style.color = "var(--accent-cyan)";
592
+
593
+ const fileURL = URL.createObjectURL(file);
594
+
595
+ setTimeout(() => {
596
+ if (file.type.startsWith('image/')) {
597
+ mediaType = 'image';
598
+ sourceImage.src = fileURL;
599
+ sourceImage.style.display = 'block';
600
+ simulatedImage.src = fileURL; // Prepare for simulation
601
+ lcdDisplay.textContent = "IMG READY";
602
 
603
+ // Enable Generate
604
+ btnGenerate.disabled = false;
605
+ btnEject.disabled = false;
606
+
607
+ } else if (file.type.startsWith('video/')) {
608
+ mediaType = 'video';
609
+ videoPlayer.src = fileURL;
610
  videoPlayer.style.display = 'block';
611
+ lcdDisplay.textContent = "VIDEO READY";
612
 
613
+ // Enable Play controls directly
614
  btnPlay.disabled = false;
615
  btnStop.disabled = false;
 
 
616
  btnEject.disabled = false;
617
 
618
+ // Auto-play preview
 
 
 
 
619
  togglePlay();
620
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
621
 
622
+ loaderRing.style.display = 'none';
623
+ isMediaLoaded = true;
624
 
625
+ }, 800);
626
+ });
 
 
627
 
628
+ // --- Event: Generate (Sora Simulation) ---
629
+ btnGenerate.addEventListener('click', function() {
630
+ if (mediaType !== 'image' || !isMediaLoaded) return;
631
 
632
+ // UI Update
633
+ btnGenerate.disabled = true;
634
+ btnPlay.disabled = true;
635
+ btnStop.disabled = true;
636
+
637
+ sourceImage.style.display = 'none';
638
+ noSignal.style.display = 'flex';
639
+ noSignal.innerHTML = `<div class="loader-ring" style="display:block"></div><br>DIFFUSING...`;
640
+
641
+ glitchOverlay.classList.add('glitching');
642
+ lcdDisplay.style.color = "white";
643
+
644
+ // Simulation Steps
645
+ const steps = ["ANALYZING", "DENOISING", "UPSCALING", "RENDERING"];
646
+ let stepIndex = 0;
647
+
648
+ progressBar.style.width = '0%';
649
+
650
+ const interval = setInterval(() => {
651
+ if (stepIndex < steps.length) {
652
+ lcdDisplay.textContent = steps[stepIndex];
653
+ progressBar.style.width = `${((stepIndex + 1) / steps.length) * 100}%`;
654
+ stepIndex++;
655
+ } else {
656
+ clearInterval(interval);
657
+ finishGeneration();
658
+ }
659
+ }, 800);
660
+ });
661
+
662
+ function finishGeneration() {
663
+ glitchOverlay.classList.remove('glitching');
664
+ isGenerated = true;
665
+
666
+ // Show "Generated" Content (Simulated via CSS animation)
667
+ noSignal.style.display = 'none';
668
+ simulatedContainer.style.display = 'block';
669
+
670
+ lcdDisplay.textContent = "COMPLETE";
671
+ lcdDisplay.style.color = "#00ff66"; // Success Green
672
+ lcdDisplay.style.textShadow = "0 0 10px #00ff66";
673
+
674
+ btnGenerate.disabled = true; // Already generated
675
+ btnPlay.disabled = false;
676
+ btnStop.disabled = false;
677
+
678
+ // Auto-play generated result
679
+ togglePlay();
680
+ }
681
+
682
+ // --- Event: Play/Pause ---
683
+ function togglePlay() {
684
+ if (!isMediaLoaded) return;
685
+
686
+ if (mediaType === 'video') {
687
  if (videoPlayer.paused) {
688
+ videoPlayer.play();
689
+ isPlaying = true;
690
+ startTracking();
 
 
 
 
691
  } else {
692
  videoPlayer.pause();
693
  isPlaying = false;
 
694
  stopTracking();
695
  }
696
+ } else if (mediaType === 'image' && isGenerated) {
697
+ // Toggle CSS animation class
698
+ if (simulatedImage.classList.contains('animating-pan')) {
699
+ simulatedImage.classList.remove('animating-pan');
700
+ isPlaying = false;
701
+ stopTracking();
702
+ } else {
703
+ simulatedImage.classList.add('animating-pan');
704
+ isPlaying = true;
705
+ startFakeTracking();
706
+ }
707
  }
708
+ updatePlayButtonIcon();
709
+ }
710
 
711
+ btnPlay.addEventListener('click', togglePlay);
712
 
713
+ function updatePlayButtonIcon() {
714
+ btnPlay.innerHTML = isPlaying ? '<i class="fas fa-pause"></i>' : '<i class="fas fa-play"></i>';
715
+ }
716
 
717
+ // --- Event: Stop ---
718
+ btnStop.addEventListener('click', function() {
719
+ if (mediaType === 'video') {
720
  videoPlayer.pause();
721
  videoPlayer.currentTime = 0;
722
+ } else if (isGenerated) {
723
+ simulatedImage.classList.remove('animating-pan');
724
+ }
725
+ isPlaying = false;
726
+ stopTracking();
727
+ progressBar.style.width = '0%';
728
+ lcdDisplay.textContent = isGenerated ? "READY" : "IMG READY";
729
+ lcdDisplay.style.color = "var(--accent-cyan)";
730
+ updatePlayButtonIcon();
731
+ });
732
+
733
+ // --- Event: Eject ---
734
+ btnEject.addEventListener('click', function() {
735
+ resetSystem();
736
+ tapeVisual.classList.remove('inserted');
737
+ fileInput.value = '';
738
+ isMediaLoaded = false;
739
+ });
740
+
741
+ function resetSystem() {
742
+ // Stop everything
743
+ videoPlayer.pause();
744
+ videoPlayer.currentTime = 0;
745
+ videoPlayer.src = "";
746
+ videoPlayer.style.display = 'none';
747
+
748
+ sourceImage.style.display = 'none';
749
+ sourceImage.src = "";
750
+
751
+ simulatedContainer.style.display = 'none';
752
+ simulatedImage.classList.remove('animating-pan');
753
+
754
+ noSignal.style.display = 'flex';
755
+ noSignal.innerHTML = `<i class="fas fa-cube fa-2x"></i><br>WAITING FOR INPUT<div style="font-size: 0.7rem; margin-top:5px; color:#555;">IMG OR VIDEO FILE</div>`;
756
+
757
+ // Disable buttons
758
+ btnPlay.disabled = true;
759
+ btnStop.disabled = true;
760
+ btnGenerate.disabled = true;
761
+ btnEject.disabled = true;
762
+
763
+ // Reset Display
764
+ lcdDisplay.textContent = "IDLE";
765
+ lcdDisplay.style.color = "var(--accent-cyan)";
766
+ lcdDisplay.style.textShadow = "0 0 5px rgba(0, 240, 255, 0.5)";
767
+ progressBar.style.width = '0%';
768
+
769
+ isGenerated = false;
770
+ isPlaying = false;
771
+ stopTracking();
772
+ }
773
+
774
+ // --- Tracking Logic ---
775
+ function startTracking() {
776
+ clearInterval(updateTimer);
777
+ if (mediaType === 'video') {
778
  updateTimer = setInterval(() => {
779
  if (!videoPlayer.paused) {
780
+ lcdDisplay.textContent = formatTime(videoPlayer.currentTime);
781
+ const pct = (videoPlayer.currentTime / videoPlayer.duration) * 100;
 
 
 
 
 
 
782
  progressBar.style.width = `${pct}%`;
783
  }
784
  }, 100);
785
  }
786
+ }
787
+
788
+ // Fake tracking for simulated video
789
+ function startFakeTracking() {
790
+ clearInterval(updateTimer);
791
+ let duration = 10; // Simulated 10s clip
792
+ let current = 0;
793
+
794
+ updateTimer = setInterval(() => {
795
+ if (isPlaying) {
796
+ current += 0.1;
797
+ if (current >= duration) current = 0; // Loop
798
+ lcdDisplay.textContent = formatTime(current);
799
+ progressBar.style.width = `${(current / duration) * 100}%`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
800
  }
801
+ }, 100);
802
+ }
803
+
804
+ function stopTracking() {
805
+ clearInterval(updateTimer);
806
+ }
807
+
808
+ // --- Video Ended ---
809
+ videoPlayer.addEventListener('ended', () => {
810
+ isPlaying = false;
811
+ updatePlayButtonIcon();
812
+ stopTracking();
813
+ lcdDisplay.textContent = "END";
814
+ });
815
+
816
+ </script>
817
  </body>
818
  </html>