@midscene/visualizer 1.5.2 → 1.5.3-beta-20260305031416.0

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 (43) hide show
  1. package/dist/es/component/blackboard/index.css +82 -4
  2. package/dist/es/component/blackboard/index.mjs +73 -301
  3. package/dist/es/component/player/index.css +144 -119
  4. package/dist/es/component/player/index.mjs +468 -830
  5. package/dist/es/component/player/remotion/StepScene.mjs +190 -0
  6. package/dist/es/component/player/remotion/derive-frame-state.mjs +207 -0
  7. package/dist/es/component/player/remotion/export-branded-video.mjs +210 -0
  8. package/dist/es/component/player/remotion/frame-calculator.mjs +149 -0
  9. package/dist/es/component/player/use-frame-player.mjs +88 -0
  10. package/dist/es/component/universal-playground/index.mjs +14 -1
  11. package/dist/es/hooks/usePlaygroundExecution.mjs +11 -7
  12. package/dist/es/index.mjs +2 -2
  13. package/dist/es/store/store.mjs +9 -0
  14. package/dist/es/utils/replay-scripts.mjs +78 -59
  15. package/dist/lib/component/blackboard/index.css +82 -4
  16. package/dist/lib/component/blackboard/index.js +73 -307
  17. package/dist/lib/component/player/index.css +144 -119
  18. package/dist/lib/component/player/index.js +466 -828
  19. package/dist/lib/component/player/remotion/StepScene.js +224 -0
  20. package/dist/lib/component/player/remotion/derive-frame-state.js +241 -0
  21. package/dist/lib/component/player/remotion/export-branded-video.js +244 -0
  22. package/dist/lib/component/player/remotion/frame-calculator.js +186 -0
  23. package/dist/lib/component/player/use-frame-player.js +122 -0
  24. package/dist/lib/component/universal-playground/index.js +14 -1
  25. package/dist/lib/hooks/usePlaygroundExecution.js +11 -7
  26. package/dist/lib/index.js +3 -0
  27. package/dist/lib/store/store.js +9 -0
  28. package/dist/lib/utils/replay-scripts.js +80 -58
  29. package/dist/types/component/blackboard/index.d.ts +0 -4
  30. package/dist/types/component/player/index.d.ts +0 -1
  31. package/dist/types/component/player/remotion/StepScene.d.ts +9 -0
  32. package/dist/types/component/player/remotion/derive-frame-state.d.ts +38 -0
  33. package/dist/types/component/player/remotion/export-branded-video.d.ts +2 -0
  34. package/dist/types/component/player/remotion/frame-calculator.d.ts +35 -0
  35. package/dist/types/component/player/use-frame-player.d.ts +17 -0
  36. package/dist/types/hooks/usePlaygroundExecution.d.ts +15 -1
  37. package/dist/types/index.d.ts +1 -1
  38. package/dist/types/store/store.d.ts +2 -0
  39. package/dist/types/utils/replay-scripts.d.ts +16 -1
  40. package/package.json +5 -8
  41. package/dist/es/utils/pixi-loader.mjs +0 -42
  42. package/dist/lib/utils/pixi-loader.js +0 -82
  43. package/dist/types/utils/pixi-loader.d.ts +0 -5
@@ -35,6 +35,7 @@ const ELEMENTS_VISIBLE_KEY = 'midscene-elements-visible';
35
35
  const MODEL_CALL_DETAILS_KEY = 'midscene-model-call-details';
36
36
  const DARK_MODE_KEY = 'midscene-dark-mode';
37
37
  const PLAYBACK_SPEED_KEY = 'midscene-playback-speed';
38
+ const SUBTITLE_ENABLED_KEY = 'midscene-subtitle-enabled';
38
39
  const parseBooleanParam = (value)=>{
39
40
  if (null === value) return;
40
41
  const normalized = value.trim().toLowerCase();
@@ -64,6 +65,7 @@ const useGlobalPreference = create((set)=>{
64
65
  const savedDarkMode = 'true' === localStorage.getItem(DARK_MODE_KEY);
65
66
  const parsedPlaybackSpeed = Number.parseFloat(localStorage.getItem(PLAYBACK_SPEED_KEY) || '1');
66
67
  const savedPlaybackSpeed = Number.isNaN(parsedPlaybackSpeed) ? 1 : parsedPlaybackSpeed;
68
+ const savedSubtitleEnabled = 'false' !== localStorage.getItem(SUBTITLE_ENABLED_KEY);
67
69
  const autoZoomFromQuery = getQueryPreference('focusOnCursor');
68
70
  const elementsVisibleFromQuery = getQueryPreference('showElementMarkers');
69
71
  const darkModeFromQuery = getQueryPreference('darkMode');
@@ -116,6 +118,13 @@ const useGlobalPreference = create((set)=>{
116
118
  playbackSpeed: speed
117
119
  });
118
120
  localStorage.setItem(PLAYBACK_SPEED_KEY, speed.toString());
121
+ },
122
+ subtitleEnabled: savedSubtitleEnabled,
123
+ setSubtitleEnabled: (enabled)=>{
124
+ set({
125
+ subtitleEnabled: enabled
126
+ });
127
+ localStorage.setItem(SUBTITLE_ENABLED_KEY, enabled.toString());
119
128
  }
120
129
  };
121
130
  });
@@ -28,6 +28,7 @@ __webpack_require__.d(__webpack_exports__, {
28
28
  generateAnimationScripts: ()=>generateAnimationScripts,
29
29
  mergeTwoCameraState: ()=>mergeTwoCameraState,
30
30
  cameraStateForRect: ()=>cameraStateForRect,
31
+ extractDumpMetaInfo: ()=>extractDumpMetaInfo,
31
32
  allScriptsFromDump: ()=>allScriptsFromDump
32
33
  });
33
34
  const external_index_js_namespaceObject = require("./index.js");
@@ -110,16 +111,9 @@ const mergeTwoCameraState = (cameraState1, cameraState2)=>{
110
111
  width: newWidth
111
112
  };
112
113
  };
113
- const allScriptsFromDump = (dump)=>{
114
- var _normalizedDump_executions, _normalizedDump_executions1, _normalizedDump_modelBriefs;
115
- if (!dump) {
116
- console.warn('[allScriptsFromDump] dump is empty');
117
- return {
118
- scripts: [],
119
- modelBriefs: []
120
- };
121
- }
122
- const normalizedDump = Array.isArray(dump.executions) ? dump : {
114
+ const normalizeDump = (dump)=>{
115
+ if (!dump) return null;
116
+ return Array.isArray(dump.executions) ? dump : {
123
117
  sdkVersion: '',
124
118
  groupName: 'Execution',
125
119
  modelBriefs: [],
@@ -127,7 +121,11 @@ const allScriptsFromDump = (dump)=>{
127
121
  dump
128
122
  ]
129
123
  };
130
- const dimensionsSet = new Set();
124
+ };
125
+ const extractDumpMetaInfo = (dump)=>{
126
+ var _normalizedDump_executions, _normalizedDump_modelBriefs;
127
+ const normalizedDump = normalizeDump(dump);
128
+ if (!normalizedDump) return null;
131
129
  let firstWidth;
132
130
  let firstHeight;
133
131
  const sdkVersion = normalizedDump.sdkVersion;
@@ -142,35 +140,17 @@ const allScriptsFromDump = (dump)=>{
142
140
  firstWidth = w;
143
141
  firstHeight = h;
144
142
  }
145
- dimensionsSet.add(`${w}x${h}`);
146
143
  }
147
- });
148
- });
149
- if (!firstWidth || !firstHeight) {
150
- console.warn('width or height is missing in dump file');
151
- return {
152
- scripts: [],
153
- sdkVersion,
154
- modelBriefs: []
155
- };
156
- }
157
- const allScripts = [];
158
- const executions = (null == (_normalizedDump_executions1 = normalizedDump.executions) ? void 0 : _normalizedDump_executions1.filter(Boolean)) || [];
159
- for(let execIndex = 0; execIndex < executions.length; execIndex++){
160
- const execution = executions[execIndex];
161
- const scripts = generateAnimationScripts(execution, -1, firstWidth, firstHeight, execIndex);
162
- if (scripts) allScripts.push(...scripts);
163
- execution.tasks.forEach((task)=>{
164
144
  if (task.usage) {
165
145
  const { model_name, model_description, intent } = task.usage;
166
146
  if (intent && model_name) modelBriefsSet.add(model_description ? `${intent}/${model_name}(${model_description})` : `${intent}/${model_name}`);
167
147
  }
168
148
  });
169
- }
170
- const allScriptsWithoutIntermediateDoneFrame = allScripts.filter((script, index)=>{
171
- if (index !== allScripts.length - 1 && 'Done' === script.title) return false;
172
- return true;
173
149
  });
150
+ if (!firstWidth || !firstHeight) {
151
+ console.warn('width or height is missing in dump file');
152
+ return null;
153
+ }
174
154
  const normalizedModelBriefs = (null == (_normalizedDump_modelBriefs = normalizedDump.modelBriefs) ? void 0 : _normalizedDump_modelBriefs.length) ? normalizedDump.modelBriefs : [];
175
155
  const modelBriefs = (()=>{
176
156
  var _list_;
@@ -185,11 +165,48 @@ const allScriptsFromDump = (dump)=>{
185
165
  return list;
186
166
  })();
187
167
  return {
188
- scripts: allScriptsWithoutIntermediateDoneFrame,
189
168
  width: firstWidth,
190
169
  height: firstHeight,
191
170
  sdkVersion,
192
- modelBriefs
171
+ modelBriefs,
172
+ deviceType: normalizedDump.deviceType
173
+ };
174
+ };
175
+ const allScriptsFromDump = (dump)=>{
176
+ var _normalizedDump_executions;
177
+ const normalizedDump = normalizeDump(dump);
178
+ if (!normalizedDump) {
179
+ console.warn('[allScriptsFromDump] dump is empty');
180
+ return {
181
+ scripts: [],
182
+ modelBriefs: []
183
+ };
184
+ }
185
+ const metaInfo = extractDumpMetaInfo(dump);
186
+ if (!metaInfo) return {
187
+ scripts: [],
188
+ sdkVersion: normalizedDump.sdkVersion,
189
+ modelBriefs: []
190
+ };
191
+ const { width: firstWidth, height: firstHeight } = metaInfo;
192
+ const allScripts = [];
193
+ const executions = (null == (_normalizedDump_executions = normalizedDump.executions) ? void 0 : _normalizedDump_executions.filter(Boolean)) || [];
194
+ for(let execIndex = 0; execIndex < executions.length; execIndex++){
195
+ const execution = executions[execIndex];
196
+ const scripts = generateAnimationScripts(execution, -1, firstWidth, firstHeight, execIndex);
197
+ if (scripts) allScripts.push(...scripts);
198
+ }
199
+ const allScriptsWithoutIntermediateDoneFrame = allScripts.filter((script, index)=>{
200
+ if (index !== allScripts.length - 1 && 'Done' === script.title) return false;
201
+ return true;
202
+ });
203
+ return {
204
+ scripts: allScriptsWithoutIntermediateDoneFrame,
205
+ width: firstWidth,
206
+ height: firstHeight,
207
+ sdkVersion: metaInfo.sdkVersion,
208
+ modelBriefs: metaInfo.modelBriefs,
209
+ deviceType: metaInfo.deviceType
193
210
  };
194
211
  };
195
212
  const generateAnimationScripts = (execution, task, imageWidth, imageHeight, executionIndex = 0)=>{
@@ -228,6 +245,19 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
228
245
  subTitle,
229
246
  taskId
230
247
  });
248
+ const createScript = (base, screenshot)=>{
249
+ if (!screenshot) return base;
250
+ const script = _object_spread({}, base);
251
+ let cachedImg;
252
+ Object.defineProperty(script, 'img', {
253
+ get () {
254
+ if (void 0 === cachedImg) cachedImg = screenshot.base64;
255
+ return cachedImg;
256
+ },
257
+ enumerable: true
258
+ });
259
+ return script;
260
+ };
231
261
  const scripts = [];
232
262
  let insightCameraState;
233
263
  let insightOnTop = false;
@@ -271,17 +301,16 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
271
301
  var _context_shotSize, _context_shotSize1;
272
302
  const width = (null == (_context_shotSize = context.shotSize) ? void 0 : _context_shotSize.width) || imageWidth;
273
303
  const height = (null == (_context_shotSize1 = context.shotSize) ? void 0 : _context_shotSize1.height) || imageHeight;
274
- const screenshotData = context.screenshot.base64;
275
- scripts.push({
304
+ const contextScreenshot = context.screenshot;
305
+ scripts.push(createScript({
276
306
  type: 'img',
277
- img: screenshotData,
278
307
  duration: stillAfterInsightDuration,
279
308
  title,
280
309
  subTitle,
281
310
  imageWidth: width,
282
311
  imageHeight: height,
283
312
  taskId: currentTaskId
284
- });
313
+ }, contextScreenshot));
285
314
  locateElements.forEach((element)=>{
286
315
  var _task_log_taskInfo, _task_log, _context_shotSize, _context_shotSize1;
287
316
  insightCameraState = _object_spread_props(_object_spread({}, cameraStateForRect(element.rect, width, height)), {
@@ -289,9 +318,8 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
289
318
  pointerTop: element.center[1]
290
319
  });
291
320
  const newCameraState = insightCameraState;
292
- scripts.push({
321
+ scripts.push(createScript({
293
322
  type: 'insight',
294
- img: screenshotData,
295
323
  context: context,
296
324
  camera: newCameraState,
297
325
  highlightElement: element,
@@ -303,7 +331,7 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
303
331
  imageWidth: (null == (_context_shotSize = context.shotSize) ? void 0 : _context_shotSize.width) || imageWidth,
304
332
  imageHeight: (null == (_context_shotSize1 = context.shotSize) ? void 0 : _context_shotSize1.height) || imageHeight,
305
333
  taskId: currentTaskId
306
- });
334
+ }, contextScreenshot));
307
335
  insightOnTop = true;
308
336
  });
309
337
  }
@@ -311,17 +339,15 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
311
339
  if (planningTask.recorder && planningTask.recorder.length > 0) {
312
340
  var _planningTask_recorder_, _task_uiContext_shotSize, _task_uiContext, _task_uiContext_shotSize1, _task_uiContext1;
313
341
  const screenshot = null == (_planningTask_recorder_ = planningTask.recorder[0]) ? void 0 : _planningTask_recorder_.screenshot;
314
- const screenshotData = (null == screenshot ? void 0 : screenshot.base64) || '';
315
- scripts.push({
342
+ scripts.push(createScript({
316
343
  type: 'img',
317
- img: screenshotData,
318
344
  duration: stillDuration,
319
345
  title: (0, agent_namespaceObject.typeStr)(task),
320
346
  subTitle: (0, agent_namespaceObject.paramStr)(task),
321
347
  imageWidth: (null == (_task_uiContext = task.uiContext) ? void 0 : null == (_task_uiContext_shotSize = _task_uiContext.shotSize) ? void 0 : _task_uiContext_shotSize.width) || imageWidth,
322
348
  imageHeight: (null == (_task_uiContext1 = task.uiContext) ? void 0 : null == (_task_uiContext_shotSize1 = _task_uiContext1.shotSize) ? void 0 : _task_uiContext_shotSize1.height) || imageHeight,
323
349
  taskId: currentTaskId
324
- });
350
+ }, screenshot));
325
351
  }
326
352
  } else if ('Action Space' === task.type) {
327
353
  var _task_recorder_, _task_recorder, _task_uiContext_shotSize2, _task_uiContext2, _task_uiContext_shotSize3, _task_uiContext3;
@@ -346,10 +372,8 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
346
372
  }
347
373
  scripts.push(setPointerScript(external_index_js_namespaceObject.mousePointer, title, subTitle, currentTaskId));
348
374
  const screenshot = null == (_task_recorder = task.recorder) ? void 0 : null == (_task_recorder_ = _task_recorder[0]) ? void 0 : _task_recorder_.screenshot;
349
- const actionScreenshotData = (null == screenshot ? void 0 : screenshot.base64) || '';
350
- scripts.push({
375
+ scripts.push(createScript({
351
376
  type: 'img',
352
- img: actionScreenshotData,
353
377
  duration: actionDuration,
354
378
  camera: 'Sleep' === task.subType ? fullPageCameraState : void 0,
355
379
  title,
@@ -357,7 +381,7 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
357
381
  imageWidth: (null == (_task_uiContext2 = task.uiContext) ? void 0 : null == (_task_uiContext_shotSize2 = _task_uiContext2.shotSize) ? void 0 : _task_uiContext_shotSize2.width) || imageWidth,
358
382
  imageHeight: (null == (_task_uiContext3 = task.uiContext) ? void 0 : null == (_task_uiContext_shotSize3 = _task_uiContext3.shotSize) ? void 0 : _task_uiContext_shotSize3.height) || imageHeight,
359
383
  taskId: currentTaskId
360
- });
384
+ }, screenshot));
361
385
  } else {
362
386
  var _task_recorder_1, _task_recorder1;
363
387
  const title = (0, agent_namespaceObject.typeStr)(task);
@@ -365,10 +389,8 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
365
389
  const screenshot = null == (_task_recorder1 = task.recorder) ? void 0 : null == (_task_recorder_1 = _task_recorder1[task.recorder.length - 1]) ? void 0 : _task_recorder_1.screenshot;
366
390
  if (screenshot) {
367
391
  var _task_uiContext_shotSize4, _task_uiContext4, _task_uiContext_shotSize5, _task_uiContext5;
368
- const screenshotData = screenshot.base64;
369
- scripts.push({
392
+ scripts.push(createScript({
370
393
  type: 'img',
371
- img: screenshotData,
372
394
  duration: stillDuration,
373
395
  camera: fullPageCameraState,
374
396
  title,
@@ -376,7 +398,7 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
376
398
  imageWidth: (null == (_task_uiContext4 = task.uiContext) ? void 0 : null == (_task_uiContext_shotSize4 = _task_uiContext4.shotSize) ? void 0 : _task_uiContext_shotSize4.width) || imageWidth,
377
399
  imageHeight: (null == (_task_uiContext5 = task.uiContext) ? void 0 : null == (_task_uiContext_shotSize5 = _task_uiContext5.shotSize) ? void 0 : _task_uiContext_shotSize5.height) || imageHeight,
378
400
  taskId: currentTaskId
379
- });
401
+ }, screenshot));
380
402
  }
381
403
  }
382
404
  if ('finished' !== task.status) {
@@ -385,10 +407,8 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
385
407
  const errorMsg = task.errorMessage || 'unknown error';
386
408
  const errorSubTitle = errorMsg.indexOf('NOT_IMPLEMENTED_AS_DESIGNED') > 0 ? 'Further actions cannot be performed in the current environment' : errorMsg;
387
409
  const screenshot = null == (_task_recorder2 = task.recorder) ? void 0 : null == (_task_recorder_2 = _task_recorder2[task.recorder.length - 1]) ? void 0 : _task_recorder_2.screenshot;
388
- const errorScreenshotData = (null == screenshot ? void 0 : screenshot.base64) || '';
389
- scripts.push({
410
+ scripts.push(createScript({
390
411
  type: 'img',
391
- img: errorScreenshotData,
392
412
  camera: fullPageCameraState,
393
413
  duration: stillDuration,
394
414
  title: errorTitle,
@@ -396,7 +416,7 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
396
416
  imageWidth: (null == (_task_uiContext6 = task.uiContext) ? void 0 : null == (_task_uiContext_shotSize6 = _task_uiContext6.shotSize) ? void 0 : _task_uiContext_shotSize6.width) || imageWidth,
397
417
  imageHeight: (null == (_task_uiContext7 = task.uiContext) ? void 0 : null == (_task_uiContext_shotSize7 = _task_uiContext7.shotSize) ? void 0 : _task_uiContext_shotSize7.height) || imageHeight,
398
418
  taskId: currentTaskId
399
- });
419
+ }, screenshot));
400
420
  }
401
421
  });
402
422
  scripts.push({
@@ -411,11 +431,13 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight, exec
411
431
  };
412
432
  exports.allScriptsFromDump = __webpack_exports__.allScriptsFromDump;
413
433
  exports.cameraStateForRect = __webpack_exports__.cameraStateForRect;
434
+ exports.extractDumpMetaInfo = __webpack_exports__.extractDumpMetaInfo;
414
435
  exports.generateAnimationScripts = __webpack_exports__.generateAnimationScripts;
415
436
  exports.mergeTwoCameraState = __webpack_exports__.mergeTwoCameraState;
416
437
  for(var __rspack_i in __webpack_exports__)if (-1 === [
417
438
  "allScriptsFromDump",
418
439
  "cameraStateForRect",
440
+ "extractDumpMetaInfo",
419
441
  "generateAnimationScripts",
420
442
  "mergeTwoCameraState"
421
443
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
@@ -1,9 +1,5 @@
1
- import 'pixi.js/unsafe-eval';
2
1
  import type { BaseElement, Rect, UIContext } from '@midscene/core';
3
- import * as PIXI from 'pixi.js';
4
2
  import './index.less';
5
- export declare const pointMarkForItem: (point: [number, number], type: "highlightPoint") => PIXI.Graphics;
6
- export declare const rectMarkForItem: (rect: Rect, name: string, type: "element" | "searchArea" | "highlight") => (PIXI.Graphics | PIXI.Text)[];
7
3
  export declare const Blackboard: (props: {
8
4
  uiContext: UIContext | undefined | null;
9
5
  highlightElements?: BaseElement[];
@@ -1,4 +1,3 @@
1
- import 'pixi.js/unsafe-eval';
2
1
  import './index.less';
3
2
  import type { AnimationScript } from '../../utils/replay-scripts';
4
3
  export declare function Player(props?: {
@@ -0,0 +1,9 @@
1
+ import type { FrameMap } from './frame-calculator';
2
+ export declare const StepsTimeline: React.FC<{
3
+ frameMap: FrameMap;
4
+ autoZoom: boolean;
5
+ frame: number;
6
+ width: number;
7
+ height: number;
8
+ fps: number;
9
+ }>;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Shared frame state derivation from ScriptFrame timeline.
3
+ * Used by both Remotion preview (StepScene.tsx) and Canvas export (export-branded-video.ts).
4
+ */
5
+ import type { ScriptFrame } from './frame-calculator';
6
+ export interface CameraState {
7
+ left: number;
8
+ top: number;
9
+ width: number;
10
+ pointerLeft: number;
11
+ pointerTop: number;
12
+ }
13
+ export interface InsightOverlay {
14
+ highlightElement?: ScriptFrame['highlightElement'];
15
+ searchArea?: ScriptFrame['searchArea'];
16
+ alpha: number;
17
+ }
18
+ export interface FrameState {
19
+ img: string;
20
+ imageWidth: number;
21
+ imageHeight: number;
22
+ prevImg: string | null;
23
+ camera: CameraState;
24
+ prevCamera: CameraState;
25
+ insights: InsightOverlay[];
26
+ spinning: boolean;
27
+ spinningElapsedMs: number;
28
+ currentPointerImg: string;
29
+ title: string;
30
+ subTitle: string;
31
+ taskId: string | undefined;
32
+ frameInScript: number;
33
+ scriptIndex: number;
34
+ imageChanged: boolean;
35
+ pointerMoved: boolean;
36
+ rawProgress: number;
37
+ }
38
+ export declare function deriveFrameState(scriptFrames: ScriptFrame[], frame: number, baseW: number, baseH: number, fps: number): FrameState;
@@ -0,0 +1,2 @@
1
+ import type { FrameMap } from './frame-calculator';
2
+ export declare function exportBrandedVideo(frameMap: FrameMap, onProgress?: (pct: number) => void): Promise<void>;
@@ -0,0 +1,35 @@
1
+ import type { LocateResultElement, Rect } from '@midscene/core';
2
+ import type { AnimationScript } from '../../../utils/replay-scripts';
3
+ export declare const FPS = 30;
4
+ export interface ScriptFrame {
5
+ type: 'img' | 'insight' | 'clear-insight' | 'pointer' | 'spinning-pointer' | 'sleep';
6
+ startFrame: number;
7
+ durationInFrames: number;
8
+ img?: string;
9
+ imageWidth?: number;
10
+ imageHeight?: number;
11
+ cameraTarget?: {
12
+ left: number;
13
+ top: number;
14
+ width: number;
15
+ pointerLeft: number;
16
+ pointerTop: number;
17
+ };
18
+ insightPhaseFrames?: number;
19
+ cameraPhaseFrames?: number;
20
+ highlightElement?: LocateResultElement;
21
+ searchArea?: Rect;
22
+ pointerImg?: string;
23
+ title?: string;
24
+ subTitle?: string;
25
+ taskId?: string;
26
+ }
27
+ export interface FrameMap {
28
+ scriptFrames: ScriptFrame[];
29
+ totalDurationInFrames: number;
30
+ fps: number;
31
+ stepsDurationInFrames: number;
32
+ imageWidth: number;
33
+ imageHeight: number;
34
+ }
35
+ export declare function calculateFrameMap(scripts: AnimationScript[]): FrameMap;
@@ -0,0 +1,17 @@
1
+ interface UseFramePlayerOptions {
2
+ durationInFrames: number;
3
+ fps: number;
4
+ autoPlay?: boolean;
5
+ loop?: boolean;
6
+ playbackRate?: number;
7
+ }
8
+ interface FramePlayer {
9
+ currentFrame: number;
10
+ playing: boolean;
11
+ play: () => void;
12
+ pause: () => void;
13
+ toggle: () => void;
14
+ seekTo: (frame: number) => void;
15
+ }
16
+ export declare function useFramePlayer(options: UseFramePlayerOptions): FramePlayer;
17
+ export {};
@@ -1,9 +1,23 @@
1
1
  import type { DeviceAction } from '@midscene/core';
2
2
  import type { FormValue, InfoListItem, PlaygroundSDKLike, StorageProvider } from '../types';
3
+ export interface UsePlaygroundExecutionOptions {
4
+ playgroundSDK: PlaygroundSDKLike | null;
5
+ storage: StorageProvider | undefined | null;
6
+ actionSpace: DeviceAction<unknown>[];
7
+ loading: boolean;
8
+ setLoading: (loading: boolean) => void;
9
+ setInfoList: React.Dispatch<React.SetStateAction<InfoListItem[]>>;
10
+ replayCounter: number;
11
+ setReplayCounter: React.Dispatch<React.SetStateAction<number>>;
12
+ verticalMode: boolean;
13
+ currentRunningIdRef: React.MutableRefObject<number | null>;
14
+ interruptedFlagRef: React.MutableRefObject<Record<number, boolean>>;
15
+ deviceType?: string;
16
+ }
3
17
  /**
4
18
  * Hook for handling playground execution logic
5
19
  */
6
- export declare function usePlaygroundExecution(playgroundSDK: PlaygroundSDKLike | null, storage: StorageProvider | undefined | null, actionSpace: DeviceAction<unknown>[], loading: boolean, setLoading: (loading: boolean) => void, setInfoList: React.Dispatch<React.SetStateAction<InfoListItem[]>>, replayCounter: number, setReplayCounter: React.Dispatch<React.SetStateAction<number>>, verticalMode: boolean, currentRunningIdRef: React.MutableRefObject<number | null>, interruptedFlagRef: React.MutableRefObject<Record<number, boolean>>): {
20
+ export declare function usePlaygroundExecution(options: UsePlaygroundExecutionOptions): {
7
21
  handleRun: (value: FormValue) => Promise<void>;
8
22
  handleStop: () => Promise<void>;
9
23
  canStop: boolean;
@@ -1,4 +1,4 @@
1
- export { type AnimationScript, type ReplayScriptsInfo, allScriptsFromDump, generateAnimationScripts, } from './utils/replay-scripts';
1
+ export { type AnimationScript, type DumpMetaInfo, type ReplayScriptsInfo, allScriptsFromDump, extractDumpMetaInfo, generateAnimationScripts, } from './utils/replay-scripts';
2
2
  export { useEnvConfig, useGlobalPreference } from './store/store';
3
3
  export { colorForName, highlightColorForType, globalThemeConfig, } from './utils/color';
4
4
  export { EnvConfig } from './component/env-config';
@@ -7,12 +7,14 @@ export declare const useGlobalPreference: Z.UseBoundStore<Z.StoreApi<{
7
7
  modelCallDetailsEnabled: boolean;
8
8
  darkModeEnabled: boolean;
9
9
  playbackSpeed: PlaybackSpeedType;
10
+ subtitleEnabled: boolean;
10
11
  setBackgroundVisible: (visible: boolean) => void;
11
12
  setElementsVisible: (visible: boolean) => void;
12
13
  setAutoZoom: (enabled: boolean) => void;
13
14
  setModelCallDetailsEnabled: (enabled: boolean) => void;
14
15
  setDarkModeEnabled: (enabled: boolean) => void;
15
16
  setPlaybackSpeed: (speed: PlaybackSpeedType) => void;
17
+ setSubtitleEnabled: (enabled: boolean) => void;
16
18
  }>>;
17
19
  /**
18
20
  * Service Mode
@@ -30,6 +30,21 @@ export interface ReplayScriptsInfo {
30
30
  height?: number;
31
31
  sdkVersion?: string;
32
32
  modelBriefs: string[];
33
+ deviceType?: string;
33
34
  }
34
- export declare const allScriptsFromDump: (dump: GroupedActionDump | IGroupedActionDump | ExecutionDump | null | undefined) => ReplayScriptsInfo | null;
35
+ type DumpInput = GroupedActionDump | IGroupedActionDump | ExecutionDump | null | undefined;
36
+ export interface DumpMetaInfo {
37
+ width: number;
38
+ height: number;
39
+ sdkVersion?: string;
40
+ modelBriefs: string[];
41
+ deviceType?: string;
42
+ }
43
+ /**
44
+ * Extract lightweight metadata from dump without reading any .base64 fields.
45
+ * Used to set up the UI (dimensions, version, model info) before replay.
46
+ */
47
+ export declare const extractDumpMetaInfo: (dump: DumpInput) => DumpMetaInfo | null;
48
+ export declare const allScriptsFromDump: (dump: DumpInput) => ReplayScriptsInfo | null;
35
49
  export declare const generateAnimationScripts: (execution: ExecutionDump | IExecutionDump | null, task: ExecutionTask | number, imageWidth: number, imageHeight: number, executionIndex?: number) => AnimationScript[] | null;
50
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/visualizer",
3
- "version": "1.5.2",
3
+ "version": "1.5.3-beta-20260305031416.0",
4
4
  "repository": "https://github.com/web-infra-dev/midscene",
5
5
  "homepage": "https://midscenejs.com/",
6
6
  "types": "./dist/types/index.d.ts",
@@ -23,7 +23,6 @@
23
23
  "react-dom": ">=19.1.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@pixi/unsafe-eval": "7.4.2",
27
26
  "@rsbuild/plugin-less": "^1.5.0",
28
27
  "@rsbuild/plugin-node-polyfill": "1.4.2",
29
28
  "@rsbuild/plugin-react": "^1.4.1",
@@ -35,8 +34,6 @@
35
34
  "@types/react-dom": "^18.3.1",
36
35
  "execa": "9.3.0",
37
36
  "http-server": "14.1.1",
38
- "pixi-filters": "6.0.5",
39
- "pixi.js": "8.1.1",
40
37
  "query-string": "9.1.1",
41
38
  "react": "18.3.1",
42
39
  "react-dom": "18.3.1",
@@ -60,10 +57,10 @@
60
57
  "antd": "^5.21.6",
61
58
  "buffer": "6.0.3",
62
59
  "dayjs": "^1.11.11",
63
- "@midscene/playground": "1.5.2",
64
- "@midscene/core": "1.5.2",
65
- "@midscene/shared": "1.5.2",
66
- "@midscene/web": "1.5.2"
60
+ "@midscene/core": "1.5.3-beta-20260305031416.0",
61
+ "@midscene/playground": "1.5.3-beta-20260305031416.0",
62
+ "@midscene/shared": "1.5.3-beta-20260305031416.0",
63
+ "@midscene/web": "1.5.3-beta-20260305031416.0"
67
64
  },
68
65
  "license": "MIT",
69
66
  "scripts": {
@@ -1,42 +0,0 @@
1
- import "pixi.js/unsafe-eval";
2
- import { Assets } from "pixi.js";
3
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
4
- try {
5
- var info = gen[key](arg);
6
- var value = info.value;
7
- } catch (error) {
8
- reject(error);
9
- return;
10
- }
11
- if (info.done) resolve(value);
12
- else Promise.resolve(value).then(_next, _throw);
13
- }
14
- function _async_to_generator(fn) {
15
- return function() {
16
- var self = this, args = arguments;
17
- return new Promise(function(resolve, reject) {
18
- var gen = fn.apply(self, args);
19
- function _next(value) {
20
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
21
- }
22
- function _throw(err) {
23
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
24
- }
25
- _next(void 0);
26
- });
27
- };
28
- }
29
- const globalTextureMap = new Map();
30
- const loadTexture = (img)=>_async_to_generator(function*() {
31
- if (globalTextureMap.has(img)) return;
32
- return Assets.load(img).then((texture)=>{
33
- globalTextureMap.set(img, texture);
34
- });
35
- })();
36
- const getTextureFromCache = (name)=>globalTextureMap.get(name);
37
- const getTexture = (name)=>_async_to_generator(function*() {
38
- if (globalTextureMap.has(name)) return globalTextureMap.get(name);
39
- yield loadTexture(name);
40
- return globalTextureMap.get(name);
41
- })();
42
- export { getTexture, getTextureFromCache, loadTexture };