@livepeer-frameworks/player-react 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -9
- package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +359 -0
- package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
- package/dist/cjs/assets/logomark.svg.js +8 -0
- package/dist/cjs/assets/logomark.svg.js.map +1 -0
- package/dist/cjs/components/DevModePanel.js +826 -0
- package/dist/cjs/components/DevModePanel.js.map +1 -0
- package/dist/cjs/components/DvdLogo.js +200 -0
- package/dist/cjs/components/DvdLogo.js.map +1 -0
- package/dist/cjs/components/Icons.js +439 -0
- package/dist/cjs/components/Icons.js.map +1 -0
- package/dist/cjs/components/IdleScreen.js +587 -0
- package/dist/cjs/components/IdleScreen.js.map +1 -0
- package/dist/cjs/components/LoadingScreen.js +523 -0
- package/dist/cjs/components/LoadingScreen.js.map +1 -0
- package/dist/cjs/components/Player.js +420 -0
- package/dist/cjs/components/Player.js.map +1 -0
- package/dist/cjs/components/PlayerControls.js +798 -0
- package/dist/cjs/components/PlayerControls.js.map +1 -0
- package/dist/cjs/components/PlayerErrorBoundary.js +80 -0
- package/dist/cjs/components/PlayerErrorBoundary.js.map +1 -0
- package/dist/cjs/components/SeekBar.js +253 -0
- package/dist/cjs/components/SeekBar.js.map +1 -0
- package/dist/cjs/components/SkipIndicator.js +92 -0
- package/dist/cjs/components/SkipIndicator.js.map +1 -0
- package/dist/cjs/components/SpeedIndicator.js +43 -0
- package/dist/cjs/components/SpeedIndicator.js.map +1 -0
- package/dist/cjs/components/StatsPanel.js +202 -0
- package/dist/cjs/components/StatsPanel.js.map +1 -0
- package/dist/cjs/components/StreamStateOverlay.js +229 -0
- package/dist/cjs/components/StreamStateOverlay.js.map +1 -0
- package/dist/cjs/components/ThumbnailOverlay.js +86 -0
- package/dist/cjs/components/ThumbnailOverlay.js.map +1 -0
- package/dist/cjs/components/TitleOverlay.js +32 -0
- package/dist/cjs/components/TitleOverlay.js.map +1 -0
- package/dist/cjs/context/PlayerContext.js +46 -0
- package/dist/cjs/context/PlayerContext.js.map +1 -0
- package/dist/cjs/hooks/useMetaTrack.js +165 -0
- package/dist/cjs/hooks/useMetaTrack.js.map +1 -0
- package/dist/cjs/hooks/usePlaybackQuality.js +131 -0
- package/dist/cjs/hooks/usePlaybackQuality.js.map +1 -0
- package/dist/cjs/hooks/usePlayerController.js +518 -0
- package/dist/cjs/hooks/usePlayerController.js.map +1 -0
- package/dist/cjs/hooks/usePlayerSelection.js +90 -0
- package/dist/cjs/hooks/usePlayerSelection.js.map +1 -0
- package/dist/cjs/hooks/useStreamState.js +360 -0
- package/dist/cjs/hooks/useStreamState.js.map +1 -0
- package/dist/cjs/hooks/useTelemetry.js +120 -0
- package/dist/cjs/hooks/useTelemetry.js.map +1 -0
- package/dist/cjs/hooks/useViewerEndpoints.js +222 -0
- package/dist/cjs/hooks/useViewerEndpoints.js.map +1 -0
- package/dist/cjs/index.js +97 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/ui/badge.js +34 -0
- package/dist/cjs/ui/badge.js.map +1 -0
- package/dist/cjs/ui/button.js +74 -0
- package/dist/cjs/ui/button.js.map +1 -0
- package/dist/cjs/ui/context-menu.js +163 -0
- package/dist/cjs/ui/context-menu.js.map +1 -0
- package/dist/cjs/ui/slider.js +60 -0
- package/dist/cjs/ui/slider.js.map +1 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
- package/dist/esm/assets/logomark.svg.js +4 -0
- package/dist/esm/assets/logomark.svg.js.map +1 -0
- package/dist/esm/components/DevModePanel.js +822 -0
- package/dist/esm/components/DevModePanel.js.map +1 -0
- package/dist/esm/components/DvdLogo.js +196 -0
- package/dist/esm/components/DvdLogo.js.map +1 -0
- package/dist/esm/components/Icons.js +421 -0
- package/dist/esm/components/Icons.js.map +1 -0
- package/dist/esm/components/IdleScreen.js +582 -0
- package/dist/esm/components/IdleScreen.js.map +1 -0
- package/dist/esm/components/LoadingScreen.js +519 -0
- package/dist/esm/components/LoadingScreen.js.map +1 -0
- package/dist/esm/components/Player.js +416 -0
- package/dist/esm/components/Player.js.map +1 -0
- package/dist/esm/components/PlayerControls.js +794 -0
- package/dist/esm/components/PlayerControls.js.map +1 -0
- package/dist/esm/components/PlayerErrorBoundary.js +76 -0
- package/dist/esm/components/PlayerErrorBoundary.js.map +1 -0
- package/dist/esm/components/SeekBar.js +249 -0
- package/dist/esm/components/SeekBar.js.map +1 -0
- package/dist/esm/components/SkipIndicator.js +88 -0
- package/dist/esm/components/SkipIndicator.js.map +1 -0
- package/dist/esm/components/SpeedIndicator.js +39 -0
- package/dist/esm/components/SpeedIndicator.js.map +1 -0
- package/dist/esm/components/StatsPanel.js +198 -0
- package/dist/esm/components/StatsPanel.js.map +1 -0
- package/dist/esm/components/StreamStateOverlay.js +224 -0
- package/dist/esm/components/StreamStateOverlay.js.map +1 -0
- package/dist/esm/components/ThumbnailOverlay.js +82 -0
- package/dist/esm/components/ThumbnailOverlay.js.map +1 -0
- package/dist/esm/components/TitleOverlay.js +28 -0
- package/dist/esm/components/TitleOverlay.js.map +1 -0
- package/dist/esm/context/PlayerContext.js +41 -0
- package/dist/esm/context/PlayerContext.js.map +1 -0
- package/dist/esm/hooks/useMetaTrack.js +163 -0
- package/dist/esm/hooks/useMetaTrack.js.map +1 -0
- package/dist/esm/hooks/usePlaybackQuality.js +129 -0
- package/dist/esm/hooks/usePlaybackQuality.js.map +1 -0
- package/dist/esm/hooks/usePlayerController.js +516 -0
- package/dist/esm/hooks/usePlayerController.js.map +1 -0
- package/dist/esm/hooks/usePlayerSelection.js +88 -0
- package/dist/esm/hooks/usePlayerSelection.js.map +1 -0
- package/dist/esm/hooks/useStreamState.js +358 -0
- package/dist/esm/hooks/useStreamState.js.map +1 -0
- package/dist/esm/hooks/useTelemetry.js +118 -0
- package/dist/esm/hooks/useTelemetry.js.map +1 -0
- package/dist/esm/hooks/useViewerEndpoints.js +220 -0
- package/dist/esm/hooks/useViewerEndpoints.js.map +1 -0
- package/dist/esm/index.js +23 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/ui/badge.js +31 -0
- package/dist/esm/ui/badge.js.map +1 -0
- package/dist/esm/ui/button.js +52 -0
- package/dist/esm/ui/button.js.map +1 -0
- package/dist/esm/ui/context-menu.js +132 -0
- package/dist/esm/ui/context-menu.js.map +1 -0
- package/dist/esm/ui/slider.js +38 -0
- package/dist/esm/ui/slider.js.map +1 -0
- package/dist/types/components/DvdLogo.d.ts +1 -1
- package/dist/types/components/Icons.d.ts +1 -1
- package/dist/types/components/Player.d.ts +1 -1
- package/dist/types/components/PlayerErrorBoundary.d.ts +2 -1
- package/dist/types/components/StreamStateOverlay.d.ts +2 -2
- package/dist/types/components/SubtitleRenderer.d.ts +2 -2
- package/dist/types/context/PlayerContext.d.ts +2 -2
- package/dist/types/context/index.d.ts +2 -2
- package/dist/types/hooks/useMetaTrack.d.ts +3 -3
- package/dist/types/hooks/usePlaybackQuality.d.ts +2 -2
- package/dist/types/hooks/usePlayerController.d.ts +26 -3
- package/dist/types/hooks/usePlayerSelection.d.ts +1 -1
- package/dist/types/hooks/useStreamState.d.ts +1 -1
- package/dist/types/hooks/useTelemetry.d.ts +1 -1
- package/dist/types/hooks/useViewerEndpoints.d.ts +3 -3
- package/dist/types/index.d.ts +28 -28
- package/dist/types/types.d.ts +3 -3
- package/dist/types/ui/select.d.ts +1 -1
- package/package.json +22 -14
- package/src/components/DevModePanel.tsx +244 -143
- package/src/components/DvdLogo.tsx +1 -1
- package/src/components/Icons.tsx +105 -25
- package/src/components/IdleScreen.tsx +262 -128
- package/src/components/LoadingScreen.tsx +169 -151
- package/src/components/LogoOverlay.tsx +3 -6
- package/src/components/Player.tsx +126 -59
- package/src/components/PlayerControls.tsx +384 -272
- package/src/components/PlayerErrorBoundary.tsx +7 -13
- package/src/components/SeekBar.tsx +96 -88
- package/src/components/SkipIndicator.tsx +2 -12
- package/src/components/SpeedIndicator.tsx +2 -11
- package/src/components/StatsPanel.tsx +31 -22
- package/src/components/StreamStateOverlay.tsx +105 -49
- package/src/components/SubtitleRenderer.tsx +29 -29
- package/src/components/ThumbnailOverlay.tsx +5 -6
- package/src/components/TitleOverlay.tsx +2 -8
- package/src/context/PlayerContext.tsx +4 -8
- package/src/context/index.ts +3 -3
- package/src/hooks/useMetaTrack.ts +27 -27
- package/src/hooks/usePlaybackQuality.ts +3 -3
- package/src/hooks/usePlayerController.ts +246 -138
- package/src/hooks/usePlayerSelection.ts +6 -6
- package/src/hooks/useStreamState.ts +51 -56
- package/src/hooks/useTelemetry.ts +18 -3
- package/src/hooks/useViewerEndpoints.ts +34 -23
- package/src/index.tsx +36 -28
- package/src/types.ts +8 -8
- package/src/ui/badge.tsx +6 -5
- package/src/ui/button.tsx +9 -8
- package/src/ui/context-menu.tsx +42 -61
- package/src/ui/select.tsx +13 -7
- package/src/ui/slider.tsx +18 -29
- package/dist/types/components/players/DashJsPlayer.d.ts +0 -18
- package/dist/types/components/players/HlsJsPlayer.d.ts +0 -18
- package/dist/types/components/players/MewsWsPlayer/index.d.ts +0 -18
- package/dist/types/components/players/MistPlayer.d.ts +0 -20
- package/dist/types/components/players/MistWebRTCPlayer/index.d.ts +0 -20
- package/dist/types/components/players/NativePlayer.d.ts +0 -19
- package/dist/types/components/players/VideoJsPlayer.d.ts +0 -18
- package/src/components/players/DashJsPlayer.tsx +0 -56
- package/src/components/players/HlsJsPlayer.tsx +0 -56
- package/src/components/players/MewsWsPlayer/index.tsx +0 -56
- package/src/components/players/MistPlayer.tsx +0 -60
- package/src/components/players/MistWebRTCPlayer/index.tsx +0 -59
- package/src/components/players/NativePlayer.tsx +0 -58
- package/src/components/players/VideoJsPlayer.tsx +0 -56
|
@@ -27,20 +27,23 @@ const AnimatedBubble: React.FC<AnimatedBubbleProps> = ({ index }) => {
|
|
|
27
27
|
// Fade in
|
|
28
28
|
setOpacity(0.15);
|
|
29
29
|
|
|
30
|
-
setTimeout(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// Move to new random position with new size while invisible
|
|
36
|
-
setPosition(getRandomPosition());
|
|
37
|
-
setSize(getRandomSize());
|
|
38
|
-
// Start next cycle after a brief delay to ensure position change is complete
|
|
30
|
+
setTimeout(
|
|
31
|
+
() => {
|
|
32
|
+
// Fade out
|
|
33
|
+
setOpacity(0);
|
|
34
|
+
|
|
39
35
|
setTimeout(() => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
// Move to new random position with new size while invisible
|
|
37
|
+
setPosition(getRandomPosition());
|
|
38
|
+
setSize(getRandomSize());
|
|
39
|
+
// Start next cycle after a brief delay to ensure position change is complete
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
animationCycle();
|
|
42
|
+
}, 200);
|
|
43
|
+
}, 1500); // Wait for fade out to complete
|
|
44
|
+
},
|
|
45
|
+
4000 + Math.random() * 3000
|
|
46
|
+
); // Stay visible for 4-7 seconds (was 2-4)
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
// Start the animation cycle with staggered timing
|
|
@@ -55,32 +58,34 @@ const AnimatedBubble: React.FC<AnimatedBubbleProps> = ({ index }) => {
|
|
|
55
58
|
const bubbleColors = [
|
|
56
59
|
"rgba(122, 162, 247, 0.2)", // Terminal Blue
|
|
57
60
|
"rgba(187, 154, 247, 0.2)", // Terminal Magenta
|
|
58
|
-
"rgba(158, 206, 106, 0.2)", // Strings/CSS classes
|
|
61
|
+
"rgba(158, 206, 106, 0.2)", // Strings/CSS classes
|
|
59
62
|
"rgba(115, 218, 202, 0.2)", // Terminal Green
|
|
60
63
|
"rgba(125, 207, 255, 0.2)", // Terminal Cyan
|
|
61
64
|
"rgba(247, 118, 142, 0.2)", // Keywords/Terminal Red
|
|
62
65
|
"rgba(224, 175, 104, 0.2)", // Terminal Yellow
|
|
63
|
-
"rgba(42, 195, 222, 0.2)",
|
|
66
|
+
"rgba(42, 195, 222, 0.2)", // Language functions
|
|
64
67
|
];
|
|
65
68
|
|
|
66
69
|
return (
|
|
67
70
|
<div
|
|
68
|
-
style={
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
style={
|
|
72
|
+
{
|
|
73
|
+
position: "absolute",
|
|
74
|
+
top: `${position.top}%`,
|
|
75
|
+
left: `${position.left}%`,
|
|
76
|
+
width: `${size}px`,
|
|
77
|
+
height: `${size}px`,
|
|
78
|
+
borderRadius: "50%",
|
|
79
|
+
background: bubbleColors[index % bubbleColors.length],
|
|
80
|
+
opacity: opacity,
|
|
81
|
+
transition: "opacity 1s ease-in-out",
|
|
82
|
+
pointerEvents: "none",
|
|
83
|
+
userSelect: "none",
|
|
84
|
+
WebkitUserSelect: "none",
|
|
85
|
+
MozUserSelect: "none",
|
|
86
|
+
msUserSelect: "none",
|
|
87
|
+
} as React.CSSProperties
|
|
88
|
+
}
|
|
84
89
|
/>
|
|
85
90
|
);
|
|
86
91
|
};
|
|
@@ -154,12 +159,12 @@ const CenterLogo: React.FC<CenterLogoProps> = ({ containerRef, scale = 0.2, onHi
|
|
|
154
159
|
useEffect(() => {
|
|
155
160
|
if (containerRef.current) {
|
|
156
161
|
const container = containerRef.current;
|
|
157
|
-
container.addEventListener(
|
|
158
|
-
container.addEventListener(
|
|
162
|
+
container.addEventListener("mousemove", handleMouseMove);
|
|
163
|
+
container.addEventListener("mouseleave", handleMouseLeave);
|
|
159
164
|
|
|
160
165
|
return () => {
|
|
161
|
-
container.removeEventListener(
|
|
162
|
-
container.removeEventListener(
|
|
166
|
+
container.removeEventListener("mousemove", handleMouseMove);
|
|
167
|
+
container.removeEventListener("mouseleave", handleMouseLeave);
|
|
163
168
|
};
|
|
164
169
|
}
|
|
165
170
|
}, [logoSize, containerRef]);
|
|
@@ -190,7 +195,9 @@ const CenterLogo: React.FC<CenterLogoProps> = ({ containerRef, scale = 0.2, onHi
|
|
|
190
195
|
height: `${logoSize * 1.4}px`,
|
|
191
196
|
borderRadius: "50%",
|
|
192
197
|
background: "rgba(122, 162, 247, 0.15)",
|
|
193
|
-
animation: isHovered
|
|
198
|
+
animation: isHovered
|
|
199
|
+
? "logoPulse 1s ease-in-out infinite"
|
|
200
|
+
: "logoPulse 3s ease-in-out infinite",
|
|
194
201
|
transform: isHovered ? "scale(1.2)" : "scale(1)",
|
|
195
202
|
transition: "transform 0.3s ease-out",
|
|
196
203
|
userSelect: "none",
|
|
@@ -206,24 +213,26 @@ const CenterLogo: React.FC<CenterLogoProps> = ({ containerRef, scale = 0.2, onHi
|
|
|
206
213
|
src={logomarkAsset}
|
|
207
214
|
alt="FrameWorks Logo"
|
|
208
215
|
onClick={handleLogoClick}
|
|
209
|
-
style={
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
216
|
+
style={
|
|
217
|
+
{
|
|
218
|
+
width: `${logoSize}px`,
|
|
219
|
+
height: `${logoSize}px`,
|
|
220
|
+
position: "relative",
|
|
221
|
+
zIndex: 1,
|
|
222
|
+
filter: isHovered
|
|
223
|
+
? "drop-shadow(0 6px 12px rgba(36, 40, 59, 0.4)) brightness(1.1)"
|
|
224
|
+
: "drop-shadow(0 4px 8px rgba(36, 40, 59, 0.3))",
|
|
225
|
+
transform: isHovered ? "scale(1.1)" : "scale(1)",
|
|
226
|
+
transition: "all 0.3s ease-out",
|
|
227
|
+
cursor: isHovered ? "pointer" : "default",
|
|
228
|
+
userSelect: "none",
|
|
229
|
+
WebkitUserSelect: "none",
|
|
230
|
+
MozUserSelect: "none",
|
|
231
|
+
msUserSelect: "none",
|
|
232
|
+
WebkitUserDrag: "none",
|
|
233
|
+
WebkitTouchCallout: "none",
|
|
234
|
+
} as React.CSSProperties
|
|
235
|
+
}
|
|
227
236
|
/>
|
|
228
237
|
</div>
|
|
229
238
|
);
|
|
@@ -246,51 +255,52 @@ const LoadingScreen: React.FC<LoadingScreenProps> = ({ message = "Waiting for so
|
|
|
246
255
|
const playHitmarkerSound = () => {
|
|
247
256
|
try {
|
|
248
257
|
// Embedded hitmarker sound as base64 data URL
|
|
249
|
-
const hitmarkerDataUrl =
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
258
|
+
const hitmarkerDataUrl =
|
|
259
|
+
"data:audio/mpeg;base64,SUQzBAAAAAAANFRDT04AAAAHAAADT3RoZXIAVFNTRQAAAA8AAANMYXZmNTcuODMuMTAwAAAAAAAAAAAA" +
|
|
260
|
+
"AAD/+1QAAAAAAAAAAAAAAAAAAAAA" +
|
|
261
|
+
"AAAAAAAAAAAAAAAAAAAAAABJbmZvAAAADwAAAAYAAAnAADs7Ozs7Ozs7Ozs7Ozs7OztiYmJiYmJiYmJi" +
|
|
262
|
+
"YmJiYmJiYomJiYmJiYmJiYmJiYmJiYmxsbGxsbGxsbGxsbGxsbGxsdjY2NjY2NjY2NjY2NjY2NjY////" +
|
|
263
|
+
"/////////////////wAAAABMYXZjNTcuMTAAAAAAAAAAAAAAAAAkAkAAAAAAAAAJwOuMZun/+5RkAA8S" +
|
|
264
|
+
"/F23AGAaAi0AF0AAAAAInXsEAIRXyQ8D4OQgjEhE3cO7ujuHF0XCOu4G7xKbi3Funu7u7p9dw7unu7u7" +
|
|
265
|
+
"p7u7u6fXcW7om7u7uiU3dxdT67u7p7uHdxelN3cW6fXcW7oXXd3eJTd3d0+u4t3iXdw4up70W4uiPruL" +
|
|
266
|
+
"DzMw8Pz79Y99JfkyfPv5/h9uTJoy79Y99Y97q3vyZPJk0ZfrL6x73Vn+J35dKKS/STQyQ8CAiCPNuRAO" +
|
|
267
|
+
"OqquAx+fzJeBKDAsgAMBuWcBsHKhjJTcCwIALyAvABbI0ZIcCmP8jHJe8gZAdVRp2TpnU/kUXV4iQuBA" +
|
|
268
|
+
"AkAQgisLPvwQ2Jz7wIkIpQ8QOl/KFy75w+2HpTFnRqXLQo0fzlSYRe5Ce9yZMEzRM4xesu95Mo8QQsoM" +
|
|
269
|
+
"H4gLg+fJqkmY3GZJE2kwGfMECJiAdIttoEa2yotfC7jsS2mjKgbzAfEMeiwZpGSUFCQwPKQiWXh0TnkN" +
|
|
270
|
+
"or5SmrKvwHlX2zFxKxPCzRL/+5RkIwADvUxLawwb0GdF6Y1hJlgNNJk+DSRwyQwI6AD2JCiBmhaff0dz" +
|
|
271
|
+
"CEBjgFABAcDNFc3YAEV4hQn0L/QvQnevom+n13eIjoTvABLrHg/L9RzdWXYonHbbbE2K0pX+gkL2g56R" +
|
|
272
|
+
"iwrbuWwhoABzQoMKOAIGAfE4UKk6BhSIJpECBq0CEYmZKYIiAJt72H24dNou7y/Ee7a/3v+MgySemSTY" +
|
|
273
|
+
"mnBAFwIAAGfCJ8/D9YfkwQEBcP38uA1d/EB1T5dZKEsgnuhwZirY5fIMRMdRn7U4OcN2m5NWeYdcPBwX" +
|
|
274
|
+
"DBOsJF1DBYks62pAURqz1hGoGHH/QIoRC80tYAJ8g4f3MPD51sywAbhAn/X9P/75tvZww3gZ3pYPDx/+" +
|
|
275
|
+
"ACO/7//ffHj/D/AAfATC4DYGFA3MRABo0lqWjBOl2yAda1C1BdhduXgm8FGnAQB/lDiEi6j9qw9EHigI" +
|
|
276
|
+
"IOLB6F1eIPd+T6Agc4//lMo6+k3tdttJY2gArU7cN07m2FLSm4gCjyz/+5RECwACwSRZawkdLFGi2mVh" +
|
|
277
|
+
"5h4LfFdPVPGACViTavaeMAAV0UkkEsDhxxJwqF04on002mZah8w9+5ItfSAoyZa1dchnPpLmAEKrVMRA" +
|
|
278
|
+
"//sD8w0WsB4xiw4JqaZMB45TdpIuXXUPf8Bpa35p/jQIAOAuZkmUeJoM5W6L2gqqO6rTuHjUTDnhy4Qi" +
|
|
279
|
+
"K348vtFysOizShoHbBpsPRYcSINCbiN4XOLPPAgq3dW2Ga7SlyiKXBV7W1RQl5BiiVGkwayJfEnPxgXk" +
|
|
280
|
+
"QeZxxzyhTuLO2XFUDDstoc6CkM1J8QZAjUN3bM8580cRygNfmPAELGjIH0Z/0A+8csyH/4eHvgAf8APg" +
|
|
281
|
+
"ABmZ98AARAADP////Dw8PHEmIpgGttpJQJsmZjq5nPQ8j5VqWW1evqdjP182PA6tHJZgkC5iSbEQkyJS" +
|
|
282
|
+
"z/BvP3eucLKN0+Wiza4feKKFBqiAEBAMXyYni5NZc16CDl/QY9j6BAcWSmQYcIcoMHYoQNBiIBgIBUAz" +
|
|
283
|
+
"QUMSnjj/+5RkCwADsFLffjEAAjrJe63JHACO6WtlnPMACKaCK1uMMADU5dI6JhW2cam98UlRmY4ihyKF" +
|
|
284
|
+
"rNsgpZd5PYgBALnYofKEt82De0GbW1DLibvFDK+bSeOm8qKdqUFZ7uiK8XMPHyqm3pTxUvcunUfxXEo9" +
|
|
285
|
+
"RNe5b/8vfCD3kzDN7vTtHyaIcntVDAYBAUBAAAAQBI2vguYNsHWm5AR3mZtZib8WAHFvz2Kf9//iYvlR" +
|
|
286
|
+
"B/+n///////////+UH7XoIDMoJAEAMtj8JshJPRwklVqNSpYnalfE+VzNCAISCoxVHEpIo/WrTiMvP7V" +
|
|
287
|
+
"TujOPnOglLbMLN/pq/d2Y4lRJIkSnPlUSJEjSKJqM41d88zWtMzP+fCOORmc9NeM+f1nnO//efM52/fG" +
|
|
288
|
+
"/ef385+5u+u1bRJkwU8FAkEItZpkRYeQYcAgZTEYlaZa2yROLeC0qdX73rZJJ/d2f6v6Or0u/+5FBYcn" +
|
|
289
|
+
"g0MlCiQTR9GUU5LScmSuSlH00IWqXA6jlw4BEcD/+5REEAAi3RtU+eYbGF1E+lk9g0YJzLUgh7BlQVGT" +
|
|
290
|
+
"ZJD0jKhhTNVilqrMzFRK+x/szcMKBWKep4NP1A0DR6RESkTp5Z1Q9Y8REgqMg1DpUBPleeqlRQcerBpM" +
|
|
291
|
+
"jiURHVD4XwAALhAgbxxlxYD5OFkG8oQRPB2EpsxSCNVlgcYUqoAyiVJmaARlkwplICfPoUy/zWEzM2pc" +
|
|
292
|
+
"NYzAQNJDSniEYecSEqxFEzQqEvUFGnvzwUfcRlpZ9T2LCR5QdDQDDhKICAjpJCagpRo9UQRPClZZlg6E" +
|
|
293
|
+
"p9DMTkTl+okuhRIVIzAQEf9L+Mx/DUjqmqN6kX7M36lS4zgLyJV3iV6j3xF8kJduJawVw1nndAlBaLLg" +
|
|
294
|
+
"JupwsTcLkxmJgFLgSzoCmHjSNGSqkGPCpnNqTXIwolf6qlVWN+q/su37HzgrES1pWGg3KnWh0FXCVniJ" +
|
|
295
|
+
"9K5b4iCrpLEuIcFTqwkVLFiqgaDqCCSMVWqxBAVCFOLVrVahm2ahUThUKJnmFCw15hD0Qhb/+5REEAhC" +
|
|
296
|
+
"YSRCSQEb4FOGaBUMI6JIRYC0QIB2SQsgGpgwDghgIlS6FU8VBXDoiBp5Y9gtkVnhEhYBdJFQ7kQ3w1yp" +
|
|
297
|
+
"0NB2CoNPEttZ1/aeDUAAA26FEghWgEKNVAVWkFAQEmMK2Uwk/qI0hqUb/4epVIZH1ai6szf6kzH1f2ar" +
|
|
298
|
+
"xYGS9FcOsN5UlJLQt///+oo0FRDTUQ0FBQr9f5LxXP+mEUfk0AIrf/5GRmQ0//mX//ZbLP5b5GrWSz+W" +
|
|
299
|
+
"SkZMrWyyyy2GRqyggVRyMv////////st//sn/yyVDI1l8mVgoYGDCOqiqIQBxmvxWCggTpZZZD//aWfy" +
|
|
300
|
+
"yWf/y/7KGDA0ssBggTof9k/+WS/8slQyMp/5Nfln8WAqGcUbULCrKxT9ISF+kKsxQWpMQU1FMy4xMDCq" +
|
|
301
|
+
"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq" +
|
|
302
|
+
"qqqqqqqqqqqqqqqqqqqqqqqqqqo=";
|
|
303
|
+
|
|
294
304
|
const audio = new Audio(hitmarkerDataUrl);
|
|
295
305
|
audio.volume = 0.3;
|
|
296
306
|
audio.play().catch(() => {
|
|
@@ -306,106 +316,109 @@ const LoadingScreen: React.FC<LoadingScreenProps> = ({ message = "Waiting for so
|
|
|
306
316
|
const createSyntheticHitmarkerSound = () => {
|
|
307
317
|
try {
|
|
308
318
|
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
|
|
309
|
-
|
|
319
|
+
|
|
310
320
|
// Create a more realistic hitmarker sound with noise and metallic ring
|
|
311
321
|
const oscillator1 = audioContext.createOscillator();
|
|
312
322
|
const oscillator2 = audioContext.createOscillator();
|
|
313
|
-
const noiseBuffer = audioContext.createBuffer(
|
|
323
|
+
const noiseBuffer = audioContext.createBuffer(
|
|
324
|
+
1,
|
|
325
|
+
audioContext.sampleRate * 0.1,
|
|
326
|
+
audioContext.sampleRate
|
|
327
|
+
);
|
|
314
328
|
const noiseSource = audioContext.createBufferSource();
|
|
315
|
-
|
|
329
|
+
|
|
316
330
|
// Generate white noise for the initial "crack"
|
|
317
331
|
const noiseData = noiseBuffer.getChannelData(0);
|
|
318
332
|
for (let i = 0; i < noiseData.length; i++) {
|
|
319
333
|
noiseData[i] = Math.random() * 2 - 1;
|
|
320
334
|
}
|
|
321
335
|
noiseSource.buffer = noiseBuffer;
|
|
322
|
-
|
|
336
|
+
|
|
323
337
|
const gainNode1 = audioContext.createGain();
|
|
324
338
|
const gainNode2 = audioContext.createGain();
|
|
325
339
|
const noiseGain = audioContext.createGain();
|
|
326
340
|
const masterGain = audioContext.createGain();
|
|
327
|
-
|
|
341
|
+
|
|
328
342
|
// Connect everything
|
|
329
343
|
oscillator1.connect(gainNode1);
|
|
330
344
|
oscillator2.connect(gainNode2);
|
|
331
345
|
noiseSource.connect(noiseGain);
|
|
332
|
-
|
|
346
|
+
|
|
333
347
|
gainNode1.connect(masterGain);
|
|
334
348
|
gainNode2.connect(masterGain);
|
|
335
349
|
noiseGain.connect(masterGain);
|
|
336
350
|
masterGain.connect(audioContext.destination);
|
|
337
|
-
|
|
351
|
+
|
|
338
352
|
// Sharp metallic frequencies
|
|
339
353
|
oscillator1.frequency.setValueAtTime(1800, audioContext.currentTime);
|
|
340
354
|
oscillator1.frequency.exponentialRampToValueAtTime(900, audioContext.currentTime + 0.08);
|
|
341
|
-
|
|
355
|
+
|
|
342
356
|
oscillator2.frequency.setValueAtTime(3600, audioContext.currentTime);
|
|
343
357
|
oscillator2.frequency.exponentialRampToValueAtTime(1800, audioContext.currentTime + 0.04);
|
|
344
|
-
|
|
345
|
-
oscillator1.type =
|
|
346
|
-
oscillator2.type =
|
|
347
|
-
|
|
358
|
+
|
|
359
|
+
oscillator1.type = "triangle";
|
|
360
|
+
oscillator2.type = "sine";
|
|
361
|
+
|
|
348
362
|
// Sharp attack, quick decay
|
|
349
363
|
gainNode1.gain.setValueAtTime(0, audioContext.currentTime);
|
|
350
364
|
gainNode1.gain.linearRampToValueAtTime(0.4, audioContext.currentTime + 0.002);
|
|
351
365
|
gainNode1.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.12);
|
|
352
|
-
|
|
366
|
+
|
|
353
367
|
gainNode2.gain.setValueAtTime(0, audioContext.currentTime);
|
|
354
368
|
gainNode2.gain.linearRampToValueAtTime(0.3, audioContext.currentTime + 0.001);
|
|
355
369
|
gainNode2.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.06);
|
|
356
|
-
|
|
370
|
+
|
|
357
371
|
// Noise burst for the initial crack
|
|
358
372
|
noiseGain.gain.setValueAtTime(0, audioContext.currentTime);
|
|
359
373
|
noiseGain.gain.linearRampToValueAtTime(0.2, audioContext.currentTime + 0.001);
|
|
360
374
|
noiseGain.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.01);
|
|
361
|
-
|
|
375
|
+
|
|
362
376
|
masterGain.gain.setValueAtTime(0.5, audioContext.currentTime);
|
|
363
|
-
|
|
377
|
+
|
|
364
378
|
const startTime = audioContext.currentTime;
|
|
365
379
|
const stopTime = startTime + 0.15;
|
|
366
|
-
|
|
380
|
+
|
|
367
381
|
oscillator1.start(startTime);
|
|
368
382
|
oscillator2.start(startTime);
|
|
369
383
|
noiseSource.start(startTime);
|
|
370
|
-
|
|
384
|
+
|
|
371
385
|
oscillator1.stop(stopTime);
|
|
372
386
|
oscillator2.stop(stopTime);
|
|
373
387
|
noiseSource.stop(startTime + 0.02);
|
|
374
|
-
|
|
375
388
|
} catch {
|
|
376
|
-
console.log(
|
|
389
|
+
console.log("Audio context not available");
|
|
377
390
|
}
|
|
378
391
|
};
|
|
379
392
|
|
|
380
393
|
const createHitmarker = (e: { clientX: number; clientY: number }) => {
|
|
381
394
|
if (!containerRef.current) return;
|
|
382
|
-
|
|
395
|
+
|
|
383
396
|
const rect = containerRef.current.getBoundingClientRect();
|
|
384
397
|
const x = e.clientX - rect.left;
|
|
385
398
|
const y = e.clientY - rect.top;
|
|
386
|
-
|
|
399
|
+
|
|
387
400
|
const newHitmarker: Hitmarker = {
|
|
388
401
|
id: Date.now() + Math.random(),
|
|
389
402
|
x,
|
|
390
403
|
y,
|
|
391
404
|
};
|
|
392
|
-
|
|
393
|
-
setHitmarkers(prev => [...prev, newHitmarker]);
|
|
394
|
-
|
|
405
|
+
|
|
406
|
+
setHitmarkers((prev) => [...prev, newHitmarker]);
|
|
407
|
+
|
|
395
408
|
// Play sound
|
|
396
409
|
playHitmarkerSound();
|
|
397
|
-
|
|
410
|
+
|
|
398
411
|
// Remove hitmarker after animation
|
|
399
412
|
setTimeout(() => {
|
|
400
|
-
setHitmarkers(prev => prev.filter(h => h.id !== newHitmarker.id));
|
|
413
|
+
setHitmarkers((prev) => prev.filter((h) => h.id !== newHitmarker.id));
|
|
401
414
|
}, 600);
|
|
402
415
|
};
|
|
403
416
|
|
|
404
417
|
// Inject CSS animations
|
|
405
418
|
useEffect(() => {
|
|
406
|
-
const styleId =
|
|
419
|
+
const styleId = "loading-screen-animations";
|
|
407
420
|
if (!document.getElementById(styleId)) {
|
|
408
|
-
const style = document.createElement(
|
|
421
|
+
const style = document.createElement("style");
|
|
409
422
|
style.id = styleId;
|
|
410
423
|
style.textContent = `
|
|
411
424
|
@keyframes fadeInOut {
|
|
@@ -516,12 +529,13 @@ const LoadingScreen: React.FC<LoadingScreenProps> = ({ message = "Waiting for so
|
|
|
516
529
|
<div
|
|
517
530
|
ref={containerRef}
|
|
518
531
|
className="fw-player-root"
|
|
519
|
-
style={
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
532
|
+
style={
|
|
533
|
+
{
|
|
534
|
+
position: "relative",
|
|
535
|
+
width: "100%",
|
|
536
|
+
height: "100%",
|
|
537
|
+
minHeight: "300px",
|
|
538
|
+
background: `
|
|
525
539
|
linear-gradient(135deg,
|
|
526
540
|
hsl(var(--tn-bg-dark, 235 21% 11%)) 0%,
|
|
527
541
|
hsl(var(--tn-bg, 233 23% 17%)) 25%,
|
|
@@ -530,22 +544,23 @@ const LoadingScreen: React.FC<LoadingScreenProps> = ({ message = "Waiting for so
|
|
|
530
544
|
hsl(var(--tn-bg-dark, 235 21% 11%)) 100%
|
|
531
545
|
)
|
|
532
546
|
`,
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
547
|
+
backgroundSize: "400% 400%",
|
|
548
|
+
animation: "gradientShift 16s ease-in-out infinite",
|
|
549
|
+
display: "flex",
|
|
550
|
+
flexDirection: "column",
|
|
551
|
+
alignItems: "center",
|
|
552
|
+
justifyContent: "center",
|
|
553
|
+
overflow: "hidden",
|
|
554
|
+
borderRadius: "0" /* Slab - no rounded corners */,
|
|
555
|
+
userSelect: "none",
|
|
556
|
+
WebkitUserSelect: "none",
|
|
557
|
+
MozUserSelect: "none",
|
|
558
|
+
msUserSelect: "none",
|
|
559
|
+
} as React.CSSProperties
|
|
560
|
+
}
|
|
546
561
|
>
|
|
547
562
|
{/* Hitmarkers */}
|
|
548
|
-
{hitmarkers.map(hitmarker => (
|
|
563
|
+
{hitmarkers.map((hitmarker) => (
|
|
549
564
|
<div
|
|
550
565
|
key={hitmarker.id}
|
|
551
566
|
style={{
|
|
@@ -634,7 +649,7 @@ const LoadingScreen: React.FC<LoadingScreenProps> = ({ message = "Waiting for so
|
|
|
634
649
|
borderRadius: "50%",
|
|
635
650
|
background: [
|
|
636
651
|
"#7aa2f7", // Terminal Blue
|
|
637
|
-
"#bb9af7", // Terminal Magenta
|
|
652
|
+
"#bb9af7", // Terminal Magenta
|
|
638
653
|
"#9ece6a", // Strings/CSS classes
|
|
639
654
|
"#73daca", // Terminal Green
|
|
640
655
|
"#7dcfff", // Terminal Cyan
|
|
@@ -657,7 +672,10 @@ const LoadingScreen: React.FC<LoadingScreenProps> = ({ message = "Waiting for so
|
|
|
657
672
|
))}
|
|
658
673
|
|
|
659
674
|
{/* Center logo */}
|
|
660
|
-
<CenterLogo
|
|
675
|
+
<CenterLogo
|
|
676
|
+
containerRef={containerRef as React.RefObject<HTMLDivElement>}
|
|
677
|
+
onHitmarker={createHitmarker}
|
|
678
|
+
/>
|
|
661
679
|
|
|
662
680
|
{/* Bouncing DVD Logo */}
|
|
663
681
|
<DvdLogo parentRef={containerRef as React.RefObject<HTMLDivElement>} scale={0.08} />
|
|
@@ -707,4 +725,4 @@ const LoadingScreen: React.FC<LoadingScreenProps> = ({ message = "Waiting for so
|
|
|
707
725
|
);
|
|
708
726
|
};
|
|
709
727
|
|
|
710
|
-
export default LoadingScreen;
|
|
728
|
+
export default LoadingScreen;
|
|
@@ -10,14 +10,11 @@ interface LogoOverlayProps {
|
|
|
10
10
|
clickUrl?: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const POSITION_MAP: Record<
|
|
14
|
-
NonNullable<LogoOverlayProps["position"]>,
|
|
15
|
-
string
|
|
16
|
-
> = {
|
|
13
|
+
const POSITION_MAP: Record<NonNullable<LogoOverlayProps["position"]>, string> = {
|
|
17
14
|
"top-left": "left-3 top-3 sm:left-4 sm:top-4",
|
|
18
15
|
"top-right": "right-3 top-3 sm:right-4 sm:top-4",
|
|
19
16
|
"bottom-left": "left-3 bottom-3 sm:left-4 sm:bottom-4",
|
|
20
|
-
"bottom-right": "right-3 bottom-3 sm:right-4 sm:bottom-4"
|
|
17
|
+
"bottom-right": "right-3 bottom-3 sm:right-4 sm:bottom-4",
|
|
21
18
|
};
|
|
22
19
|
|
|
23
20
|
const LogoOverlay: React.FC<LogoOverlayProps> = ({
|
|
@@ -26,7 +23,7 @@ const LogoOverlay: React.FC<LogoOverlayProps> = ({
|
|
|
26
23
|
position = "bottom-right",
|
|
27
24
|
width = 96,
|
|
28
25
|
height = "auto",
|
|
29
|
-
clickUrl
|
|
26
|
+
clickUrl,
|
|
30
27
|
}) => {
|
|
31
28
|
if (!show) return null;
|
|
32
29
|
|