@godscene/visualizer 1.7.11

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.
Files changed (221) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -0
  3. package/dist/es/component/blackboard/highlights.mjs +47 -0
  4. package/dist/es/component/blackboard/index.css +118 -0
  5. package/dist/es/component/blackboard/index.mjs +122 -0
  6. package/dist/es/component/config-selector/index.mjs +251 -0
  7. package/dist/es/component/context-preview/index.mjs +37 -0
  8. package/dist/es/component/env-config/index.mjs +237 -0
  9. package/dist/es/component/env-config-reminder/index.css +30 -0
  10. package/dist/es/component/env-config-reminder/index.mjs +27 -0
  11. package/dist/es/component/form-field/index.mjs +158 -0
  12. package/dist/es/component/history-selector/index.css +237 -0
  13. package/dist/es/component/history-selector/index.mjs +197 -0
  14. package/dist/es/component/index.mjs +1 -0
  15. package/dist/es/component/logo/index.css +19 -0
  16. package/dist/es/component/logo/index.mjs +20 -0
  17. package/dist/es/component/logo/logo.mjs +2 -0
  18. package/dist/es/component/misc/index.mjs +96 -0
  19. package/dist/es/component/nav-actions/index.mjs +14 -0
  20. package/dist/es/component/nav-actions/style.css +35 -0
  21. package/dist/es/component/player/index.css +296 -0
  22. package/dist/es/component/player/index.mjs +702 -0
  23. package/dist/es/component/player/playback-controls.mjs +4 -0
  24. package/dist/es/component/player/report-download.mjs +61 -0
  25. package/dist/es/component/player/scenes/StepScene.mjs +194 -0
  26. package/dist/es/component/player/scenes/derive-frame-state.mjs +229 -0
  27. package/dist/es/component/player/scenes/export-branded-video.mjs +360 -0
  28. package/dist/es/component/player/scenes/frame-calculator.mjs +149 -0
  29. package/dist/es/component/player/scenes/playback-frame.mjs +6 -0
  30. package/dist/es/component/player/scenes/playback-layout.mjs +12 -0
  31. package/dist/es/component/player/scenes/pointer-layout.mjs +36 -0
  32. package/dist/es/component/player/use-frame-player.mjs +87 -0
  33. package/dist/es/component/playground/index.css +930 -0
  34. package/dist/es/component/playground/playground-demo-ui-context.json +290 -0
  35. package/dist/es/component/playground-result/index.css +92 -0
  36. package/dist/es/component/playground-result/index.mjs +232 -0
  37. package/dist/es/component/prompt-input/index.css +832 -0
  38. package/dist/es/component/prompt-input/index.mjs +959 -0
  39. package/dist/es/component/screenshot-viewer/index.css +237 -0
  40. package/dist/es/component/screenshot-viewer/index.mjs +319 -0
  41. package/dist/es/component/service-mode-control/index.mjs +107 -0
  42. package/dist/es/component/shiny-text/index.css +107 -0
  43. package/dist/es/component/shiny-text/index.mjs +15 -0
  44. package/dist/es/component/universal-playground/empty-state.mjs +5 -0
  45. package/dist/es/component/universal-playground/index.css +619 -0
  46. package/dist/es/component/universal-playground/index.mjs +558 -0
  47. package/dist/es/component/universal-playground/providers/context-provider.mjs +90 -0
  48. package/dist/es/component/universal-playground/providers/indexeddb-storage-provider.mjs +280 -0
  49. package/dist/es/component/universal-playground/providers/storage-provider.mjs +279 -0
  50. package/dist/es/component/universal-playground/universal-playground-electron.mjs +668 -0
  51. package/dist/es/hooks/useMinimalTypeGate.mjs +47 -0
  52. package/dist/es/hooks/usePlaygroundExecution.mjs +435 -0
  53. package/dist/es/hooks/usePlaygroundState.mjs +278 -0
  54. package/dist/es/hooks/useSafeOverrideAIConfig.mjs +20 -0
  55. package/dist/es/hooks/useServerValid.mjs +55 -0
  56. package/dist/es/hooks/useTheme.mjs +25 -0
  57. package/dist/es/icons/action-chevron.mjs +61 -0
  58. package/dist/es/icons/avatar.mjs +70 -0
  59. package/dist/es/icons/close.mjs +61 -0
  60. package/dist/es/icons/global-perspective.mjs +58 -0
  61. package/dist/es/icons/history.mjs +72 -0
  62. package/dist/es/icons/magnifying-glass.mjs +81 -0
  63. package/dist/es/icons/player-setting.mjs +68 -0
  64. package/dist/es/icons/prompt-history.mjs +70 -0
  65. package/dist/es/icons/setting.mjs +62 -0
  66. package/dist/es/icons/show-marker.mjs +58 -0
  67. package/dist/es/index.mjs +26 -0
  68. package/dist/es/static/image/logo.png +0 -0
  69. package/dist/es/store/history.mjs +128 -0
  70. package/dist/es/store/store.mjs +277 -0
  71. package/dist/es/types.mjs +73 -0
  72. package/dist/es/utils/action-label.mjs +15 -0
  73. package/dist/es/utils/color.mjs +35 -0
  74. package/dist/es/utils/constants.mjs +99 -0
  75. package/dist/es/utils/device-capabilities.mjs +13 -0
  76. package/dist/es/utils/empty-state-scroll.mjs +8 -0
  77. package/dist/es/utils/highlight-element.mjs +62 -0
  78. package/dist/es/utils/index.mjs +13 -0
  79. package/dist/es/utils/playground-utils.mjs +43 -0
  80. package/dist/es/utils/progress-action-icon.mjs +30 -0
  81. package/dist/es/utils/prompt-input-utils.mjs +49 -0
  82. package/dist/es/utils/prompt-placeholder.mjs +19 -0
  83. package/dist/es/utils/replay-scripts.mjs +428 -0
  84. package/dist/lib/component/blackboard/highlights.js +84 -0
  85. package/dist/lib/component/blackboard/index.css +118 -0
  86. package/dist/lib/component/blackboard/index.js +169 -0
  87. package/dist/lib/component/config-selector/index.js +295 -0
  88. package/dist/lib/component/context-preview/index.js +82 -0
  89. package/dist/lib/component/env-config/index.js +271 -0
  90. package/dist/lib/component/env-config-reminder/index.css +30 -0
  91. package/dist/lib/component/env-config-reminder/index.js +61 -0
  92. package/dist/lib/component/form-field/index.js +204 -0
  93. package/dist/lib/component/history-selector/index.css +237 -0
  94. package/dist/lib/component/history-selector/index.js +243 -0
  95. package/dist/lib/component/index.js +58 -0
  96. package/dist/lib/component/logo/index.css +19 -0
  97. package/dist/lib/component/logo/index.js +67 -0
  98. package/dist/lib/component/logo/logo.js +24 -0
  99. package/dist/lib/component/misc/index.js +152 -0
  100. package/dist/lib/component/nav-actions/index.js +48 -0
  101. package/dist/lib/component/nav-actions/style.css +35 -0
  102. package/dist/lib/component/player/index.css +296 -0
  103. package/dist/lib/component/player/index.js +747 -0
  104. package/dist/lib/component/player/playback-controls.js +38 -0
  105. package/dist/lib/component/player/report-download.js +98 -0
  106. package/dist/lib/component/player/scenes/StepScene.js +228 -0
  107. package/dist/lib/component/player/scenes/derive-frame-state.js +266 -0
  108. package/dist/lib/component/player/scenes/export-branded-video.js +403 -0
  109. package/dist/lib/component/player/scenes/frame-calculator.js +186 -0
  110. package/dist/lib/component/player/scenes/playback-frame.js +40 -0
  111. package/dist/lib/component/player/scenes/playback-layout.js +46 -0
  112. package/dist/lib/component/player/scenes/pointer-layout.js +88 -0
  113. package/dist/lib/component/player/use-frame-player.js +121 -0
  114. package/dist/lib/component/playground/index.css +930 -0
  115. package/dist/lib/component/playground/playground-demo-ui-context.json +290 -0
  116. package/dist/lib/component/playground-result/index.css +92 -0
  117. package/dist/lib/component/playground-result/index.js +276 -0
  118. package/dist/lib/component/prompt-input/index.css +832 -0
  119. package/dist/lib/component/prompt-input/index.js +1005 -0
  120. package/dist/lib/component/screenshot-viewer/index.css +237 -0
  121. package/dist/lib/component/screenshot-viewer/index.js +353 -0
  122. package/dist/lib/component/service-mode-control/index.js +141 -0
  123. package/dist/lib/component/shiny-text/index.css +107 -0
  124. package/dist/lib/component/shiny-text/index.js +49 -0
  125. package/dist/lib/component/universal-playground/empty-state.js +39 -0
  126. package/dist/lib/component/universal-playground/index.css +619 -0
  127. package/dist/lib/component/universal-playground/index.js +607 -0
  128. package/dist/lib/component/universal-playground/providers/context-provider.js +133 -0
  129. package/dist/lib/component/universal-playground/providers/indexeddb-storage-provider.js +320 -0
  130. package/dist/lib/component/universal-playground/providers/storage-provider.js +337 -0
  131. package/dist/lib/component/universal-playground/universal-playground-electron.js +717 -0
  132. package/dist/lib/hooks/useMinimalTypeGate.js +81 -0
  133. package/dist/lib/hooks/usePlaygroundExecution.js +478 -0
  134. package/dist/lib/hooks/usePlaygroundState.js +312 -0
  135. package/dist/lib/hooks/useSafeOverrideAIConfig.js +57 -0
  136. package/dist/lib/hooks/useServerValid.js +89 -0
  137. package/dist/lib/hooks/useTheme.js +59 -0
  138. package/dist/lib/icons/action-chevron.js +95 -0
  139. package/dist/lib/icons/avatar.js +104 -0
  140. package/dist/lib/icons/close.js +95 -0
  141. package/dist/lib/icons/global-perspective.js +92 -0
  142. package/dist/lib/icons/history.js +106 -0
  143. package/dist/lib/icons/magnifying-glass.js +115 -0
  144. package/dist/lib/icons/player-setting.js +102 -0
  145. package/dist/lib/icons/prompt-history.js +104 -0
  146. package/dist/lib/icons/setting.js +96 -0
  147. package/dist/lib/icons/show-marker.js +92 -0
  148. package/dist/lib/index.js +204 -0
  149. package/dist/lib/static/image/logo.png +0 -0
  150. package/dist/lib/store/history.js +135 -0
  151. package/dist/lib/store/store.js +287 -0
  152. package/dist/lib/types.js +119 -0
  153. package/dist/lib/utils/action-label.js +52 -0
  154. package/dist/lib/utils/color.js +75 -0
  155. package/dist/lib/utils/constants.js +172 -0
  156. package/dist/lib/utils/device-capabilities.js +50 -0
  157. package/dist/lib/utils/empty-state-scroll.js +42 -0
  158. package/dist/lib/utils/highlight-element.js +99 -0
  159. package/dist/lib/utils/index.js +69 -0
  160. package/dist/lib/utils/playground-utils.js +86 -0
  161. package/dist/lib/utils/progress-action-icon.js +67 -0
  162. package/dist/lib/utils/prompt-input-utils.js +89 -0
  163. package/dist/lib/utils/prompt-placeholder.js +53 -0
  164. package/dist/lib/utils/replay-scripts.js +474 -0
  165. package/dist/types/component/blackboard/highlights.d.ts +11 -0
  166. package/dist/types/component/blackboard/index.d.ts +10 -0
  167. package/dist/types/component/config-selector/index.d.ts +15 -0
  168. package/dist/types/component/context-preview/index.d.ts +9 -0
  169. package/dist/types/component/env-config/index.d.ts +8 -0
  170. package/dist/types/component/env-config-reminder/index.d.ts +6 -0
  171. package/dist/types/component/form-field/index.d.ts +17 -0
  172. package/dist/types/component/history-selector/index.d.ts +13 -0
  173. package/dist/types/component/index.d.ts +1 -0
  174. package/dist/types/component/logo/index.d.ts +5 -0
  175. package/dist/types/component/misc/index.d.ts +6 -0
  176. package/dist/types/component/nav-actions/index.d.ts +12 -0
  177. package/dist/types/component/player/index.d.ts +15 -0
  178. package/dist/types/component/player/playback-controls.d.ts +1 -0
  179. package/dist/types/component/player/report-download.d.ts +32 -0
  180. package/dist/types/component/player/scenes/StepScene.d.ts +9 -0
  181. package/dist/types/component/player/scenes/derive-frame-state.d.ts +40 -0
  182. package/dist/types/component/player/scenes/export-branded-video.d.ts +33 -0
  183. package/dist/types/component/player/scenes/frame-calculator.d.ts +40 -0
  184. package/dist/types/component/player/scenes/playback-frame.d.ts +3 -0
  185. package/dist/types/component/player/scenes/playback-layout.d.ts +7 -0
  186. package/dist/types/component/player/scenes/pointer-layout.d.ts +20 -0
  187. package/dist/types/component/player/use-frame-player.d.ts +17 -0
  188. package/dist/types/component/playground-result/index.d.ts +22 -0
  189. package/dist/types/component/prompt-input/index.d.ts +23 -0
  190. package/dist/types/component/screenshot-viewer/index.d.ts +23 -0
  191. package/dist/types/component/service-mode-control/index.d.ts +6 -0
  192. package/dist/types/component/shiny-text/index.d.ts +12 -0
  193. package/dist/types/component/universal-playground/empty-state.d.ts +3 -0
  194. package/dist/types/component/universal-playground/index.d.ts +4 -0
  195. package/dist/types/component/universal-playground/providers/context-provider.d.ts +37 -0
  196. package/dist/types/component/universal-playground/providers/indexeddb-storage-provider.d.ts +71 -0
  197. package/dist/types/component/universal-playground/providers/storage-provider.d.ts +58 -0
  198. package/dist/types/component/universal-playground/universal-playground-electron.d.ts +4 -0
  199. package/dist/types/hooks/useMinimalTypeGate.d.ts +72 -0
  200. package/dist/types/hooks/usePlaygroundExecution.d.ts +40 -0
  201. package/dist/types/hooks/usePlaygroundState.d.ts +26 -0
  202. package/dist/types/hooks/useSafeOverrideAIConfig.d.ts +16 -0
  203. package/dist/types/hooks/useServerValid.d.ts +1 -0
  204. package/dist/types/hooks/useTheme.d.ts +7 -0
  205. package/dist/types/index.d.ts +29 -0
  206. package/dist/types/store/history.d.ts +16 -0
  207. package/dist/types/store/store.d.ts +57 -0
  208. package/dist/types/types.d.ts +278 -0
  209. package/dist/types/utils/action-label.d.ts +11 -0
  210. package/dist/types/utils/color.d.ts +4 -0
  211. package/dist/types/utils/constants.d.ts +80 -0
  212. package/dist/types/utils/device-capabilities.d.ts +9 -0
  213. package/dist/types/utils/empty-state-scroll.d.ts +11 -0
  214. package/dist/types/utils/highlight-element.d.ts +3 -0
  215. package/dist/types/utils/index.d.ts +5 -0
  216. package/dist/types/utils/playground-utils.d.ts +11 -0
  217. package/dist/types/utils/progress-action-icon.d.ts +12 -0
  218. package/dist/types/utils/prompt-input-utils.d.ts +24 -0
  219. package/dist/types/utils/prompt-placeholder.d.ts +1 -0
  220. package/dist/types/utils/replay-scripts.d.ts +50 -0
  221. package/package.json +82 -0
@@ -0,0 +1,702 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
+ import "./index.css";
5
+ import { CaretRightOutlined, DownloadOutlined, ExportOutlined, FontSizeOutlined, PauseOutlined, ThunderboltOutlined } from "@ant-design/icons";
6
+ import { Button, Dropdown, Progress, Switch, Tooltip, message } from "antd";
7
+ import global_perspective from "../../icons/global-perspective.mjs";
8
+ import player_setting from "../../icons/player-setting.mjs";
9
+ import { useGlobalPreference } from "../../store/store.mjs";
10
+ import { shouldRestartPlaybackFromBeginning } from "./playback-controls.mjs";
11
+ import { triggerReportDownload } from "./report-download.mjs";
12
+ import { StepsTimeline } from "./scenes/StepScene.mjs";
13
+ import { exportBrandedVideo } from "./scenes/export-branded-video.mjs";
14
+ import { calculateFrameMap } from "./scenes/frame-calculator.mjs";
15
+ import { getPlaybackFrameState } from "./scenes/playback-frame.mjs";
16
+ import { useFramePlayer } from "./use-frame-player.mjs";
17
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
18
+ try {
19
+ var info = gen[key](arg);
20
+ var value = info.value;
21
+ } catch (error) {
22
+ reject(error);
23
+ return;
24
+ }
25
+ if (info.done) resolve(value);
26
+ else Promise.resolve(value).then(_next, _throw);
27
+ }
28
+ function _async_to_generator(fn) {
29
+ return function() {
30
+ var self = this, args = arguments;
31
+ return new Promise(function(resolve, reject) {
32
+ var gen = fn.apply(self, args);
33
+ function _next(value) {
34
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
35
+ }
36
+ function _throw(err) {
37
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
38
+ }
39
+ _next(void 0);
40
+ });
41
+ };
42
+ }
43
+ function deriveTaskId(scriptFrames, stepsFrame) {
44
+ let taskId = null;
45
+ for (const sf of scriptFrames){
46
+ var _sf_taskId;
47
+ if (0 === sf.durationInFrames) {
48
+ if (sf.startFrame <= stepsFrame) {
49
+ var _sf_taskId1;
50
+ taskId = null != (_sf_taskId1 = sf.taskId) ? _sf_taskId1 : taskId;
51
+ }
52
+ continue;
53
+ }
54
+ if (stepsFrame < sf.startFrame) break;
55
+ taskId = null != (_sf_taskId = sf.taskId) ? _sf_taskId : taskId;
56
+ }
57
+ return taskId;
58
+ }
59
+ function formatTime(frame, fps) {
60
+ const totalSeconds = Math.floor(frame / fps);
61
+ const m = Math.floor(totalSeconds / 60);
62
+ const s = totalSeconds % 60;
63
+ return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
64
+ }
65
+ function Player(props) {
66
+ var _ref, _ref1, _ref2;
67
+ const { autoZoom, setAutoZoom, playbackSpeed, setPlaybackSpeed, subtitleEnabled, setSubtitleEnabled } = useGlobalPreference();
68
+ useEffect(()=>{
69
+ if ((null == props ? void 0 : props.autoZoom) !== void 0) setAutoZoom(props.autoZoom);
70
+ }, [
71
+ null == props ? void 0 : props.autoZoom,
72
+ setAutoZoom
73
+ ]);
74
+ const scripts = null == props ? void 0 : props.replayScripts;
75
+ const frameMap = useMemo(()=>{
76
+ if (!scripts || 0 === scripts.length) return null;
77
+ return calculateFrameMap(scripts, {
78
+ imageWidth: null == props ? void 0 : props.imageWidth,
79
+ imageHeight: null == props ? void 0 : props.imageHeight
80
+ });
81
+ }, [
82
+ null == props ? void 0 : props.imageHeight,
83
+ null == props ? void 0 : props.imageWidth,
84
+ scripts
85
+ ]);
86
+ const containerRef = useRef(null);
87
+ const renderLayerRef = useRef(null);
88
+ const lastTaskIdRef = useRef(null);
89
+ const [containerSize, setContainerSize] = useState({
90
+ width: 0,
91
+ height: 0
92
+ });
93
+ useEffect(()=>{
94
+ const el = renderLayerRef.current;
95
+ if (!el) return;
96
+ const ro = new ResizeObserver((entries)=>{
97
+ for (const entry of entries){
98
+ const { width, height } = entry.contentRect;
99
+ setContainerSize((prev)=>prev.width === width && prev.height === height ? prev : {
100
+ width,
101
+ height
102
+ });
103
+ }
104
+ });
105
+ ro.observe(el);
106
+ return ()=>ro.disconnect();
107
+ }, []);
108
+ const player = useFramePlayer({
109
+ durationInFrames: Math.max(null != (_ref = null == frameMap ? void 0 : frameMap.totalDurationInFrames) ? _ref : 1, 1),
110
+ fps: null != (_ref1 = null == frameMap ? void 0 : frameMap.fps) ? _ref1 : 30,
111
+ autoPlay: false,
112
+ loop: false,
113
+ playbackRate: playbackSpeed
114
+ });
115
+ const effectiveEndFrame = useMemo(()=>{
116
+ if (!frameMap) return 0;
117
+ for(let i = frameMap.scriptFrames.length - 1; i >= 0; i--){
118
+ const sf = frameMap.scriptFrames[i];
119
+ if (sf.taskId) return sf.startFrame + sf.durationInFrames - 1;
120
+ }
121
+ return Math.max(0, frameMap.totalDurationInFrames - 1);
122
+ }, [
123
+ frameMap
124
+ ]);
125
+ const handlePlaybackToggle = useCallback(()=>{
126
+ if (player.playing) return void player.pause();
127
+ if (shouldRestartPlaybackFromBeginning(player.currentFrame, effectiveEndFrame)) player.seekTo(0);
128
+ player.play();
129
+ }, [
130
+ effectiveEndFrame,
131
+ player.currentFrame,
132
+ player.pause,
133
+ player.play,
134
+ player.playing,
135
+ player.seekTo
136
+ ]);
137
+ useEffect(()=>{
138
+ if (!frameMap || player.playing) return;
139
+ if (player.currentFrame < frameMap.totalDurationInFrames - 1) return;
140
+ if (effectiveEndFrame > 0) player.seekTo(effectiveEndFrame);
141
+ }, [
142
+ effectiveEndFrame,
143
+ frameMap,
144
+ player.currentFrame,
145
+ player.playing,
146
+ player.seekTo
147
+ ]);
148
+ useEffect(()=>{
149
+ if (!frameMap || !(null == props ? void 0 : props.onTaskChange)) return;
150
+ if (!player.playing) {
151
+ if (null !== lastTaskIdRef.current) {
152
+ lastTaskIdRef.current = null;
153
+ props.onTaskChange(null);
154
+ }
155
+ return;
156
+ }
157
+ const taskId = deriveTaskId(frameMap.scriptFrames, player.currentFrame);
158
+ if (taskId !== lastTaskIdRef.current) {
159
+ lastTaskIdRef.current = taskId;
160
+ props.onTaskChange(taskId);
161
+ }
162
+ }, [
163
+ frameMap,
164
+ null == props ? void 0 : props.onTaskChange,
165
+ player.currentFrame,
166
+ player.playing
167
+ ]);
168
+ const currentFrameState = useMemo(()=>{
169
+ if (!frameMap) return null;
170
+ return getPlaybackFrameState(frameMap, player.currentFrame);
171
+ }, [
172
+ frameMap,
173
+ player.currentFrame
174
+ ]);
175
+ const handleDownloadReport = useCallback(()=>_async_to_generator(function*() {
176
+ if (!(null == props ? void 0 : props.reportFileContent)) return;
177
+ try {
178
+ yield triggerReportDownload({
179
+ content: props.reportFileContent,
180
+ onDownloadReport: props.onDownloadReport
181
+ });
182
+ } catch (error) {
183
+ const errorMessage = error instanceof Error ? error.message : String(error);
184
+ message.error(`Failed to download report: ${errorMessage}`);
185
+ }
186
+ })(), [
187
+ null == props ? void 0 : props.onDownloadReport,
188
+ null == props ? void 0 : props.reportFileContent
189
+ ]);
190
+ const subtitle = useMemo(()=>{
191
+ if (!currentFrameState) return null;
192
+ if (!currentFrameState.title && !currentFrameState.subTitle) return null;
193
+ return {
194
+ title: currentFrameState.title,
195
+ subTitle: currentFrameState.subTitle
196
+ };
197
+ }, [
198
+ currentFrameState
199
+ ]);
200
+ const [isExporting, setIsExporting] = useState(false);
201
+ const [exportProgress, setExportProgress] = useState(0);
202
+ const exportInFlightRef = useRef(false);
203
+ const [controlsVisible, setControlsVisible] = useState(true);
204
+ const hideTimerRef = useRef(null);
205
+ const showControls = useCallback(()=>{
206
+ setControlsVisible(true);
207
+ if (hideTimerRef.current) clearTimeout(hideTimerRef.current);
208
+ if (isExporting) return;
209
+ hideTimerRef.current = setTimeout(()=>setControlsVisible(false), 3000);
210
+ }, [
211
+ isExporting
212
+ ]);
213
+ const onMouseEnter = useCallback(()=>{
214
+ setControlsVisible(true);
215
+ if (hideTimerRef.current) clearTimeout(hideTimerRef.current);
216
+ }, []);
217
+ const onMouseLeave = useCallback(()=>{
218
+ if (hideTimerRef.current) clearTimeout(hideTimerRef.current);
219
+ if (isExporting) return;
220
+ hideTimerRef.current = setTimeout(()=>setControlsVisible(false), 1000);
221
+ }, [
222
+ isExporting
223
+ ]);
224
+ useEffect(()=>{
225
+ if (!isExporting) return;
226
+ setControlsVisible(true);
227
+ if (hideTimerRef.current) {
228
+ clearTimeout(hideTimerRef.current);
229
+ hideTimerRef.current = null;
230
+ }
231
+ }, [
232
+ isExporting
233
+ ]);
234
+ useEffect(()=>{
235
+ const handleKeyDown = (e)=>{
236
+ var _e_target;
237
+ const tag = null == (_e_target = e.target) ? void 0 : _e_target.tagName;
238
+ if ('INPUT' === tag || 'TEXTAREA' === tag || 'SELECT' === tag) return;
239
+ if ('Space' === e.code) {
240
+ e.preventDefault();
241
+ handlePlaybackToggle();
242
+ }
243
+ };
244
+ document.addEventListener('keydown', handleKeyDown);
245
+ return ()=>document.removeEventListener('keydown', handleKeyDown);
246
+ }, [
247
+ handlePlaybackToggle
248
+ ]);
249
+ const seekBarRef = useRef(null);
250
+ const handleSeekPointerDown = useCallback((e)=>{
251
+ if (!frameMap || !seekBarRef.current) return;
252
+ const bar = seekBarRef.current;
253
+ bar.setPointerCapture(e.pointerId);
254
+ const seek = (clientX)=>{
255
+ const rect = bar.getBoundingClientRect();
256
+ const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
257
+ player.seekTo(Math.round(ratio * effectiveEndFrame));
258
+ };
259
+ seek(e.clientX);
260
+ const onMove = (ev)=>seek(ev.clientX);
261
+ const onUp = ()=>{
262
+ bar.removeEventListener('pointermove', onMove);
263
+ bar.removeEventListener('pointerup', onUp);
264
+ };
265
+ bar.addEventListener('pointermove', onMove);
266
+ bar.addEventListener('pointerup', onUp);
267
+ }, [
268
+ frameMap,
269
+ player,
270
+ effectiveEndFrame
271
+ ]);
272
+ const [isFullscreen, setIsFullscreen] = useState(false);
273
+ useCallback(()=>{
274
+ const el = containerRef.current;
275
+ if (!el) return;
276
+ if (document.fullscreenElement) document.exitFullscreen().then(()=>setIsFullscreen(false));
277
+ else el.requestFullscreen().then(()=>setIsFullscreen(true));
278
+ }, []);
279
+ useEffect(()=>{
280
+ const handler = ()=>setIsFullscreen(!!document.fullscreenElement);
281
+ document.addEventListener('fullscreenchange', handler);
282
+ return ()=>document.removeEventListener('fullscreenchange', handler);
283
+ }, []);
284
+ const handleExportVideo = useCallback(()=>_async_to_generator(function*() {
285
+ if (!frameMap || exportInFlightRef.current) return;
286
+ exportInFlightRef.current = true;
287
+ setIsExporting(true);
288
+ setExportProgress(0);
289
+ try {
290
+ yield exportBrandedVideo(frameMap, {
291
+ autoZoom
292
+ }, (pct)=>setExportProgress(Math.round(100 * pct)));
293
+ message.success('Video exported');
294
+ } catch (e) {
295
+ console.error('Export failed:', e);
296
+ const errorMessage = e instanceof Error ? e.message : 'Export failed';
297
+ message.error(errorMessage);
298
+ } finally{
299
+ exportInFlightRef.current = false;
300
+ setIsExporting(false);
301
+ setExportProgress(0);
302
+ }
303
+ })(), [
304
+ autoZoom,
305
+ frameMap
306
+ ]);
307
+ const chapterMarkers = useMemo(()=>{
308
+ if (!frameMap || effectiveEndFrame <= 0) return [];
309
+ const markers = [];
310
+ for (const sf of frameMap.scriptFrames){
311
+ if ('img' !== sf.type && 'insight' !== sf.type || 0 === sf.durationInFrames) continue;
312
+ const globalFrame = sf.startFrame;
313
+ const percent = globalFrame / effectiveEndFrame * 100;
314
+ if (percent > 1 && percent < 99) {
315
+ const parts = [
316
+ sf.title,
317
+ sf.subTitle
318
+ ].filter(Boolean);
319
+ markers.push({
320
+ percent,
321
+ title: parts.length > 0 ? parts.join(': ') : `Chapter ${markers.length + 1}`,
322
+ frame: globalFrame
323
+ });
324
+ }
325
+ }
326
+ return markers;
327
+ }, [
328
+ frameMap,
329
+ effectiveEndFrame
330
+ ]);
331
+ const reportFileContent = null != (_ref2 = null == props ? void 0 : props.reportFileContent) ? _ref2 : null;
332
+ const canDownloadReport = (null == props ? void 0 : props.canDownloadReport) !== false;
333
+ if (!scripts || 0 === scripts.length || !frameMap) {
334
+ if (reportFileContent && canDownloadReport) return /*#__PURE__*/ jsx("div", {
335
+ className: "player-container player-container-empty",
336
+ children: /*#__PURE__*/ jsxs("div", {
337
+ className: "player-empty-state",
338
+ children: [
339
+ /*#__PURE__*/ jsx("span", {
340
+ className: "player-empty-text",
341
+ children: "No replay available"
342
+ }),
343
+ /*#__PURE__*/ jsx(Button, {
344
+ icon: /*#__PURE__*/ jsx(DownloadOutlined, {}),
345
+ onClick: ()=>{
346
+ handleDownloadReport();
347
+ },
348
+ children: "Download report"
349
+ })
350
+ ]
351
+ })
352
+ });
353
+ return null;
354
+ }
355
+ const compositionWidth = (null == currentFrameState ? void 0 : currentFrameState.imageWidth) || frameMap.imageWidth;
356
+ const compositionHeight = (null == currentFrameState ? void 0 : currentFrameState.imageHeight) || frameMap.imageHeight;
357
+ const isPortraitCanvas = compositionHeight > compositionWidth;
358
+ const seekPercent = effectiveEndFrame > 0 ? Math.min(100, player.currentFrame / effectiveEndFrame * 100) : 0;
359
+ return /*#__PURE__*/ jsx("div", {
360
+ className: "player-container",
361
+ "data-fit-mode": null == props ? void 0 : props.fitMode,
362
+ children: /*#__PURE__*/ jsxs("div", {
363
+ className: "canvas-container",
364
+ ref: containerRef,
365
+ onMouseMove: showControls,
366
+ onMouseEnter: onMouseEnter,
367
+ onMouseLeave: onMouseLeave,
368
+ children: [
369
+ /*#__PURE__*/ jsx("div", {
370
+ className: "player-wrapper",
371
+ "data-portrait": isPortraitCanvas ? '' : void 0,
372
+ style: {
373
+ aspectRatio: `${compositionWidth}/${compositionHeight}`
374
+ },
375
+ children: /*#__PURE__*/ jsx("div", {
376
+ ref: renderLayerRef,
377
+ style: {
378
+ display: 'flex',
379
+ justifyContent: 'center',
380
+ alignItems: 'center',
381
+ width: '100%',
382
+ height: '100%',
383
+ overflow: 'hidden'
384
+ },
385
+ onClick: handlePlaybackToggle,
386
+ children: (()=>{
387
+ const scale = containerSize.width > 0 && containerSize.height > 0 ? Math.min(containerSize.width / compositionWidth, containerSize.height / compositionHeight) : 1;
388
+ return /*#__PURE__*/ jsx("div", {
389
+ style: {
390
+ width: compositionWidth * scale,
391
+ height: compositionHeight * scale,
392
+ flexShrink: 0,
393
+ position: 'relative',
394
+ overflow: 'hidden'
395
+ },
396
+ children: /*#__PURE__*/ jsx("div", {
397
+ style: {
398
+ width: compositionWidth,
399
+ height: compositionHeight,
400
+ transformOrigin: '0 0',
401
+ transform: `scale(${scale})`
402
+ },
403
+ children: /*#__PURE__*/ jsx(StepsTimeline, {
404
+ frameMap: frameMap,
405
+ autoZoom: autoZoom && player.playing,
406
+ frame: player.currentFrame,
407
+ width: compositionWidth,
408
+ height: compositionHeight,
409
+ fps: frameMap.fps
410
+ })
411
+ })
412
+ });
413
+ })()
414
+ })
415
+ }),
416
+ subtitleEnabled && subtitle && /*#__PURE__*/ jsxs("div", {
417
+ className: "player-subtitle",
418
+ children: [
419
+ subtitle.title && /*#__PURE__*/ jsx("span", {
420
+ className: "player-subtitle-badge",
421
+ children: subtitle.title
422
+ }),
423
+ subtitle.subTitle && /*#__PURE__*/ jsx("span", {
424
+ className: "player-subtitle-text",
425
+ children: subtitle.subTitle
426
+ })
427
+ ]
428
+ }),
429
+ /*#__PURE__*/ jsxs("div", {
430
+ className: `control-bar ${controlsVisible ? '' : 'hidden'}`,
431
+ onClick: (e)=>e.stopPropagation(),
432
+ children: [
433
+ /*#__PURE__*/ jsx("div", {
434
+ className: "status-icon",
435
+ onClick: handlePlaybackToggle,
436
+ children: player.playing ? /*#__PURE__*/ jsx(PauseOutlined, {}) : /*#__PURE__*/ jsx(CaretRightOutlined, {})
437
+ }),
438
+ /*#__PURE__*/ jsxs("span", {
439
+ className: "time-display",
440
+ children: [
441
+ formatTime(Math.min(player.currentFrame, effectiveEndFrame), frameMap.fps),
442
+ ' ',
443
+ "/ ",
444
+ formatTime(effectiveEndFrame + 1, frameMap.fps)
445
+ ]
446
+ }),
447
+ /*#__PURE__*/ jsxs("div", {
448
+ className: "seek-bar-track",
449
+ ref: seekBarRef,
450
+ onPointerDown: handleSeekPointerDown,
451
+ children: [
452
+ /*#__PURE__*/ jsx("div", {
453
+ className: "seek-bar-fill",
454
+ style: {
455
+ width: `${seekPercent}%`
456
+ }
457
+ }),
458
+ /*#__PURE__*/ jsx("div", {
459
+ className: "seek-bar-knob",
460
+ style: {
461
+ left: `${seekPercent}%`
462
+ }
463
+ }),
464
+ chapterMarkers.map((marker)=>/*#__PURE__*/ jsx(Tooltip, {
465
+ title: marker.title,
466
+ overlayClassName: "chapter-tooltip",
467
+ children: /*#__PURE__*/ jsx("div", {
468
+ className: "chapter-marker",
469
+ style: {
470
+ left: `${marker.percent}%`
471
+ },
472
+ onClick: (e)=>{
473
+ e.stopPropagation();
474
+ player.seekTo(marker.frame);
475
+ }
476
+ })
477
+ }, marker.percent))
478
+ ]
479
+ }),
480
+ /*#__PURE__*/ jsxs("div", {
481
+ className: "player-custom-controls",
482
+ children: [
483
+ reportFileContent && canDownloadReport ? /*#__PURE__*/ jsx(Tooltip, {
484
+ title: "Download Report",
485
+ children: /*#__PURE__*/ jsx("div", {
486
+ className: "status-icon",
487
+ onClick: ()=>{
488
+ handleDownloadReport();
489
+ },
490
+ children: /*#__PURE__*/ jsx(DownloadOutlined, {})
491
+ })
492
+ }) : null,
493
+ /*#__PURE__*/ jsx(Dropdown, {
494
+ trigger: [
495
+ 'hover',
496
+ 'click'
497
+ ],
498
+ placement: "topRight",
499
+ overlayStyle: {
500
+ minWidth: '148px'
501
+ },
502
+ dropdownRender: ()=>/*#__PURE__*/ jsxs("div", {
503
+ className: "player-settings-dropdown",
504
+ children: [
505
+ /*#__PURE__*/ jsxs("div", {
506
+ className: "player-settings-item",
507
+ style: {
508
+ display: 'flex',
509
+ alignItems: 'center',
510
+ gap: '4px',
511
+ height: '32px',
512
+ padding: '0 8px',
513
+ borderRadius: '4px',
514
+ cursor: isExporting ? 'not-allowed' : 'pointer',
515
+ opacity: isExporting ? 0.5 : 1
516
+ },
517
+ onClick: isExporting ? void 0 : handleExportVideo,
518
+ children: [
519
+ /*#__PURE__*/ jsx("span", {
520
+ style: {
521
+ width: 16,
522
+ height: 16,
523
+ display: 'inline-flex',
524
+ alignItems: 'center',
525
+ justifyContent: 'center',
526
+ flexShrink: 0
527
+ },
528
+ children: isExporting ? /*#__PURE__*/ jsx(Progress, {
529
+ type: "circle",
530
+ percent: exportProgress,
531
+ size: 16,
532
+ strokeWidth: 14,
533
+ showInfo: false,
534
+ strokeColor: "#1677ff",
535
+ trailColor: "rgba(0, 0, 0, 0.12)"
536
+ }) : /*#__PURE__*/ jsx(ExportOutlined, {
537
+ style: {
538
+ width: '16px',
539
+ height: '16px'
540
+ }
541
+ })
542
+ }),
543
+ /*#__PURE__*/ jsx("span", {
544
+ className: "player-export-label",
545
+ children: isExporting ? `Exporting ${exportProgress}%` : 'Export video'
546
+ })
547
+ ]
548
+ }),
549
+ /*#__PURE__*/ jsx("div", {
550
+ className: "player-settings-divider"
551
+ }),
552
+ /*#__PURE__*/ jsxs("div", {
553
+ className: "player-settings-item",
554
+ style: {
555
+ display: 'flex',
556
+ alignItems: 'center',
557
+ justifyContent: 'space-between',
558
+ height: '32px',
559
+ padding: '0 8px',
560
+ borderRadius: '4px'
561
+ },
562
+ children: [
563
+ /*#__PURE__*/ jsxs("div", {
564
+ style: {
565
+ display: 'flex',
566
+ alignItems: 'center',
567
+ gap: '4px'
568
+ },
569
+ children: [
570
+ /*#__PURE__*/ jsx(global_perspective, {
571
+ style: {
572
+ width: '16px',
573
+ height: '16px'
574
+ }
575
+ }),
576
+ /*#__PURE__*/ jsx("span", {
577
+ style: {
578
+ fontSize: '14px',
579
+ marginRight: '16px'
580
+ },
581
+ children: "Focus on cursor"
582
+ })
583
+ ]
584
+ }),
585
+ /*#__PURE__*/ jsx(Switch, {
586
+ size: "small",
587
+ checked: autoZoom,
588
+ onChange: (checked)=>setAutoZoom(checked)
589
+ })
590
+ ]
591
+ }),
592
+ /*#__PURE__*/ jsxs("div", {
593
+ className: "player-settings-item",
594
+ style: {
595
+ display: 'flex',
596
+ alignItems: 'center',
597
+ justifyContent: 'space-between',
598
+ height: '32px',
599
+ padding: '0 8px',
600
+ borderRadius: '4px'
601
+ },
602
+ children: [
603
+ /*#__PURE__*/ jsxs("div", {
604
+ style: {
605
+ display: 'flex',
606
+ alignItems: 'center',
607
+ gap: '4px'
608
+ },
609
+ children: [
610
+ /*#__PURE__*/ jsx(FontSizeOutlined, {
611
+ style: {
612
+ width: '16px',
613
+ height: '16px'
614
+ }
615
+ }),
616
+ /*#__PURE__*/ jsx("span", {
617
+ style: {
618
+ fontSize: '14px',
619
+ marginRight: '16px'
620
+ },
621
+ children: "Subtitle"
622
+ })
623
+ ]
624
+ }),
625
+ /*#__PURE__*/ jsx(Switch, {
626
+ size: "small",
627
+ checked: subtitleEnabled,
628
+ onChange: (checked)=>setSubtitleEnabled(checked)
629
+ })
630
+ ]
631
+ }),
632
+ /*#__PURE__*/ jsx("div", {
633
+ className: "player-settings-divider"
634
+ }),
635
+ /*#__PURE__*/ jsxs("div", {
636
+ style: {
637
+ display: 'flex',
638
+ alignItems: 'center',
639
+ gap: '4px',
640
+ height: '32px',
641
+ padding: '0 8px'
642
+ },
643
+ children: [
644
+ /*#__PURE__*/ jsx(ThunderboltOutlined, {
645
+ style: {
646
+ width: '16px',
647
+ height: '16px'
648
+ }
649
+ }),
650
+ /*#__PURE__*/ jsx("span", {
651
+ style: {
652
+ fontSize: '14px'
653
+ },
654
+ children: "Playback speed"
655
+ })
656
+ ]
657
+ }),
658
+ [
659
+ 0.5,
660
+ 1,
661
+ 1.5,
662
+ 2
663
+ ].map((speed)=>/*#__PURE__*/ jsxs("div", {
664
+ onClick: ()=>setPlaybackSpeed(speed),
665
+ style: {
666
+ height: '32px',
667
+ lineHeight: '32px',
668
+ padding: '0 8px 0 28px',
669
+ fontSize: '14px',
670
+ cursor: 'pointer',
671
+ borderRadius: '4px'
672
+ },
673
+ className: `player-speed-option${playbackSpeed === speed ? ' active' : ''}`,
674
+ children: [
675
+ speed,
676
+ "x"
677
+ ]
678
+ }, speed))
679
+ ]
680
+ }),
681
+ menu: {
682
+ items: []
683
+ },
684
+ children: /*#__PURE__*/ jsx("div", {
685
+ className: "status-icon",
686
+ children: /*#__PURE__*/ jsx(player_setting, {
687
+ style: {
688
+ width: '16px',
689
+ height: '16px'
690
+ }
691
+ })
692
+ })
693
+ })
694
+ ]
695
+ })
696
+ ]
697
+ })
698
+ ]
699
+ })
700
+ });
701
+ }
702
+ export { Player };