@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,360 @@
1
+ import { mouseLoading, mousePointer } from "../../../utils/index.mjs";
2
+ import { getCenterHighlightBox } from "../../../utils/highlight-element.mjs";
3
+ import { deriveFrameState, shouldRenderCursor } from "./derive-frame-state.mjs";
4
+ import { getPlaybackViewport } from "./playback-layout.mjs";
5
+ import { resolveExportPointerLayout, resolveSpinnerLayout } from "./pointer-layout.mjs";
6
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
7
+ try {
8
+ var info = gen[key](arg);
9
+ var value = info.value;
10
+ } catch (error) {
11
+ reject(error);
12
+ return;
13
+ }
14
+ if (info.done) resolve(value);
15
+ else Promise.resolve(value).then(_next, _throw);
16
+ }
17
+ function _async_to_generator(fn) {
18
+ return function() {
19
+ var self = this, args = arguments;
20
+ return new Promise(function(resolve, reject) {
21
+ var gen = fn.apply(self, args);
22
+ function _next(value) {
23
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
24
+ }
25
+ function _throw(err) {
26
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
27
+ }
28
+ _next(void 0);
29
+ });
30
+ };
31
+ }
32
+ function _define_property(obj, key, value) {
33
+ if (key in obj) Object.defineProperty(obj, key, {
34
+ value: value,
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true
38
+ });
39
+ else obj[key] = value;
40
+ return obj;
41
+ }
42
+ function _object_spread(target) {
43
+ for(var i = 1; i < arguments.length; i++){
44
+ var source = null != arguments[i] ? arguments[i] : {};
45
+ var ownKeys = Object.keys(source);
46
+ if ("function" == typeof Object.getOwnPropertySymbols) ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
47
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
48
+ }));
49
+ ownKeys.forEach(function(key) {
50
+ _define_property(target, key, source[key]);
51
+ });
52
+ }
53
+ return target;
54
+ }
55
+ function export_branded_video_ownKeys(object, enumerableOnly) {
56
+ var keys = Object.keys(object);
57
+ if (Object.getOwnPropertySymbols) {
58
+ var symbols = Object.getOwnPropertySymbols(object);
59
+ if (enumerableOnly) symbols = symbols.filter(function(sym) {
60
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
61
+ });
62
+ keys.push.apply(keys, symbols);
63
+ }
64
+ return keys;
65
+ }
66
+ function _object_spread_props(target, source) {
67
+ source = null != source ? source : {};
68
+ if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
69
+ else export_branded_video_ownKeys(Object(source)).forEach(function(key) {
70
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
71
+ });
72
+ return target;
73
+ }
74
+ const W = 960;
75
+ const H = 540;
76
+ const POINTER_PHASE = 0.375;
77
+ const CROSSFADE_FRAMES = 10;
78
+ const EXPORT_STALL_GRACE_MS = 2000;
79
+ const EXPORT_STALL_GRACE_FRAMES = 10;
80
+ let activeExport = false;
81
+ function clamp(v, lo, hi) {
82
+ return Math.min(Math.max(v, lo), hi);
83
+ }
84
+ function lerp(a, b, t) {
85
+ return a + (b - a) * t;
86
+ }
87
+ function isExportRenderStalled(elapsedSinceLastFrameMs, frameDurationMs) {
88
+ return elapsedSinceLastFrameMs > Math.max(EXPORT_STALL_GRACE_MS, frameDurationMs * EXPORT_STALL_GRACE_FRAMES);
89
+ }
90
+ function resolveExportCamera(prevCamera, camera, imageWidth, progress, autoZoom) {
91
+ if (!autoZoom) return {
92
+ camLeft: 0,
93
+ camTop: 0,
94
+ camWidth: imageWidth
95
+ };
96
+ return {
97
+ camLeft: lerp(prevCamera.left, camera.left, progress),
98
+ camTop: lerp(prevCamera.top, camera.top, progress),
99
+ camWidth: lerp(prevCamera.width, camera.width, progress)
100
+ };
101
+ }
102
+ function loadImage(src) {
103
+ return new Promise((resolve, reject)=>{
104
+ const img = new Image();
105
+ img.crossOrigin = 'anonymous';
106
+ img.onload = ()=>resolve(img);
107
+ img.onerror = reject;
108
+ img.src = src;
109
+ });
110
+ }
111
+ function projectNativeRectToExportViewport(rect, cameraTransform, viewport) {
112
+ const scaleX = viewport.contentWidth / viewport.imageWidth;
113
+ const scaleY = viewport.contentHeight / viewport.imageHeight;
114
+ return {
115
+ left: viewport.offsetX + (rect.left * scaleX + cameraTransform.tx) * cameraTransform.zoom,
116
+ top: viewport.offsetY + (rect.top * scaleY + cameraTransform.ty) * cameraTransform.zoom,
117
+ width: rect.width * scaleX * cameraTransform.zoom,
118
+ height: rect.height * scaleY * cameraTransform.zoom
119
+ };
120
+ }
121
+ function drawInsightOverlays(ctx, insights, cameraTransform, viewport) {
122
+ ctx.save();
123
+ ctx.beginPath();
124
+ ctx.rect(viewport.offsetX, viewport.offsetY, viewport.contentWidth, viewport.contentHeight);
125
+ ctx.clip();
126
+ for (const insight of insights)if (!(insight.alpha <= 0)) {
127
+ ctx.save();
128
+ ctx.globalAlpha *= insight.alpha;
129
+ if (insight.highlightElement) {
130
+ const highlightBox = getCenterHighlightBox(insight.highlightElement);
131
+ const projected = projectNativeRectToExportViewport(highlightBox, cameraTransform, viewport);
132
+ ctx.fillStyle = 'rgba(253, 89, 7, 0.4)';
133
+ ctx.fillRect(projected.left, projected.top, projected.width, projected.height);
134
+ ctx.strokeStyle = '#fd5907';
135
+ ctx.lineWidth = 1;
136
+ ctx.strokeRect(projected.left, projected.top, projected.width, projected.height);
137
+ ctx.shadowColor = 'rgba(51, 51, 51, 0.4)';
138
+ ctx.shadowBlur = 2;
139
+ ctx.shadowOffsetX = 4;
140
+ ctx.shadowOffsetY = 4;
141
+ ctx.strokeRect(projected.left, projected.top, projected.width, projected.height);
142
+ ctx.shadowBlur = 0;
143
+ ctx.shadowOffsetX = 0;
144
+ ctx.shadowOffsetY = 0;
145
+ }
146
+ if (insight.searchArea) {
147
+ const projected = projectNativeRectToExportViewport(insight.searchArea, cameraTransform, viewport);
148
+ ctx.fillStyle = 'rgba(2, 131, 145, 0.4)';
149
+ ctx.fillRect(projected.left, projected.top, projected.width, projected.height);
150
+ ctx.strokeStyle = '#028391';
151
+ ctx.lineWidth = 1;
152
+ ctx.strokeRect(projected.left, projected.top, projected.width, projected.height);
153
+ }
154
+ ctx.restore();
155
+ }
156
+ ctx.restore();
157
+ }
158
+ function drawSpinningPointer(ctx, img, x, y, layout, elapsedMs) {
159
+ const progress = (Math.sin(elapsedMs / 500 - Math.PI / 2) + 1) / 2;
160
+ const rotation = progress * Math.PI * 2;
161
+ ctx.save();
162
+ ctx.translate(x, y);
163
+ ctx.rotate(rotation);
164
+ ctx.drawImage(img, -layout.centerOffsetX, -layout.centerOffsetY, layout.width, layout.height);
165
+ ctx.restore();
166
+ }
167
+ function drawSteps(ctx, stepsFrame, frameMap, imgCache, pointerCache, spinnerImg, autoZoom) {
168
+ var _pointerCache_get;
169
+ const { scriptFrames, imageWidth: baseW, imageHeight: baseH, fps } = frameMap;
170
+ const st = deriveFrameState(scriptFrames, stepsFrame, baseW, baseH, fps);
171
+ if (!st.img) return;
172
+ const { img, prevImg, imageWidth: imgW, imageHeight: imgH, camera, prevCamera, pointerMoved, imageChanged, rawProgress, frameInScript: fInScript, spinning, spinningElapsedMs, currentPointerImg, pointerVisible, insights } = st;
173
+ const pT = autoZoom ? pointerMoved ? Math.min(rawProgress / POINTER_PHASE, 1) : rawProgress : 1;
174
+ const cT = pointerMoved ? rawProgress <= POINTER_PHASE ? 0 : Math.min((rawProgress - POINTER_PHASE) / (1 - POINTER_PHASE), 1) : rawProgress;
175
+ const { camLeft: camL, camTop: camT2, camWidth: camW } = resolveExportCamera(prevCamera, camera, imgW, cT, autoZoom);
176
+ const ptrX = lerp(prevCamera.pointerLeft, camera.pointerLeft, pT);
177
+ const ptrY = lerp(prevCamera.pointerTop, camera.pointerTop, pT);
178
+ const zoom = imgW / camW;
179
+ const { offsetX, offsetY, contentWidth, contentHeight } = getPlaybackViewport(W, H, imgW, imgH);
180
+ const tx = contentWidth / imgW * -camL;
181
+ const ty = contentHeight / imgH * -camT2;
182
+ const crossAlpha = imageChanged ? clamp(fInScript / CROSSFADE_FRAMES, 0, 1) : 1;
183
+ ctx.fillStyle = '#000';
184
+ ctx.fillRect(0, 0, W, H);
185
+ const drawImg = (src, alpha)=>{
186
+ const imgEl = imgCache.get(src);
187
+ if (!imgEl || alpha <= 0) return;
188
+ ctx.save();
189
+ ctx.globalAlpha = alpha;
190
+ ctx.beginPath();
191
+ ctx.rect(0, 0, W, H);
192
+ ctx.clip();
193
+ ctx.translate(offsetX + tx * zoom, offsetY + ty * zoom);
194
+ ctx.scale(zoom, zoom);
195
+ ctx.drawImage(imgEl, 0, 0, contentWidth, contentHeight);
196
+ ctx.restore();
197
+ };
198
+ if (imageChanged && prevImg && crossAlpha < 1) drawImg(prevImg, 1 - crossAlpha);
199
+ drawImg(img, imageChanged ? crossAlpha : 1);
200
+ if (insights.length > 0) drawInsightOverlays(ctx, insights, {
201
+ zoom,
202
+ tx,
203
+ ty
204
+ }, {
205
+ offsetX,
206
+ offsetY,
207
+ contentWidth,
208
+ contentHeight,
209
+ imageWidth: imgW,
210
+ imageHeight: imgH
211
+ });
212
+ const camH = imgH / imgW * camW;
213
+ const sX = offsetX + (ptrX - camL) / camW * contentWidth;
214
+ const sY = offsetY + (ptrY - camT2) / camH * contentHeight;
215
+ const pointerLayout = resolveExportPointerLayout(imgW, contentWidth);
216
+ const spinnerLayout = resolveSpinnerLayout(pointerLayout);
217
+ const cursorImg = null != (_pointerCache_get = pointerCache.get(currentPointerImg)) ? _pointerCache_get : pointerCache.get(mousePointer);
218
+ const showCursor = shouldRenderCursor(pointerVisible, camera, prevCamera, imgW, imgH);
219
+ if (spinning && spinnerImg) drawSpinningPointer(ctx, spinnerImg, sX, sY, _object_spread_props(_object_spread({}, pointerLayout), {
220
+ width: spinnerLayout.size,
221
+ height: spinnerLayout.size,
222
+ centerOffsetX: spinnerLayout.centerOffset,
223
+ centerOffsetY: spinnerLayout.centerOffset
224
+ }), spinningElapsedMs);
225
+ if (!spinning && showCursor && cursorImg) ctx.drawImage(cursorImg, sX - pointerLayout.hotspotX, sY - pointerLayout.hotspotY, pointerLayout.width, pointerLayout.height);
226
+ }
227
+ function exportBrandedVideo(frameMap, options, onProgress) {
228
+ return _async_to_generator(function*() {
229
+ if (activeExport) throw new Error('Video export is already in progress');
230
+ activeExport = true;
231
+ try {
232
+ yield runExportBrandedVideo(frameMap, options, onProgress);
233
+ } finally{
234
+ activeExport = false;
235
+ }
236
+ })();
237
+ }
238
+ function runExportBrandedVideo(frameMap, options, onProgress) {
239
+ return _async_to_generator(function*() {
240
+ var _ref;
241
+ const { totalDurationInFrames: total, fps } = frameMap;
242
+ const autoZoom = null != (_ref = null == options ? void 0 : options.autoZoom) ? _ref : true;
243
+ const imgSrcs = new Set();
244
+ for (const sf of frameMap.scriptFrames)if (sf.img) imgSrcs.add(sf.img);
245
+ const imgCache = new Map();
246
+ yield Promise.all([
247
+ ...imgSrcs
248
+ ].map((src)=>_async_to_generator(function*() {
249
+ try {
250
+ imgCache.set(src, (yield loadImage(src)));
251
+ } catch (unused) {}
252
+ })()));
253
+ const pointerSrcs = new Set([
254
+ mousePointer
255
+ ]);
256
+ for (const sf of frameMap.scriptFrames)if (sf.pointerImg) pointerSrcs.add(sf.pointerImg);
257
+ const pointerCache = new Map();
258
+ yield Promise.all([
259
+ ...pointerSrcs
260
+ ].map((src)=>_async_to_generator(function*() {
261
+ try {
262
+ pointerCache.set(src, (yield loadImage(src)));
263
+ } catch (unused) {}
264
+ })()));
265
+ let spinnerImg = null;
266
+ try {
267
+ spinnerImg = yield loadImage(mouseLoading);
268
+ } catch (unused) {}
269
+ const canvas = document.createElement('canvas');
270
+ canvas.width = W;
271
+ canvas.height = H;
272
+ const ctx = canvas.getContext('2d');
273
+ const stream = canvas.captureStream(fps);
274
+ const recorder = new MediaRecorder(stream, {
275
+ mimeType: 'video/webm'
276
+ });
277
+ const chunks = [];
278
+ recorder.ondataavailable = (e)=>{
279
+ if (e.data.size > 0) chunks.push(e.data);
280
+ };
281
+ return new Promise((resolve, reject)=>{
282
+ let stoppedByError = null;
283
+ let settled = false;
284
+ let nextFrame = 0;
285
+ let nextFrameDueAt = performance.now();
286
+ let lastFrameAt = nextFrameDueAt;
287
+ let stopTimer = null;
288
+ let renderTimer = null;
289
+ const frameDuration = 1000 / fps;
290
+ const cleanup = ()=>{
291
+ if (stopTimer) clearTimeout(stopTimer);
292
+ if (renderTimer) clearTimeout(renderTimer);
293
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
294
+ stream.getTracks().forEach((track)=>track.stop());
295
+ };
296
+ const finishWithError = (error)=>{
297
+ if (settled || stoppedByError) return;
298
+ stoppedByError = error;
299
+ if ('inactive' !== recorder.state) recorder.stop();
300
+ else {
301
+ cleanup();
302
+ settled = true;
303
+ reject(error);
304
+ }
305
+ };
306
+ const handleVisibilityChange = ()=>{
307
+ if (document.hidden) finishWithError(new Error('Video export was interrupted because the report tab was hidden'));
308
+ };
309
+ recorder.onerror = ()=>{
310
+ finishWithError(new Error('MediaRecorder error'));
311
+ };
312
+ recorder.onstop = ()=>{
313
+ cleanup();
314
+ if (settled) return;
315
+ settled = true;
316
+ if (stoppedByError) return void reject(stoppedByError);
317
+ if (0 === chunks.length) return void reject(new Error('No video data'));
318
+ const blob = new Blob(chunks, {
319
+ type: 'video/webm'
320
+ });
321
+ const url = URL.createObjectURL(blob);
322
+ const a = document.createElement('a');
323
+ a.href = url;
324
+ a.download = 'midscene_replay.webm';
325
+ a.click();
326
+ setTimeout(()=>URL.revokeObjectURL(url), 1000);
327
+ resolve();
328
+ };
329
+ document.addEventListener('visibilitychange', handleVisibilityChange);
330
+ recorder.start();
331
+ const scheduleNextFrame = ()=>{
332
+ const delay = Math.max(0, nextFrameDueAt - performance.now());
333
+ renderTimer = setTimeout(()=>{
334
+ requestAnimationFrame(renderFrame);
335
+ }, delay);
336
+ };
337
+ const renderFrame = (timestamp)=>{
338
+ if (settled || 'inactive' === recorder.state) return;
339
+ if (nextFrame > 0 && isExportRenderStalled(timestamp - lastFrameAt, frameDuration)) return void finishWithError(new Error('Video export was interrupted because rendering stalled'));
340
+ lastFrameAt = timestamp;
341
+ ctx.clearRect(0, 0, W, H);
342
+ drawSteps(ctx, nextFrame, frameMap, imgCache, pointerCache, spinnerImg, autoZoom);
343
+ null == onProgress || onProgress((nextFrame + 1) / total);
344
+ nextFrame += 1;
345
+ if (nextFrame < total) {
346
+ nextFrameDueAt += frameDuration;
347
+ scheduleNextFrame();
348
+ } else stopTimer = setTimeout(()=>{
349
+ if ('inactive' !== recorder.state) recorder.stop();
350
+ }, 2 * frameDuration);
351
+ };
352
+ requestAnimationFrame((timestamp)=>{
353
+ lastFrameAt = timestamp;
354
+ nextFrameDueAt = timestamp;
355
+ renderFrame(timestamp);
356
+ });
357
+ });
358
+ })();
359
+ }
360
+ export { exportBrandedVideo, isExportRenderStalled, projectNativeRectToExportViewport, resolveExportCamera };
@@ -0,0 +1,149 @@
1
+ const FPS = 30;
2
+ function calculateFrameMap(scripts, options) {
3
+ let baseImageWidth = (null == options ? void 0 : options.imageWidth) || 1920;
4
+ let baseImageHeight = (null == options ? void 0 : options.imageHeight) || 1080;
5
+ for (const s of scripts)if (('img' === s.type || 'insight' === s.type) && s.img) {
6
+ baseImageWidth = s.imageWidth || baseImageWidth;
7
+ baseImageHeight = s.imageHeight || baseImageHeight;
8
+ break;
9
+ }
10
+ const scriptFrames = [];
11
+ let currentFrame = 0;
12
+ for (const script of scripts){
13
+ const durationMs = script.duration;
14
+ switch(script.type){
15
+ case 'sleep':
16
+ {
17
+ const frames = Math.ceil(durationMs / 1000 * FPS);
18
+ scriptFrames.push({
19
+ type: 'sleep',
20
+ startFrame: currentFrame,
21
+ durationInFrames: frames,
22
+ title: script.title,
23
+ subTitle: script.subTitle,
24
+ taskId: script.taskId
25
+ });
26
+ currentFrame += frames;
27
+ break;
28
+ }
29
+ case 'img':
30
+ {
31
+ const frames = Math.max(Math.ceil(durationMs / 1000 * FPS), 1);
32
+ const camera = script.camera;
33
+ const iw = script.imageWidth || baseImageWidth;
34
+ const ih = script.imageHeight || baseImageHeight;
35
+ const sf = {
36
+ type: 'img',
37
+ startFrame: currentFrame,
38
+ durationInFrames: frames,
39
+ img: script.img,
40
+ imageWidth: iw,
41
+ imageHeight: ih,
42
+ title: script.title,
43
+ subTitle: script.subTitle,
44
+ taskId: script.taskId
45
+ };
46
+ if (camera) {
47
+ var _camera_pointerLeft, _camera_pointerTop;
48
+ sf.cameraTarget = {
49
+ left: camera.left,
50
+ top: camera.top,
51
+ width: camera.width,
52
+ pointerLeft: null != (_camera_pointerLeft = camera.pointerLeft) ? _camera_pointerLeft : Math.round(iw / 2),
53
+ pointerTop: null != (_camera_pointerTop = camera.pointerTop) ? _camera_pointerTop : Math.round(ih / 2)
54
+ };
55
+ }
56
+ scriptFrames.push(sf);
57
+ currentFrame += frames;
58
+ break;
59
+ }
60
+ case 'insight':
61
+ {
62
+ const insightPhaseFrames = Math.max(Math.ceil(durationMs / 1000 * FPS), 1);
63
+ const cameraDurationMs = script.insightCameraDuration || 0;
64
+ const cameraPhaseFrames = Math.ceil(cameraDurationMs / 1000 * FPS);
65
+ const totalFrames = insightPhaseFrames + cameraPhaseFrames;
66
+ const iw = script.imageWidth || baseImageWidth;
67
+ const ih = script.imageHeight || baseImageHeight;
68
+ const camera = script.camera;
69
+ const sf = {
70
+ type: 'insight',
71
+ startFrame: currentFrame,
72
+ durationInFrames: totalFrames,
73
+ img: script.img,
74
+ imageWidth: iw,
75
+ imageHeight: ih,
76
+ insightPhaseFrames,
77
+ cameraPhaseFrames,
78
+ highlightElement: script.highlightElement,
79
+ searchArea: script.searchArea,
80
+ title: script.title,
81
+ subTitle: script.subTitle,
82
+ taskId: script.taskId
83
+ };
84
+ if (camera) {
85
+ var _camera_pointerLeft1, _camera_pointerTop1;
86
+ sf.cameraTarget = {
87
+ left: camera.left,
88
+ top: camera.top,
89
+ width: camera.width,
90
+ pointerLeft: null != (_camera_pointerLeft1 = camera.pointerLeft) ? _camera_pointerLeft1 : Math.round(iw / 2),
91
+ pointerTop: null != (_camera_pointerTop1 = camera.pointerTop) ? _camera_pointerTop1 : Math.round(ih / 2)
92
+ };
93
+ }
94
+ scriptFrames.push(sf);
95
+ currentFrame += totalFrames;
96
+ break;
97
+ }
98
+ case 'clear-insight':
99
+ {
100
+ const frames = Math.max(Math.ceil(durationMs / 1000 * FPS), 1);
101
+ scriptFrames.push({
102
+ type: 'clear-insight',
103
+ startFrame: currentFrame,
104
+ durationInFrames: frames,
105
+ title: script.title,
106
+ subTitle: script.subTitle,
107
+ taskId: script.taskId
108
+ });
109
+ currentFrame += frames;
110
+ break;
111
+ }
112
+ case 'spinning-pointer':
113
+ {
114
+ const frames = Math.max(Math.ceil(durationMs / 1000 * FPS), 1);
115
+ scriptFrames.push({
116
+ type: 'spinning-pointer',
117
+ startFrame: currentFrame,
118
+ durationInFrames: frames,
119
+ title: script.title,
120
+ subTitle: script.subTitle,
121
+ taskId: script.taskId
122
+ });
123
+ currentFrame += frames;
124
+ break;
125
+ }
126
+ case 'pointer':
127
+ scriptFrames.push({
128
+ type: 'pointer',
129
+ startFrame: currentFrame,
130
+ durationInFrames: 0,
131
+ pointerImg: script.img,
132
+ title: script.title,
133
+ subTitle: script.subTitle,
134
+ taskId: script.taskId
135
+ });
136
+ break;
137
+ }
138
+ }
139
+ const stepsDurationInFrames = Math.max(currentFrame, 1);
140
+ return {
141
+ scriptFrames,
142
+ totalDurationInFrames: stepsDurationInFrames,
143
+ fps: FPS,
144
+ stepsDurationInFrames,
145
+ imageWidth: baseImageWidth,
146
+ imageHeight: baseImageHeight
147
+ };
148
+ }
149
+ export { FPS, calculateFrameMap };
@@ -0,0 +1,6 @@
1
+ import { deriveFrameState } from "./derive-frame-state.mjs";
2
+ function getPlaybackFrameState(frameMap, frame) {
3
+ const state = deriveFrameState(frameMap.scriptFrames, frame, frameMap.imageWidth, frameMap.imageHeight, frameMap.fps);
4
+ return state.img ? state : null;
5
+ }
6
+ export { getPlaybackFrameState };
@@ -0,0 +1,12 @@
1
+ function getPlaybackViewport(containerWidth, containerHeight, imageWidth, imageHeight) {
2
+ const scale = Math.min(containerWidth / imageWidth, containerHeight / imageHeight);
3
+ const contentWidth = imageWidth * scale;
4
+ const contentHeight = imageHeight * scale;
5
+ return {
6
+ offsetX: (containerWidth - contentWidth) / 2,
7
+ offsetY: (containerHeight - contentHeight) / 2,
8
+ contentWidth,
9
+ contentHeight
10
+ };
11
+ }
12
+ export { getPlaybackViewport };
@@ -0,0 +1,36 @@
1
+ const POINTER_REFERENCE_IMAGE_WIDTH = 1920;
2
+ const POINTER_WIDTH = 44;
3
+ const POINTER_HEIGHT = 56;
4
+ const POINTER_HOTSPOT_X = 6;
5
+ const POINTER_HOTSPOT_Y = 4;
6
+ function assertPositiveFinite(value, name) {
7
+ if (!Number.isFinite(value) || value <= 0) throw new Error(`${name} must be a positive finite number`);
8
+ }
9
+ function buildPointerLayout(scale) {
10
+ return {
11
+ scale,
12
+ width: POINTER_WIDTH * scale,
13
+ height: POINTER_HEIGHT * scale,
14
+ hotspotX: POINTER_HOTSPOT_X * scale,
15
+ hotspotY: POINTER_HOTSPOT_Y * scale,
16
+ centerOffsetX: POINTER_WIDTH * scale / 2,
17
+ centerOffsetY: POINTER_HEIGHT * scale / 2
18
+ };
19
+ }
20
+ function resolvePointerLayout(imageWidth) {
21
+ assertPositiveFinite(imageWidth, 'imageWidth');
22
+ return buildPointerLayout(Math.max(1, Math.sqrt(imageWidth / POINTER_REFERENCE_IMAGE_WIDTH)));
23
+ }
24
+ function resolveExportPointerLayout(imageWidth, contentWidth) {
25
+ assertPositiveFinite(contentWidth, 'contentWidth');
26
+ const liveLayout = resolvePointerLayout(imageWidth);
27
+ return buildPointerLayout(liveLayout.scale * (contentWidth / imageWidth));
28
+ }
29
+ function resolveSpinnerLayout(pointerLayout) {
30
+ const size = pointerLayout.height;
31
+ return {
32
+ size,
33
+ centerOffset: size / 2
34
+ };
35
+ }
36
+ export { POINTER_HEIGHT, POINTER_HOTSPOT_X, POINTER_HOTSPOT_Y, POINTER_WIDTH, resolveExportPointerLayout, resolvePointerLayout, resolveSpinnerLayout };
@@ -0,0 +1,87 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ function useFramePlayer(options) {
3
+ var _options_playbackRate, _options_playbackRate1;
4
+ const { durationInFrames, fps, autoPlay = false, loop = false } = options;
5
+ const [currentFrame, setCurrentFrame] = useState(0);
6
+ const [playing, setPlaying] = useState(autoPlay);
7
+ const playingRef = useRef(playing);
8
+ const frameRef = useRef(currentFrame);
9
+ const rateRef = useRef(null != (_options_playbackRate = options.playbackRate) ? _options_playbackRate : 1);
10
+ const durationRef = useRef(durationInFrames);
11
+ const fpsRef = useRef(fps);
12
+ const loopRef = useRef(loop);
13
+ playingRef.current = playing;
14
+ frameRef.current = currentFrame;
15
+ rateRef.current = null != (_options_playbackRate1 = options.playbackRate) ? _options_playbackRate1 : 1;
16
+ durationRef.current = durationInFrames;
17
+ fpsRef.current = fps;
18
+ loopRef.current = loop;
19
+ useEffect(()=>{
20
+ if (!playing) return;
21
+ let rafId;
22
+ let lastTime = null;
23
+ let accumulated = 0;
24
+ const tick = (now)=>{
25
+ if (null !== lastTime) {
26
+ const delta = (now - lastTime) * rateRef.current;
27
+ accumulated += delta;
28
+ const frameDuration = 1000 / fpsRef.current;
29
+ while(accumulated >= frameDuration){
30
+ accumulated -= frameDuration;
31
+ const next = frameRef.current + 1;
32
+ if (next >= durationRef.current) if (loopRef.current) {
33
+ frameRef.current = 0;
34
+ setCurrentFrame(0);
35
+ } else {
36
+ frameRef.current = durationRef.current - 1;
37
+ setCurrentFrame(durationRef.current - 1);
38
+ setPlaying(false);
39
+ return;
40
+ }
41
+ else {
42
+ frameRef.current = next;
43
+ setCurrentFrame(next);
44
+ }
45
+ }
46
+ }
47
+ lastTime = now;
48
+ rafId = requestAnimationFrame(tick);
49
+ };
50
+ rafId = requestAnimationFrame(tick);
51
+ return ()=>cancelAnimationFrame(rafId);
52
+ }, [
53
+ playing
54
+ ]);
55
+ const resetIfAtEnd = ()=>{
56
+ if (frameRef.current >= durationRef.current - 1) {
57
+ frameRef.current = 0;
58
+ setCurrentFrame(0);
59
+ }
60
+ };
61
+ const play = useCallback(()=>{
62
+ resetIfAtEnd();
63
+ setPlaying(true);
64
+ }, []);
65
+ const pause = useCallback(()=>setPlaying(false), []);
66
+ const toggle = useCallback(()=>{
67
+ if (playingRef.current) setPlaying(false);
68
+ else {
69
+ resetIfAtEnd();
70
+ setPlaying(true);
71
+ }
72
+ }, []);
73
+ const seekTo = useCallback((frame)=>{
74
+ const clamped = Math.max(0, Math.min(frame, durationRef.current - 1));
75
+ frameRef.current = clamped;
76
+ setCurrentFrame(clamped);
77
+ }, []);
78
+ return {
79
+ currentFrame,
80
+ playing,
81
+ play,
82
+ pause,
83
+ toggle,
84
+ seekTo
85
+ };
86
+ }
87
+ export { useFramePlayer };