@midscene/visualizer 1.7.7-beta-20260429033400.0 → 1.7.7

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.
@@ -24,13 +24,16 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
- resolveExportCamera: ()=>resolveExportCamera,
28
- exportBrandedVideo: ()=>exportBrandedVideo
27
+ exportBrandedVideo: ()=>exportBrandedVideo,
28
+ isExportRenderStalled: ()=>isExportRenderStalled,
29
+ projectNativeRectToExportViewport: ()=>projectNativeRectToExportViewport,
30
+ resolveExportCamera: ()=>resolveExportCamera
29
31
  });
30
32
  const index_js_namespaceObject = require("../../../utils/index.js");
31
33
  const highlight_element_js_namespaceObject = require("../../../utils/highlight-element.js");
32
34
  const external_derive_frame_state_js_namespaceObject = require("./derive-frame-state.js");
33
35
  const external_playback_layout_js_namespaceObject = require("./playback-layout.js");
36
+ const external_pointer_layout_js_namespaceObject = require("./pointer-layout.js");
34
37
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
35
38
  try {
36
39
  var info = gen[key](arg);
@@ -57,16 +60,64 @@ function _async_to_generator(fn) {
57
60
  });
58
61
  };
59
62
  }
63
+ function _define_property(obj, key, value) {
64
+ if (key in obj) Object.defineProperty(obj, key, {
65
+ value: value,
66
+ enumerable: true,
67
+ configurable: true,
68
+ writable: true
69
+ });
70
+ else obj[key] = value;
71
+ return obj;
72
+ }
73
+ function _object_spread(target) {
74
+ for(var i = 1; i < arguments.length; i++){
75
+ var source = null != arguments[i] ? arguments[i] : {};
76
+ var ownKeys = Object.keys(source);
77
+ if ("function" == typeof Object.getOwnPropertySymbols) ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
78
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
79
+ }));
80
+ ownKeys.forEach(function(key) {
81
+ _define_property(target, key, source[key]);
82
+ });
83
+ }
84
+ return target;
85
+ }
86
+ function export_branded_video_ownKeys(object, enumerableOnly) {
87
+ var keys = Object.keys(object);
88
+ if (Object.getOwnPropertySymbols) {
89
+ var symbols = Object.getOwnPropertySymbols(object);
90
+ if (enumerableOnly) symbols = symbols.filter(function(sym) {
91
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
92
+ });
93
+ keys.push.apply(keys, symbols);
94
+ }
95
+ return keys;
96
+ }
97
+ function _object_spread_props(target, source) {
98
+ source = null != source ? source : {};
99
+ if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
100
+ else export_branded_video_ownKeys(Object(source)).forEach(function(key) {
101
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
102
+ });
103
+ return target;
104
+ }
60
105
  const W = 960;
61
106
  const H = 540;
62
107
  const POINTER_PHASE = 0.375;
63
108
  const CROSSFADE_FRAMES = 10;
109
+ const EXPORT_STALL_GRACE_MS = 2000;
110
+ const EXPORT_STALL_GRACE_FRAMES = 10;
111
+ let activeExport = false;
64
112
  function clamp(v, lo, hi) {
65
113
  return Math.min(Math.max(v, lo), hi);
66
114
  }
67
115
  function lerp(a, b, t) {
68
116
  return a + (b - a) * t;
69
117
  }
118
+ function isExportRenderStalled(elapsedSinceLastFrameMs, frameDurationMs) {
119
+ return elapsedSinceLastFrameMs > Math.max(EXPORT_STALL_GRACE_MS, frameDurationMs * EXPORT_STALL_GRACE_FRAMES);
120
+ }
70
121
  function resolveExportCamera(prevCamera, camera, imageWidth, progress, autoZoom) {
71
122
  if (!autoZoom) return {
72
123
  camLeft: 0,
@@ -88,60 +139,68 @@ function loadImage(src) {
88
139
  img.src = src;
89
140
  });
90
141
  }
91
- function drawInsightOverlays(ctx, insights, cameraTransform, bx, contentY) {
142
+ function projectNativeRectToExportViewport(rect, cameraTransform, viewport) {
143
+ const scaleX = viewport.contentWidth / viewport.imageWidth;
144
+ const scaleY = viewport.contentHeight / viewport.imageHeight;
145
+ return {
146
+ left: viewport.offsetX + (rect.left * scaleX + cameraTransform.tx) * cameraTransform.zoom,
147
+ top: viewport.offsetY + (rect.top * scaleY + cameraTransform.ty) * cameraTransform.zoom,
148
+ width: rect.width * scaleX * cameraTransform.zoom,
149
+ height: rect.height * scaleY * cameraTransform.zoom
150
+ };
151
+ }
152
+ function drawInsightOverlays(ctx, insights, cameraTransform, viewport) {
153
+ ctx.save();
154
+ ctx.beginPath();
155
+ ctx.rect(viewport.offsetX, viewport.offsetY, viewport.contentWidth, viewport.contentHeight);
156
+ ctx.clip();
92
157
  for (const insight of insights)if (!(insight.alpha <= 0)) {
93
158
  ctx.save();
94
159
  ctx.globalAlpha *= insight.alpha;
95
160
  if (insight.highlightElement) {
96
161
  const highlightBox = (0, highlight_element_js_namespaceObject.getCenterHighlightBox)(insight.highlightElement);
97
- const rx = bx + (highlightBox.left * cameraTransform.zoom + cameraTransform.tx * cameraTransform.zoom);
98
- const ry = contentY + (highlightBox.top * cameraTransform.zoom + cameraTransform.ty * cameraTransform.zoom);
99
- const highlightWidth = highlightBox.width * cameraTransform.zoom;
100
- const highlightHeight = highlightBox.height * cameraTransform.zoom;
162
+ const projected = projectNativeRectToExportViewport(highlightBox, cameraTransform, viewport);
101
163
  ctx.fillStyle = 'rgba(253, 89, 7, 0.4)';
102
- ctx.fillRect(rx, ry, highlightWidth, highlightHeight);
164
+ ctx.fillRect(projected.left, projected.top, projected.width, projected.height);
103
165
  ctx.strokeStyle = '#fd5907';
104
166
  ctx.lineWidth = 1;
105
- ctx.strokeRect(rx, ry, highlightWidth, highlightHeight);
167
+ ctx.strokeRect(projected.left, projected.top, projected.width, projected.height);
106
168
  ctx.shadowColor = 'rgba(51, 51, 51, 0.4)';
107
169
  ctx.shadowBlur = 2;
108
170
  ctx.shadowOffsetX = 4;
109
171
  ctx.shadowOffsetY = 4;
110
- ctx.strokeRect(rx, ry, highlightWidth, highlightHeight);
172
+ ctx.strokeRect(projected.left, projected.top, projected.width, projected.height);
111
173
  ctx.shadowBlur = 0;
112
174
  ctx.shadowOffsetX = 0;
113
175
  ctx.shadowOffsetY = 0;
114
176
  }
115
177
  if (insight.searchArea) {
116
- const r = insight.searchArea;
117
- const rx = bx + (r.left * cameraTransform.zoom + cameraTransform.tx * cameraTransform.zoom);
118
- const ry = contentY + (r.top * cameraTransform.zoom + cameraTransform.ty * cameraTransform.zoom);
119
- const rw = r.width * cameraTransform.zoom;
120
- const rh = r.height * cameraTransform.zoom;
178
+ const projected = projectNativeRectToExportViewport(insight.searchArea, cameraTransform, viewport);
121
179
  ctx.fillStyle = 'rgba(2, 131, 145, 0.4)';
122
- ctx.fillRect(rx, ry, rw, rh);
180
+ ctx.fillRect(projected.left, projected.top, projected.width, projected.height);
123
181
  ctx.strokeStyle = '#028391';
124
182
  ctx.lineWidth = 1;
125
- ctx.strokeRect(rx, ry, rw, rh);
183
+ ctx.strokeRect(projected.left, projected.top, projected.width, projected.height);
126
184
  }
127
185
  ctx.restore();
128
186
  }
187
+ ctx.restore();
129
188
  }
130
- function drawSpinningPointer(ctx, img, x, y, elapsedMs) {
189
+ function drawSpinningPointer(ctx, img, x, y, layout, elapsedMs) {
131
190
  const progress = (Math.sin(elapsedMs / 500 - Math.PI / 2) + 1) / 2;
132
191
  const rotation = progress * Math.PI * 2;
133
192
  ctx.save();
134
193
  ctx.translate(x, y);
135
194
  ctx.rotate(rotation);
136
- ctx.drawImage(img, -11, -14, 22, 28);
195
+ ctx.drawImage(img, -layout.centerOffsetX, -layout.centerOffsetY, layout.width, layout.height);
137
196
  ctx.restore();
138
197
  }
139
- function drawSteps(ctx, stepsFrame, frameMap, imgCache, cursorImg, spinnerImg, autoZoom) {
198
+ function drawSteps(ctx, stepsFrame, frameMap, imgCache, pointerCache, spinnerImg, autoZoom) {
140
199
  const { scriptFrames, imageWidth: baseW, imageHeight: baseH, fps } = frameMap;
141
200
  const st = (0, external_derive_frame_state_js_namespaceObject.deriveFrameState)(scriptFrames, stepsFrame, baseW, baseH, fps);
142
201
  if (!st.img) return;
143
- const { img, prevImg, imageWidth: imgW, imageHeight: imgH, camera, prevCamera, pointerMoved, imageChanged, rawProgress, frameInScript: fInScript, spinning, spinningElapsedMs, insights } = st;
144
- const pT = pointerMoved ? Math.min(rawProgress / POINTER_PHASE, 1) : rawProgress;
202
+ const { img, prevImg, imageWidth: imgW, imageHeight: imgH, camera, prevCamera, pointerMoved, imageChanged, rawProgress, frameInScript: fInScript, spinning, spinningElapsedMs, currentPointerImg, pointerVisible, insights } = st;
203
+ const pT = autoZoom ? pointerMoved ? Math.min(rawProgress / POINTER_PHASE, 1) : rawProgress : 1;
145
204
  const cT = pointerMoved ? rawProgress <= POINTER_PHASE ? 0 : Math.min((rawProgress - POINTER_PHASE) / (1 - POINTER_PHASE), 1) : rawProgress;
146
205
  const { camLeft: camL, camTop: camT2, camWidth: camW } = resolveExportCamera(prevCamera, camera, imgW, cT, autoZoom);
147
206
  const ptrX = lerp(prevCamera.pointerLeft, camera.pointerLeft, pT);
@@ -172,15 +231,42 @@ function drawSteps(ctx, stepsFrame, frameMap, imgCache, cursorImg, spinnerImg, a
172
231
  zoom,
173
232
  tx,
174
233
  ty
175
- }, offsetX, offsetY);
234
+ }, {
235
+ offsetX,
236
+ offsetY,
237
+ contentWidth,
238
+ contentHeight,
239
+ imageWidth: imgW,
240
+ imageHeight: imgH
241
+ });
176
242
  const camH = imgH / imgW * camW;
177
243
  const sX = offsetX + (ptrX - camL) / camW * contentWidth;
178
244
  const sY = offsetY + (ptrY - camT2) / camH * contentHeight;
179
- const hasPtrData = Math.abs(camera.pointerLeft - Math.round(imgW / 2)) > 1 || Math.abs(camera.pointerTop - Math.round(imgH / 2)) > 1 || Math.abs(prevCamera.pointerLeft - Math.round(imgW / 2)) > 1 || Math.abs(prevCamera.pointerTop - Math.round(imgH / 2)) > 1;
180
- if (spinning && spinnerImg) drawSpinningPointer(ctx, spinnerImg, sX, sY, spinningElapsedMs);
181
- if (!spinning && hasPtrData && cursorImg) ctx.drawImage(cursorImg, sX - 3, sY - 2, 22, 28);
245
+ const pointerLayout = (0, external_pointer_layout_js_namespaceObject.resolveExportPointerLayout)(imgW, contentWidth);
246
+ const spinnerLayout = (0, external_pointer_layout_js_namespaceObject.resolveSpinnerLayout)(pointerLayout);
247
+ var _pointerCache_get;
248
+ const cursorImg = null != (_pointerCache_get = pointerCache.get(currentPointerImg)) ? _pointerCache_get : pointerCache.get(index_js_namespaceObject.mousePointer);
249
+ const showCursor = (0, external_derive_frame_state_js_namespaceObject.shouldRenderCursor)(pointerVisible, camera, prevCamera, imgW, imgH);
250
+ if (spinning && spinnerImg) drawSpinningPointer(ctx, spinnerImg, sX, sY, _object_spread_props(_object_spread({}, pointerLayout), {
251
+ width: spinnerLayout.size,
252
+ height: spinnerLayout.size,
253
+ centerOffsetX: spinnerLayout.centerOffset,
254
+ centerOffsetY: spinnerLayout.centerOffset
255
+ }), spinningElapsedMs);
256
+ if (!spinning && showCursor && cursorImg) ctx.drawImage(cursorImg, sX - pointerLayout.hotspotX, sY - pointerLayout.hotspotY, pointerLayout.width, pointerLayout.height);
182
257
  }
183
258
  function exportBrandedVideo(frameMap, options, onProgress) {
259
+ return _async_to_generator(function*() {
260
+ if (activeExport) throw new Error('Video export is already in progress');
261
+ activeExport = true;
262
+ try {
263
+ yield runExportBrandedVideo(frameMap, options, onProgress);
264
+ } finally{
265
+ activeExport = false;
266
+ }
267
+ })();
268
+ }
269
+ function runExportBrandedVideo(frameMap, options, onProgress) {
184
270
  return _async_to_generator(function*() {
185
271
  const { totalDurationInFrames: total, fps } = frameMap;
186
272
  var _options_autoZoom;
@@ -195,11 +281,19 @@ function exportBrandedVideo(frameMap, options, onProgress) {
195
281
  imgCache.set(src, (yield loadImage(src)));
196
282
  } catch (e) {}
197
283
  })()));
198
- let cursorImg = null;
284
+ const pointerSrcs = new Set([
285
+ index_js_namespaceObject.mousePointer
286
+ ]);
287
+ for (const sf of frameMap.scriptFrames)if (sf.pointerImg) pointerSrcs.add(sf.pointerImg);
288
+ const pointerCache = new Map();
289
+ yield Promise.all([
290
+ ...pointerSrcs
291
+ ].map((src)=>_async_to_generator(function*() {
292
+ try {
293
+ pointerCache.set(src, (yield loadImage(src)));
294
+ } catch (e) {}
295
+ })()));
199
296
  let spinnerImg = null;
200
- try {
201
- cursorImg = yield loadImage(index_js_namespaceObject.mousePointer);
202
- } catch (e) {}
203
297
  try {
204
298
  spinnerImg = yield loadImage(index_js_namespaceObject.mouseLoading);
205
299
  } catch (e) {}
@@ -216,8 +310,41 @@ function exportBrandedVideo(frameMap, options, onProgress) {
216
310
  if (e.data.size > 0) chunks.push(e.data);
217
311
  };
218
312
  return new Promise((resolve, reject)=>{
219
- recorder.onerror = ()=>reject(new Error('MediaRecorder error'));
313
+ let stoppedByError = null;
314
+ let settled = false;
315
+ let nextFrame = 0;
316
+ let nextFrameDueAt = performance.now();
317
+ let lastFrameAt = nextFrameDueAt;
318
+ let stopTimer = null;
319
+ let renderTimer = null;
320
+ const frameDuration = 1000 / fps;
321
+ const cleanup = ()=>{
322
+ if (stopTimer) clearTimeout(stopTimer);
323
+ if (renderTimer) clearTimeout(renderTimer);
324
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
325
+ stream.getTracks().forEach((track)=>track.stop());
326
+ };
327
+ const finishWithError = (error)=>{
328
+ if (settled || stoppedByError) return;
329
+ stoppedByError = error;
330
+ if ('inactive' !== recorder.state) recorder.stop();
331
+ else {
332
+ cleanup();
333
+ settled = true;
334
+ reject(error);
335
+ }
336
+ };
337
+ const handleVisibilityChange = ()=>{
338
+ if (document.hidden) finishWithError(new Error('Video export was interrupted because the report tab was hidden'));
339
+ };
340
+ recorder.onerror = ()=>{
341
+ finishWithError(new Error('MediaRecorder error'));
342
+ };
220
343
  recorder.onstop = ()=>{
344
+ cleanup();
345
+ if (settled) return;
346
+ settled = true;
347
+ if (stoppedByError) return void reject(stoppedByError);
221
348
  if (0 === chunks.length) return void reject(new Error('No video data'));
222
349
  const blob = new Blob(chunks, {
223
350
  type: 'video/webm'
@@ -227,34 +354,48 @@ function exportBrandedVideo(frameMap, options, onProgress) {
227
354
  a.href = url;
228
355
  a.download = 'midscene_replay.webm';
229
356
  a.click();
230
- stream.getTracks().forEach((track)=>track.stop());
231
357
  setTimeout(()=>URL.revokeObjectURL(url), 1000);
232
358
  resolve();
233
359
  };
360
+ document.addEventListener('visibilitychange', handleVisibilityChange);
234
361
  recorder.start();
235
- const frameDuration = 1000 / fps;
236
- const startTime = performance.now();
237
- let lastFrame = -1;
238
- const tick = ()=>{
239
- const elapsed = performance.now() - startTime;
240
- const targetFrame = Math.min(Math.floor(elapsed / frameDuration), total - 1);
241
- if (targetFrame > lastFrame) {
242
- lastFrame = targetFrame;
243
- ctx.clearRect(0, 0, W, H);
244
- drawSteps(ctx, targetFrame, frameMap, imgCache, cursorImg, spinnerImg, autoZoom);
245
- null == onProgress || onProgress((targetFrame + 1) / total);
246
- }
247
- if (targetFrame < total - 1) requestAnimationFrame(tick);
248
- else setTimeout(()=>recorder.stop(), 2 * frameDuration);
362
+ const scheduleNextFrame = ()=>{
363
+ const delay = Math.max(0, nextFrameDueAt - performance.now());
364
+ renderTimer = setTimeout(()=>{
365
+ requestAnimationFrame(renderFrame);
366
+ }, delay);
367
+ };
368
+ const renderFrame = (timestamp)=>{
369
+ if (settled || 'inactive' === recorder.state) return;
370
+ if (nextFrame > 0 && isExportRenderStalled(timestamp - lastFrameAt, frameDuration)) return void finishWithError(new Error('Video export was interrupted because rendering stalled'));
371
+ lastFrameAt = timestamp;
372
+ ctx.clearRect(0, 0, W, H);
373
+ drawSteps(ctx, nextFrame, frameMap, imgCache, pointerCache, spinnerImg, autoZoom);
374
+ null == onProgress || onProgress((nextFrame + 1) / total);
375
+ nextFrame += 1;
376
+ if (nextFrame < total) {
377
+ nextFrameDueAt += frameDuration;
378
+ scheduleNextFrame();
379
+ } else stopTimer = setTimeout(()=>{
380
+ if ('inactive' !== recorder.state) recorder.stop();
381
+ }, 2 * frameDuration);
249
382
  };
250
- requestAnimationFrame(tick);
383
+ requestAnimationFrame((timestamp)=>{
384
+ lastFrameAt = timestamp;
385
+ nextFrameDueAt = timestamp;
386
+ renderFrame(timestamp);
387
+ });
251
388
  });
252
389
  })();
253
390
  }
254
391
  exports.exportBrandedVideo = __webpack_exports__.exportBrandedVideo;
392
+ exports.isExportRenderStalled = __webpack_exports__.isExportRenderStalled;
393
+ exports.projectNativeRectToExportViewport = __webpack_exports__.projectNativeRectToExportViewport;
255
394
  exports.resolveExportCamera = __webpack_exports__.resolveExportCamera;
256
395
  for(var __rspack_i in __webpack_exports__)if (-1 === [
257
396
  "exportBrandedVideo",
397
+ "isExportRenderStalled",
398
+ "projectNativeRectToExportViewport",
258
399
  "resolveExportCamera"
259
400
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
260
401
  Object.defineProperty(exports, '__esModule', {
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ POINTER_HEIGHT: ()=>POINTER_HEIGHT,
28
+ POINTER_HOTSPOT_X: ()=>POINTER_HOTSPOT_X,
29
+ POINTER_HOTSPOT_Y: ()=>POINTER_HOTSPOT_Y,
30
+ POINTER_WIDTH: ()=>POINTER_WIDTH,
31
+ resolveExportPointerLayout: ()=>resolveExportPointerLayout,
32
+ resolvePointerLayout: ()=>resolvePointerLayout,
33
+ resolveSpinnerLayout: ()=>resolveSpinnerLayout
34
+ });
35
+ const POINTER_REFERENCE_IMAGE_WIDTH = 1920;
36
+ const POINTER_WIDTH = 44;
37
+ const POINTER_HEIGHT = 56;
38
+ const POINTER_HOTSPOT_X = 6;
39
+ const POINTER_HOTSPOT_Y = 4;
40
+ function assertPositiveFinite(value, name) {
41
+ if (!Number.isFinite(value) || value <= 0) throw new Error(`${name} must be a positive finite number`);
42
+ }
43
+ function buildPointerLayout(scale) {
44
+ return {
45
+ scale,
46
+ width: POINTER_WIDTH * scale,
47
+ height: POINTER_HEIGHT * scale,
48
+ hotspotX: POINTER_HOTSPOT_X * scale,
49
+ hotspotY: POINTER_HOTSPOT_Y * scale,
50
+ centerOffsetX: POINTER_WIDTH * scale / 2,
51
+ centerOffsetY: POINTER_HEIGHT * scale / 2
52
+ };
53
+ }
54
+ function resolvePointerLayout(imageWidth) {
55
+ assertPositiveFinite(imageWidth, 'imageWidth');
56
+ return buildPointerLayout(Math.max(1, Math.sqrt(imageWidth / POINTER_REFERENCE_IMAGE_WIDTH)));
57
+ }
58
+ function resolveExportPointerLayout(imageWidth, contentWidth) {
59
+ assertPositiveFinite(contentWidth, 'contentWidth');
60
+ const liveLayout = resolvePointerLayout(imageWidth);
61
+ return buildPointerLayout(liveLayout.scale * (contentWidth / imageWidth));
62
+ }
63
+ function resolveSpinnerLayout(pointerLayout) {
64
+ const size = pointerLayout.height;
65
+ return {
66
+ size,
67
+ centerOffset: size / 2
68
+ };
69
+ }
70
+ exports.POINTER_HEIGHT = __webpack_exports__.POINTER_HEIGHT;
71
+ exports.POINTER_HOTSPOT_X = __webpack_exports__.POINTER_HOTSPOT_X;
72
+ exports.POINTER_HOTSPOT_Y = __webpack_exports__.POINTER_HOTSPOT_Y;
73
+ exports.POINTER_WIDTH = __webpack_exports__.POINTER_WIDTH;
74
+ exports.resolveExportPointerLayout = __webpack_exports__.resolveExportPointerLayout;
75
+ exports.resolvePointerLayout = __webpack_exports__.resolvePointerLayout;
76
+ exports.resolveSpinnerLayout = __webpack_exports__.resolveSpinnerLayout;
77
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
78
+ "POINTER_HEIGHT",
79
+ "POINTER_HOTSPOT_X",
80
+ "POINTER_HOTSPOT_Y",
81
+ "POINTER_WIDTH",
82
+ "resolveExportPointerLayout",
83
+ "resolvePointerLayout",
84
+ "resolveSpinnerLayout"
85
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
86
+ Object.defineProperty(exports, '__esModule', {
87
+ value: true
88
+ });
@@ -12,4 +12,4 @@ export declare function Player(props?: {
12
12
  canDownloadReport?: boolean;
13
13
  onDownloadReport?: ReportDownloadHandler;
14
14
  onTaskChange?: (taskId: string | null) => void;
15
- }): import("react").JSX.Element;
15
+ }): import("react").JSX.Element | null;
@@ -0,0 +1 @@
1
+ export declare function shouldRestartPlaybackFromBeginning(currentFrame: number, effectiveEndFrame: number): boolean;
@@ -26,6 +26,7 @@ export interface FrameState {
26
26
  spinning: boolean;
27
27
  spinningElapsedMs: number;
28
28
  currentPointerImg: string;
29
+ pointerVisible: boolean;
29
30
  title: string;
30
31
  subTitle: string;
31
32
  taskId: string | undefined;
@@ -35,4 +36,5 @@ export interface FrameState {
35
36
  pointerMoved: boolean;
36
37
  rawProgress: number;
37
38
  }
39
+ export declare function shouldRenderCursor(pointerVisible: boolean, camera: CameraState, prevCamera: CameraState, imageWidth: number, imageHeight: number): boolean;
38
40
  export declare function deriveFrameState(scriptFrames: ScriptFrame[], frame: number, baseW: number, baseH: number, fps: number): FrameState;
@@ -1,4 +1,14 @@
1
+ import type { Rect } from '@midscene/core';
1
2
  import type { FrameMap } from './frame-calculator';
3
+ interface ExportOverlayViewport {
4
+ offsetX: number;
5
+ offsetY: number;
6
+ contentWidth: number;
7
+ contentHeight: number;
8
+ imageWidth: number;
9
+ imageHeight: number;
10
+ }
11
+ export declare function isExportRenderStalled(elapsedSinceLastFrameMs: number, frameDurationMs: number): boolean;
2
12
  export declare function resolveExportCamera(prevCamera: {
3
13
  left: number;
4
14
  top: number;
@@ -12,6 +22,12 @@ export declare function resolveExportCamera(prevCamera: {
12
22
  camTop: number;
13
23
  camWidth: number;
14
24
  };
25
+ export declare function projectNativeRectToExportViewport(rect: Rect, cameraTransform: {
26
+ zoom: number;
27
+ tx: number;
28
+ ty: number;
29
+ }, viewport: ExportOverlayViewport): Rect;
15
30
  export declare function exportBrandedVideo(frameMap: FrameMap, options?: {
16
31
  autoZoom?: boolean;
17
32
  }, onProgress?: (pct: number) => void): Promise<void>;
33
+ export {};
@@ -0,0 +1,20 @@
1
+ export declare const POINTER_WIDTH = 44;
2
+ export declare const POINTER_HEIGHT = 56;
3
+ export declare const POINTER_HOTSPOT_X = 6;
4
+ export declare const POINTER_HOTSPOT_Y = 4;
5
+ export interface PointerLayout {
6
+ scale: number;
7
+ width: number;
8
+ height: number;
9
+ hotspotX: number;
10
+ hotspotY: number;
11
+ centerOffsetX: number;
12
+ centerOffsetY: number;
13
+ }
14
+ export interface SpinnerLayout {
15
+ size: number;
16
+ centerOffset: number;
17
+ }
18
+ export declare function resolvePointerLayout(imageWidth: number): PointerLayout;
19
+ export declare function resolveExportPointerLayout(imageWidth: number, contentWidth: number): PointerLayout;
20
+ export declare function resolveSpinnerLayout(pointerLayout: PointerLayout): SpinnerLayout;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/visualizer",
3
- "version": "1.7.7-beta-20260429033400.0",
3
+ "version": "1.7.7",
4
4
  "repository": "https://github.com/web-infra-dev/midscene",
5
5
  "homepage": "https://midscenejs.com/",
6
6
  "types": "./dist/types/index.d.ts",
@@ -58,10 +58,10 @@
58
58
  "antd": "^5.21.6",
59
59
  "buffer": "6.0.3",
60
60
  "dayjs": "^1.11.11",
61
- "@midscene/playground": "1.7.7-beta-20260429033400.0",
62
- "@midscene/shared": "1.7.7-beta-20260429033400.0",
63
- "@midscene/core": "1.7.7-beta-20260429033400.0",
64
- "@midscene/web": "1.7.7-beta-20260429033400.0"
61
+ "@midscene/core": "1.7.7",
62
+ "@midscene/playground": "1.7.7",
63
+ "@midscene/web": "1.7.7",
64
+ "@midscene/shared": "1.7.7"
65
65
  },
66
66
  "license": "MIT",
67
67
  "scripts": {