TioPeperino commited on
Commit
7f1be5c
·
verified ·
1 Parent(s): 84e378d

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +841 -19
index.html CHANGED
@@ -1,19 +1,841 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>QPrompt Redesigned - Professional Teleprompter</title>
7
+ <!-- Font Awesome for Icons -->
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <!-- Google Fonts -->
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet">
11
+
12
+ <style>
13
+ :root {
14
+ --bg-color: #121212;
15
+ --surface-color: #1e1e1e;
16
+ --surface-hover: #2d2d2d;
17
+ --primary-color: #6366f1; /* Indigo */
18
+ --primary-hover: #4f46e5;
19
+ --accent-color: #ec4899; /* Pink */
20
+ --text-primary: #ffffff;
21
+ --text-secondary: #a1a1aa;
22
+ --border-color: #333;
23
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
24
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
25
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
26
+ }
27
+
28
+ * {
29
+ box-sizing: border-box;
30
+ margin: 0;
31
+ padding: 0;
32
+ }
33
+
34
+ body {
35
+ font-family: 'Inter', sans-serif;
36
+ background-color: var(--bg-color);
37
+ color: var(--text-primary);
38
+ height: 100vh;
39
+ overflow: hidden;
40
+ display: flex;
41
+ flex-direction: column;
42
+ }
43
+
44
+ /* Header */
45
+ header {
46
+ background-color: var(--surface-color);
47
+ border-bottom: 1px solid var(--border-color);
48
+ padding: 0.75rem 1.5rem;
49
+ display: flex;
50
+ justify-content: space-between;
51
+ align-items: center;
52
+ z-index: 50;
53
+ }
54
+
55
+ .logo {
56
+ display: flex;
57
+ align-items: center;
58
+ gap: 0.75rem;
59
+ font-weight: 700;
60
+ font-size: 1.25rem;
61
+ color: var(--text-primary);
62
+ text-decoration: none;
63
+ }
64
+
65
+ .logo i {
66
+ color: var(--primary-color);
67
+ font-size: 1.5rem;
68
+ }
69
+
70
+ .anycoder-link {
71
+ font-size: 0.875rem;
72
+ color: var(--text-secondary);
73
+ text-decoration: none;
74
+ transition: color 0.2s;
75
+ }
76
+
77
+ .anycoder-link:hover {
78
+ color: var(--primary-color);
79
+ }
80
+
81
+ /* Main Layout */
82
+ .app-container {
83
+ display: flex;
84
+ flex: 1;
85
+ height: calc(100vh - 60px);
86
+ overflow: hidden;
87
+ }
88
+
89
+ /* Sidebar (Controls) */
90
+ .sidebar {
91
+ width: 320px;
92
+ background-color: var(--surface-color);
93
+ border-right: 1px solid var(--border-color);
94
+ padding: 1.5rem;
95
+ display: flex;
96
+ flex-direction: column;
97
+ gap: 1.5rem;
98
+ overflow-y: auto;
99
+ transition: transform 0.3s ease;
100
+ }
101
+
102
+ .control-group {
103
+ display: flex;
104
+ flex-direction: column;
105
+ gap: 0.5rem;
106
+ }
107
+
108
+ .control-label {
109
+ font-size: 0.75rem;
110
+ text-transform: uppercase;
111
+ letter-spacing: 0.05em;
112
+ color: var(--text-secondary);
113
+ font-weight: 600;
114
+ }
115
+
116
+ .slider-container {
117
+ display: flex;
118
+ align-items: center;
119
+ gap: 1rem;
120
+ }
121
+
122
+ input[type="range"] {
123
+ -webkit-appearance: none;
124
+ width: 100%;
125
+ height: 6px;
126
+ background: #333;
127
+ border-radius: 3px;
128
+ outline: none;
129
+ }
130
+
131
+ input[type="range"]::-webkit-slider-thumb {
132
+ -webkit-appearance: none;
133
+ width: 18px;
134
+ height: 18px;
135
+ background: var(--primary-color);
136
+ border-radius: 50%;
137
+ cursor: pointer;
138
+ transition: background 0.2s;
139
+ }
140
+
141
+ input[type="range"]::-webkit-slider-thumb:hover {
142
+ background: var(--primary-hover);
143
+ }
144
+
145
+ .value-display {
146
+ font-family: 'Roboto Mono', monospace;
147
+ font-size: 0.875rem;
148
+ color: var(--text-primary);
149
+ min-width: 3ch;
150
+ }
151
+
152
+ .btn {
153
+ display: inline-flex;
154
+ align-items: center;
155
+ justify-content: center;
156
+ gap: 0.5rem;
157
+ padding: 0.75rem 1rem;
158
+ border-radius: 0.5rem;
159
+ font-weight: 600;
160
+ cursor: pointer;
161
+ transition: all 0.2s;
162
+ border: none;
163
+ font-family: inherit;
164
+ }
165
+
166
+ .btn-primary {
167
+ background-color: var(--primary-color);
168
+ color: white;
169
+ }
170
+
171
+ .btn-primary:hover {
172
+ background-color: var(--primary-hover);
173
+ }
174
+
175
+ .btn-secondary {
176
+ background-color: #333;
177
+ color: white;
178
+ }
179
+
180
+ .btn-secondary:hover {
181
+ background-color: #444;
182
+ }
183
+
184
+ .btn-danger {
185
+ background-color: transparent;
186
+ border: 1px solid #ef4444;
187
+ color: #ef4444;
188
+ }
189
+
190
+ .btn-danger:hover {
191
+ background-color: rgba(239, 68, 68, 0.1);
192
+ }
193
+
194
+ .toggle-switch {
195
+ display: flex;
196
+ align-items: center;
197
+ justify-content: space-between;
198
+ cursor: pointer;
199
+ }
200
+
201
+ .switch {
202
+ position: relative;
203
+ display: inline-block;
204
+ width: 44px;
205
+ height: 24px;
206
+ }
207
+
208
+ .switch input {
209
+ opacity: 0;
210
+ width: 0;
211
+ height: 0;
212
+ }
213
+
214
+ .slider {
215
+ position: absolute;
216
+ cursor: pointer;
217
+ top: 0;
218
+ left: 0;
219
+ right: 0;
220
+ bottom: 0;
221
+ background-color: #333;
222
+ transition: .4s;
223
+ border-radius: 24px;
224
+ }
225
+
226
+ .slider:before {
227
+ position: absolute;
228
+ content: "";
229
+ height: 18px;
230
+ width: 18px;
231
+ left: 3px;
232
+ bottom: 3px;
233
+ background-color: white;
234
+ transition: .4s;
235
+ border-radius: 50%;
236
+ }
237
+
238
+ input:checked + .slider {
239
+ background-color: var(--primary-color);
240
+ }
241
+
242
+ input:checked + .slider:before {
243
+ transform: translateX(20px);
244
+ }
245
+
246
+ /* Teleprompter Area */
247
+ .prompter-area {
248
+ flex: 1;
249
+ position: relative;
250
+ background-color: black;
251
+ overflow: hidden;
252
+ display: flex;
253
+ justify-content: center;
254
+ }
255
+
256
+ .prompter-content {
257
+ width: 100%;
258
+ height: 100%;
259
+ overflow-y: scroll; /* Allow manual scrolling when paused */
260
+ padding: 0 2rem;
261
+ /* Hide scrollbar for cleaner look */
262
+ scrollbar-width: none;
263
+ -ms-overflow-style: none;
264
+ }
265
+
266
+ .prompter-content::-webkit-scrollbar {
267
+ display: none;
268
+ }
269
+
270
+ #prompter-text {
271
+ color: white;
272
+ font-family: sans-serif;
273
+ line-height: 1.5;
274
+ outline: none;
275
+ white-space: pre-wrap;
276
+ padding-top: 45vh; /* Start text in middle */
277
+ padding-bottom: 45vh;
278
+ margin: 0 auto;
279
+ max-width: 90%;
280
+ text-align: left;
281
+ border: none;
282
+ background: transparent;
283
+ display: block;
284
+ }
285
+
286
+ /* Overlay Marker */
287
+ .marker-overlay {
288
+ position: absolute;
289
+ top: 48%; /* Slightly above center for reading line */
290
+ left: 0;
291
+ width: 100%;
292
+ height: 60px; /* Approximate height of a line or two */
293
+ border-top: 2px solid rgba(255, 255, 255, 0.2);
294
+ border-bottom: 2px solid rgba(255, 255, 255, 0.2);
295
+ background: rgba(255, 255, 255, 0.05);
296
+ pointer-events: none;
297
+ z-index: 10;
298
+ display: flex;
299
+ align-items: center;
300
+ }
301
+
302
+ .marker-overlay::before {
303
+ content: "\f0da"; /* FontAwesome caret right */
304
+ font-family: "Font Awesome 6 Free";
305
+ font-weight: 900;
306
+ color: var(--primary-color);
307
+ font-size: 2rem;
308
+ margin-left: 1rem;
309
+ opacity: 0.7;
310
+ }
311
+
312
+ .marker-overlay::after {
313
+ content: "\f0d9"; /* FontAwesome caret left */
314
+ font-family: "Font Awesome 6 Free";
315
+ font-weight: 900;
316
+ color: var(--primary-color);
317
+ font-size: 2rem;
318
+ margin-right: 1rem;
319
+ opacity: 0.7;
320
+ margin-left: auto;
321
+ }
322
+
323
+ /* Floating Controls (Play/Pause) */
324
+ .floating-controls {
325
+ position: absolute;
326
+ bottom: 2rem;
327
+ left: 50%;
328
+ transform: translateX(-50%);
329
+ background-color: rgba(30, 30, 30, 0.9);
330
+ backdrop-filter: blur(10px);
331
+ padding: 0.75rem 1.5rem;
332
+ border-radius: 50px;
333
+ display: flex;
334
+ gap: 1.5rem;
335
+ align-items: center;
336
+ box-shadow: var(--shadow-lg);
337
+ border: 1px solid var(--border-color);
338
+ z-index: 20;
339
+ transition: opacity 0.3s;
340
+ }
341
+
342
+ .floating-btn {
343
+ background: none;
344
+ border: none;
345
+ color: var(--text-primary);
346
+ font-size: 1.25rem;
347
+ cursor: pointer;
348
+ transition: color 0.2s;
349
+ width: 40px;
350
+ height: 40px;
351
+ display: flex;
352
+ align-items: center;
353
+ justify-content: center;
354
+ border-radius: 50%;
355
+ }
356
+
357
+ .floating-btn:hover {
358
+ background-color: rgba(255,255,255,0.1);
359
+ color: var(--primary-color);
360
+ }
361
+
362
+ .play-btn {
363
+ background-color: var(--primary-color);
364
+ width: 50px;
365
+ height: 50px;
366
+ font-size: 1.5rem;
367
+ }
368
+
369
+ .play-btn:hover {
370
+ background-color: var(--primary-hover);
371
+ color: white;
372
+ }
373
+
374
+ /* Mirror Classes */
375
+ .mirror-x { transform: scaleX(-1); }
376
+ .mirror-y { transform: scaleY(-1); }
377
+ .mirror-xy { transform: scale(-1, -1); }
378
+
379
+ /* Mobile Responsive */
380
+ @media (max-width: 768px) {
381
+ .app-container {
382
+ flex-direction: column;
383
+ }
384
+
385
+ .sidebar {
386
+ width: 100%;
387
+ height: auto;
388
+ max-height: 40vh;
389
+ border-right: none;
390
+ border-bottom: 1px solid var(--border-color);
391
+ order: 2; /* Move below prompter on mobile or hide behind a menu */
392
+ display: none; /* Hidden by default on mobile for cleaner view */
393
+ position: absolute;
394
+ bottom: 0;
395
+ z-index: 100;
396
+ box-shadow: 0 -4px 20px rgba(0,0,0,0.5);
397
+ }
398
+
399
+ .sidebar.active {
400
+ display: flex;
401
+ }
402
+
403
+ .mobile-menu-btn {
404
+ display: block;
405
+ }
406
+
407
+ .prompter-area {
408
+ height: 100%;
409
+ }
410
+ }
411
+
412
+ .mobile-menu-btn {
413
+ display: none;
414
+ background: none;
415
+ border: none;
416
+ color: white;
417
+ font-size: 1.25rem;
418
+ cursor: pointer;
419
+ }
420
+
421
+ @media (min-width: 769px) {
422
+ .mobile-menu-btn {
423
+ display: none;
424
+ }
425
+ }
426
+
427
+ /* Edit Mode Styling */
428
+ .prompter-content.editing #prompter-text {
429
+ border: 1px dashed var(--border-color);
430
+ background: rgba(255,255,255,0.05);
431
+ cursor: text;
432
+ }
433
+
434
+ </style>
435
+ </head>
436
+ <body>
437
+
438
+ <header>
439
+ <a href="#" class="logo">
440
+ <i class="fa-solid fa-closed-captioning"></i>
441
+ QPrompt Redux
442
+ </a>
443
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" class="anycoder-link" target="_blank">Built with anycoder</a>
444
+ <button class="mobile-menu-btn" id="toggleSettings">
445
+ <i class="fa-solid fa-sliders"></i>
446
+ </button>
447
+ </header>
448
+
449
+ <div class="app-container">
450
+ <!-- Sidebar Controls -->
451
+ <aside class="sidebar" id="sidebar">
452
+ <div class="control-group">
453
+ <div style="display: flex; justify-content: space-between; align-items: center;">
454
+ <span class="control-label">Status</span>
455
+ <button class="btn btn-secondary btn-sm" id="editBtn">
456
+ <i class="fa-solid fa-pen"></i> Edit Text
457
+ </button>
458
+ </div>
459
+ </div>
460
+
461
+ <div class="control-group">
462
+ <span class="control-label">Scroll Speed</span>
463
+ <div class="slider-container">
464
+ <i class="fa-solid fa-turtle" style="font-size: 0.8rem; color: var(--text-secondary);"></i>
465
+ <input type="range" id="speedRange" min="0" max="100" value="25">
466
+ <i class="fa-solid fa-rabbit" style="font-size: 0.8rem; color: var(--text-secondary);"></i>
467
+ <span class="value-display" id="speedValue">25</span>
468
+ </div>
469
+ </div>
470
+
471
+ <div class="control-group">
472
+ <span class="control-label">Font Size</span>
473
+ <div class="slider-container">
474
+ <i class="fa-solid fa-font" style="font-size: 0.8rem; color: var(--text-secondary);"></i>
475
+ <input type="range" id="fontSizeRange" min="20" max="150" value="60">
476
+ <i class="fa-solid fa-font" style="font-size: 1.2rem; color: var(--text-secondary);"></i>
477
+ <span class="value-display" id="fontSizeValue">60px</span>
478
+ </div>
479
+ </div>
480
+
481
+ <div class="control-group">
482
+ <span class="control-label">Line Height</span>
483
+ <div class="slider-container">
484
+ <i class="fa-solid fa-arrows-up-down" style="font-size: 0.8rem; color: var(--text-secondary);"></i>
485
+ <input type="range" id="lineHeightRange" min="10" max="30" value="15">
486
+ <span class="value-display" id="lineHeightValue">1.5</span>
487
+ </div>
488
+ </div>
489
+
490
+ <div class="control-group">
491
+ <span class="control-label">Margin (Width)</span>
492
+ <div class="slider-container">
493
+ <i class="fa-solid fa-left-right" style="font-size: 0.8rem; color: var(--text-secondary);"></i>
494
+ <input type="range" id="marginRange" min="50" max="100" value="90">
495
+ <span class="value-display" id="marginValue">90%</span>
496
+ </div>
497
+ </div>
498
+
499
+ <div class="control-group">
500
+ <span class="control-label">Colors</span>
501
+ <div style="display: flex; gap: 0.5rem;">
502
+ <button class="btn btn-secondary" style="flex: 1;" onclick="changeTheme('white', 'black')">B/W</button>
503
+ <button class="btn btn-secondary" style="flex: 1; background: white; color: black;" onclick="changeTheme('black', 'white')">W/B</button>
504
+ <button class="btn btn-secondary" style="flex: 1; color: #ffff00;" onclick="changeTheme('#ffff00', 'black')">Y/B</button>
505
+ <button class="btn btn-secondary" style="flex: 1; color: #00ff00;" onclick="changeTheme('#00ff00', 'black')">G/B</button>
506
+ </div>
507
+ </div>
508
+
509
+ <div class="control-group">
510
+ <span class="control-label">Mirroring</span>
511
+ <div class="toggle-switch">
512
+ <span>Flip Horizontal (X)</span>
513
+ <label class="switch">
514
+ <input type="checkbox" id="mirrorX">
515
+ <span class="slider"></span>
516
+ </label>
517
+ </div>
518
+ <div class="toggle-switch" style="margin-top: 0.5rem;">
519
+ <span>Flip Vertical (Y)</span>
520
+ <label class="switch">
521
+ <input type="checkbox" id="mirrorY">
522
+ <span class="slider"></span>
523
+ </label>
524
+ </div>
525
+ </div>
526
+
527
+ <div class="control-group" style="margin-top: auto;">
528
+ <button class="btn btn-danger" id="clearBtn">
529
+ <i class="fa-solid fa-trash"></i> Clear Text
530
+ </button>
531
+ </div>
532
+ </aside>
533
+
534
+ <!-- Prompter Area -->
535
+ <main class="prompter-area" id="prompterArea">
536
+ <div class="marker-overlay"></div>
537
+
538
+ <div class="prompter-content" id="scrollContainer">
539
+ <div id="prompter-text" contenteditable="false">Welcome to QPrompt Redux!
540
+
541
+ This is a modern, web-based teleprompter designed for content creators, speakers, and professionals.
542
+
543
+ How to use:
544
+ 1. Click the "Edit Text" button or the Pen icon to paste your script here.
545
+ 2. Adjust the Font Size and Speed using the sidebar controls.
546
+ 3. Use the Mirroring options if you are using a beam-splitter glass.
547
+ 4. Press the Play button below or Spacebar to start scrolling.
548
+
549
+ Features:
550
+ - Smooth scrolling engine
551
+ - Dark mode optimized
552
+ - Responsive design
553
+ - Mirroring for professional rigs
554
+ - Distraction-free interface
555
+
556
+ Tip: You can scroll manually with your mouse wheel or trackpad even when paused.
557
+
558
+ Paste your script here and start recording!
559
+ </div>
560
+ </div>
561
+
562
+ <!-- Floating Controls -->
563
+ <div class="floating-controls" id="floatingControls">
564
+ <button class="floating-btn" id="rewindBtn" title="Rewind to Top">
565
+ <i class="fa-solid fa-backward-step"></i>
566
+ </button>
567
+ <button class="floating-btn play-btn" id="playBtn" title="Play/Pause (Space)">
568
+ <i class="fa-solid fa-play"></i>
569
+ </button>
570
+ <button class="floating-btn" id="restartBtn" title="Restart">
571
+ <i class="fa-solid fa-rotate-left"></i>
572
+ </button>
573
+ <div style="width: 1px; height: 20px; background: rgba(255,255,255,0.2);"></div>
574
+ <button class="floating-btn" id="hideUIBtn" title="Hide UI">
575
+ <i class="fa-solid fa-eye-slash"></i>
576
+ </button>
577
+ </div>
578
+ </main>
579
+ </div>
580
+
581
+ <script>
582
+ // DOM Elements
583
+ const prompterText = document.getElementById('prompter-text');
584
+ const scrollContainer = document.getElementById('scrollContainer');
585
+ const playBtn = document.getElementById('playBtn');
586
+ const rewindBtn = document.getElementById('rewindBtn');
587
+ const restartBtn = document.getElementById('restartBtn');
588
+ const editBtn = document.getElementById('editBtn');
589
+ const clearBtn = document.getElementById('clearBtn');
590
+ const speedRange = document.getElementById('speedRange');
591
+ const speedValue = document.getElementById('speedValue');
592
+ const fontSizeRange = document.getElementById('fontSizeRange');
593
+ const fontSizeValue = document.getElementById('fontSizeValue');
594
+ const lineHeightRange = document.getElementById('lineHeightRange');
595
+ const lineHeightValue = document.getElementById('lineHeightValue');
596
+ const marginRange = document.getElementById('marginRange');
597
+ const marginValue = document.getElementById('marginValue');
598
+ const mirrorXCheck = document.getElementById('mirrorX');
599
+ const mirrorYCheck = document.getElementById('mirrorY');
600
+ const hideUIBtn = document.getElementById('hideUIBtn');
601
+ const sidebar = document.getElementById('sidebar');
602
+ const toggleSettings = document.getElementById('toggleSettings');
603
+ const floatingControls = document.getElementById('floatingControls');
604
+ const header = document.querySelector('header');
605
+
606
+ // State
607
+ let isPlaying = false;
608
+ let isEditing = false;
609
+ let scrollSpeed = 25;
610
+ let animationFrameId;
611
+ let lastTimestamp = 0;
612
+ let scroll accumulator = 0;
613
+
614
+ // --- Core Logic ---
615
+
616
+ function togglePlay() {
617
+ if (isEditing) return;
618
+ isPlaying = !isPlaying;
619
+ updatePlayButton();
620
+
621
+ if (isPlaying) {
622
+ lastTimestamp = performance.now();
623
+ animationFrameId = requestAnimationFrame(autoScroll);
624
+ // Hide mouse cursor after 2 seconds of inactivity
625
+ hideCursorTimer();
626
+ } else {
627
+ cancelAnimationFrame(animationFrameId);
628
+ document.body.style.cursor = 'default';
629
+ }
630
+ }
631
+
632
+ function updatePlayButton() {
633
+ const icon = playBtn.querySelector('i');
634
+ if (isPlaying) {
635
+ icon.classList.remove('fa-play');
636
+ icon.classList.add('fa-pause');
637
+ } else {
638
+ icon.classList.remove('fa-pause');
639
+ icon.classList.add('fa-play');
640
+ }
641
+ }
642
+
643
+ function autoScroll(timestamp) {
644
+ if (!isPlaying) return;
645
+
646
+ const deltaTime = timestamp - lastTimestamp;
647
+ lastTimestamp = timestamp;
648
+
649
+ // Calculate pixels to scroll based on speed (0-100)
650
+ // Speed factor: adjust multiplier to feel natural
651
+ const pixelsPerSecond = (scrollSpeed * scrollSpeed) / 10;
652
+
653
+ if (pixelsPerSecond > 0) {
654
+ const pixelsToScroll = (pixelsPerSecond * deltaTime) / 1000;
655
+ scrollContainer.scrollTop += pixelsToScroll;
656
+
657
+ // Stop at bottom
658
+ if (scrollContainer.scrollTop + scrollContainer.clientHeight >= scrollContainer.scrollHeight - 1) {
659
+ isPlaying = false;
660
+ updatePlayButton();
661
+ return;
662
+ }
663
+ }
664
+
665
+ animationFrameId = requestAnimationFrame(autoScroll);
666
+ }
667
+
668
+ function toggleEdit() {
669
+ isEditing = !isEditing;
670
+ prompterText.contentEditable = isEditing;
671
+ scrollContainer.classList.toggle('editing', isEditing);
672
+
673
+ if (isEditing) {
674
+ // Pause if playing
675
+ if (isPlaying) togglePlay();
676
+ editBtn.innerHTML = '<i class="fa-solid fa-check"></i> Done';
677
+ editBtn.classList.remove('btn-secondary');
678
+ editBtn.classList.add('btn-primary');
679
+ prompterText.focus();
680
+ } else {
681
+ editBtn.innerHTML = '<i class="fa-solid fa-pen"></i> Edit Text';
682
+ editBtn.classList.remove('btn-primary');
683
+ editBtn.classList.add('btn-secondary');
684
+ }
685
+ }
686
+
687
+ // --- UI Interactions ---
688
+
689
+ // Play/Pause
690
+ playBtn.addEventListener('click', togglePlay);
691
+
692
+ // Keyboard Shortcuts
693
+ document.addEventListener('keydown', (e) => {
694
+ if (isEditing) return; // Don't trigger shortcuts while typing
695
+
696
+ if (e.code === 'Space') {
697
+ e.preventDefault();
698
+ togglePlay();
699
+ } else if (e.code === 'ArrowUp') {
700
+ e.preventDefault();
701
+ scrollSpeed = Math.min(100, parseInt(scrollSpeed) + 5);
702
+ speedRange.value = scrollSpeed;
703
+ speedValue.textContent = scrollSpeed;
704
+ } else if (e.code === 'ArrowDown') {
705
+ e.preventDefault();
706
+ scrollSpeed = Math.max(0, parseInt(scrollSpeed) - 5);
707
+ speedRange.value = scrollSpeed;
708
+ speedValue.textContent = scrollSpeed;
709
+ }
710
+ });
711
+
712
+ // Rewind
713
+ rewindBtn.addEventListener('click', () => {
714
+ scrollContainer.scrollTo({ top: 0, behavior: 'smooth' });
715
+ });
716
+
717
+ // Restart (Rewind + Play)
718
+ restartBtn.addEventListener('click', () => {
719
+ scrollContainer.scrollTop = 0;
720
+ if (!isPlaying) togglePlay();
721
+ });
722
+
723
+ // Edit Mode
724
+ editBtn.addEventListener('click', toggleEdit);
725
+
726
+ // Clear Text
727
+ clearBtn.addEventListener('click', () => {
728
+ if (confirm("Are you sure you want to clear all text?")) {
729
+ prompterText.innerText = "";
730
+ if (!isEditing) toggleEdit();
731
+ }
732
+ });
733
+
734
+ // Speed Control
735
+ speedRange.addEventListener('input', (e) => {
736
+ scrollSpeed = e.target.value;
737
+ speedValue.textContent = scrollSpeed;
738
+ });
739
+
740
+ // Font Size
741
+ fontSizeRange.addEventListener('input', (e) => {
742
+ const size = e.target.value;
743
+ prompterText.style.fontSize = `${size}px`;
744
+ fontSizeValue.textContent = `${size}px`;
745
+ });
746
+
747
+ // Line Height
748
+ lineHeightRange.addEventListener('input', (e) => {
749
+ const val = e.target.value / 10;
750
+ prompterText.style.lineHeight = val;
751
+ lineHeightValue.textContent = val;
752
+ });
753
+
754
+ // Margin
755
+ marginRange.addEventListener('input', (e) => {
756
+ const val = e.target.value;
757
+ prompterText.style.maxWidth = `${val}%`;
758
+ marginValue.textContent = `${val}%`;
759
+ });
760
+
761
+ // Mirroring
762
+ function updateMirror() {
763
+ const x = mirrorXCheck.checked;
764
+ const y = mirrorYCheck.checked;
765
+
766
+ prompterText.className = ''; // reset
767
+ if (x && y) prompterText.classList.add('mirror-xy');
768
+ else if (x) prompterText.classList.add('mirror-x');
769
+ else if (y) prompterText.classList.add('mirror-y');
770
+ }
771
+
772
+ mirrorXCheck.addEventListener('change', updateMirror);
773
+ mirrorYCheck.addEventListener('change', updateMirror);
774
+
775
+ // Theme Change
776
+ window.changeTheme = function(textCol, bgCol) {
777
+ prompterText.style.color = textCol;
778
+ document.querySelector('.prompter-area').style.backgroundColor = bgCol;
779
+ };
780
+
781
+ // Hide UI
782
+ let uiHidden = false;
783
+ hideUIBtn.addEventListener('click', () => {
784
+ uiHidden = !uiHidden;
785
+ if (uiHidden) {
786
+ sidebar.style.transform = 'translateX(-100%)';
787
+ sidebar.style.display = 'none'; // For layout adjustment
788
+ header.style.display = 'none';
789
+ floatingControls.style.opacity = '0.2';
790
+ hideUIBtn.innerHTML = '<i class="fa-solid fa-eye"></i>';
791
+
792
+ // On hover restore opacity
793
+ floatingControls.addEventListener('mouseenter', () => floatingControls.style.opacity = '1');
794
+ floatingControls.addEventListener('mouseleave', () => floatingControls.style.opacity = '0.2');
795
+ } else {
796
+ sidebar.style.transform = 'none';
797
+ sidebar.style.display = 'flex';
798
+ header.style.display = 'flex';
799
+ floatingControls.style.opacity = '1';
800
+ hideUIBtn.innerHTML = '<i class="fa-solid fa-eye-slash"></i>';
801
+
802
+ // Remove hover listeners
803
+ floatingControls.replaceWith(floatingControls.cloneNode(true));
804
+ // Re-fetch because reference changed
805
+ document.getElementById('hideUIBtn').addEventListener('click', () => hideUIBtn.click());
806
+ // Re-bind other float buttons (simple reload of page logic usually easier but here we rebind)
807
+ // For simplicity in this single file demo, toggling visibility is enough
808
+ location.reload(); // Simplest way to restore event listeners properly without complex re-binding logic in this scope
809
+ }
810
+ });
811
+
812
+ // Mobile Menu
813
+ toggleSettings.addEventListener('click', () => {
814
+ sidebar.classList.toggle('active');
815
+ if (sidebar.classList.contains('active')) {
816
+ sidebar.style.display = 'flex';
817
+ } else {
818
+ sidebar.style.display = 'none';
819
+ }
820
+ });
821
+
822
+ // Mouse inactivity logic
823
+ let mouseTimer;
824
+ function hideCursorTimer() {
825
+ document.body.style.cursor = 'default';
826
+ clearTimeout(mouseTimer);
827
+ if(isPlaying) {
828
+ mouseTimer = setTimeout(() => {
829
+ document.body.style.cursor = 'none';
830
+ }, 2000);
831
+ }
832
+ }
833
+ document.addEventListener('mousemove', hideCursorTimer);
834
+
835
+ // Initialize defaults
836
+ prompterText.style.fontSize = '60px';
837
+ prompterText.style.lineHeight = '1.5';
838
+
839
+ </script>
840
+ </body>
841
+ </html>