@midscene/visualizer 1.3.7 → 1.3.8-beta-20260206024209.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.
@@ -209,3 +209,33 @@
209
209
  background: rgba(255, 255, 255, .08);
210
210
  }
211
211
 
212
+ .player-settings-dropdown {
213
+ background-color: #fff;
214
+ border: 1px solid rgba(0, 0, 0, .08);
215
+ border-radius: 8px;
216
+ padding: 4px;
217
+ overflow: hidden;
218
+ box-shadow: 0 2px 8px rgba(0, 0, 0, .08);
219
+ }
220
+
221
+ .player-settings-divider {
222
+ background: rgba(0, 0, 0, .06);
223
+ height: 1px;
224
+ margin: 4px 0;
225
+ }
226
+
227
+ .player-speed-option:hover, .player-settings-item:hover {
228
+ background: rgba(0, 0, 0, .04);
229
+ }
230
+
231
+ [data-theme="dark"] .player-settings-dropdown {
232
+ color: #f8fafd;
233
+ background-color: #1f1f1f;
234
+ border-color: rgba(255, 255, 255, .08);
235
+ box-shadow: 0 2px 8px rgba(0, 0, 0, .3);
236
+ }
237
+
238
+ [data-theme="dark"] .player-settings-divider, [data-theme="dark"] .player-speed-option:hover, [data-theme="dark"] .player-settings-item:hover {
239
+ background: rgba(255, 255, 255, .08);
240
+ }
241
+
@@ -5,7 +5,7 @@ import { Application, Container, Sprite } from "pixi.js";
5
5
  import { useEffect, useMemo, useRef, useState } from "react";
6
6
  import "./index.css";
7
7
  import { mouseLoading, mousePointer } from "../../utils/index.mjs";
8
- import { CaretRightOutlined, DownloadOutlined, ExportOutlined, LoadingOutlined } from "@ant-design/icons";
8
+ import { CaretRightOutlined, DownloadOutlined, ExportOutlined, LoadingOutlined, ThunderboltOutlined } from "@ant-design/icons";
9
9
  import { Dropdown, Spin, Switch, Tooltip, message } from "antd";
10
10
  import global_perspective from "../../icons/global-perspective.mjs";
11
11
  import player_setting from "../../icons/player-setting.mjs";
@@ -204,7 +204,7 @@ function Player(props) {
204
204
  var _scripts_;
205
205
  const [titleText, setTitleText] = useState('');
206
206
  const [subTitleText, setSubTitleText] = useState('');
207
- const { autoZoom, setAutoZoom } = useGlobalPreference();
207
+ const { autoZoom, setAutoZoom, playbackSpeed, setPlaybackSpeed } = useGlobalPreference();
208
208
  useEffect(()=>{
209
209
  if ((null == props ? void 0 : props.autoZoom) !== void 0) setAutoZoom(props.autoZoom);
210
210
  }, [
@@ -549,7 +549,9 @@ function Player(props) {
549
549
  var _scripts_;
550
550
  if (!app || !appInitialized.current) throw new Error('app is not initialized');
551
551
  if (!scripts) throw new Error("scripts is required");
552
- const { frame, cancel, timeout, sleep } = frameKit();
552
+ const { frame, cancel, timeout, sleep: baseSleep } = frameKit();
553
+ const scaleByPlaybackSpeed = (duration)=>duration / playbackSpeed;
554
+ const sleep = (ms)=>baseSleep(scaleByPlaybackSpeed(ms));
553
555
  cancelFn = cancel;
554
556
  cancelAnimationRef.current = cancel;
555
557
  const allImages = scripts.filter((item)=>!!item.img).map((item)=>item.img);
@@ -562,7 +564,7 @@ function Player(props) {
562
564
  yield updatePointer(mousePointer, imageWidth / 2, imageHeight / 2);
563
565
  yield repaintImage();
564
566
  yield updateCamera(_object_spread({}, basicCameraState));
565
- const totalDuration = scripts.reduce((acc, item)=>acc + item.duration + (item.camera && item.insightCameraDuration ? item.insightCameraDuration : 0), 0);
567
+ const totalDuration = scaleByPlaybackSpeed(scripts.reduce((acc, item)=>acc + item.duration + (item.camera && item.insightCameraDuration ? item.insightCameraDuration : 0), 0));
566
568
  const progressUpdateInterval = 200;
567
569
  const startTime = performance.now();
568
570
  setAnimationProgress(0);
@@ -598,13 +600,13 @@ function Player(props) {
598
600
  const highlightElements = item.highlightElement ? [
599
601
  item.highlightElement
600
602
  ] : [];
601
- yield insightElementsAnimation([], highlightElements, item.searchArea, item.duration, frame);
603
+ yield insightElementsAnimation([], highlightElements, item.searchArea, scaleByPlaybackSpeed(item.duration), frame);
602
604
  if (item.camera) {
603
605
  if (!item.insightCameraDuration) throw new Error('insightCameraDuration is required');
604
- yield cameraAnimation(item.camera, item.insightCameraDuration, frame);
606
+ yield cameraAnimation(item.camera, scaleByPlaybackSpeed(item.insightCameraDuration), frame);
605
607
  }
606
608
  } else if ('clear-insight' === item.type) {
607
- yield fadeOutItem(insightMarkContainer, item.duration, frame);
609
+ yield fadeOutItem(insightMarkContainer, scaleByPlaybackSpeed(item.duration), frame);
608
610
  insightMarkContainer.removeChildren();
609
611
  insightMarkContainer.alpha = 1;
610
612
  } else if ('img' === item.type) {
@@ -612,7 +614,7 @@ function Player(props) {
612
614
  currentImg.current = item.img;
613
615
  yield repaintImage(item.imageWidth, item.imageHeight);
614
616
  }
615
- if (item.camera) yield cameraAnimation(item.camera, item.duration, frame);
617
+ if (item.camera) yield cameraAnimation(item.camera, scaleByPlaybackSpeed(item.duration), frame);
616
618
  else yield sleep(item.duration);
617
619
  } else if ('pointer' === item.type) {
618
620
  if (!item.img) throw new Error('pointer img is required');
@@ -810,36 +812,18 @@ function Player(props) {
810
812
  overlayStyle: {
811
813
  minWidth: '148px'
812
814
  },
813
- dropdownRender: (menu)=>/*#__PURE__*/ jsx("div", {
814
- style: {
815
- borderRadius: '8px',
816
- border: '1px solid rgba(0, 0, 0, 0.08)',
817
- backgroundColor: '#fff',
818
- boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)',
819
- overflow: 'hidden'
820
- },
821
- children: menu
822
- }),
823
- menu: {
824
- style: {
825
- borderRadius: '8px',
826
- padding: 0
827
- },
828
- items: [
829
- {
830
- key: 'autoZoom',
831
- style: {
832
- height: '39px',
833
- margin: 0,
834
- padding: '0 12px'
835
- },
836
- label: /*#__PURE__*/ jsxs("div", {
815
+ dropdownRender: ()=>/*#__PURE__*/ jsxs("div", {
816
+ className: "player-settings-dropdown",
817
+ children: [
818
+ /*#__PURE__*/ jsxs("div", {
819
+ className: "player-settings-item",
837
820
  style: {
838
821
  display: 'flex',
839
822
  alignItems: 'center',
840
823
  justifyContent: 'space-between',
841
- width: '100%',
842
- height: '39px'
824
+ height: '32px',
825
+ padding: '0 8px',
826
+ borderRadius: '4px'
843
827
  },
844
828
  children: [
845
829
  /*#__PURE__*/ jsxs("div", {
@@ -870,16 +854,65 @@ function Player(props) {
870
854
  onChange: (checked)=>{
871
855
  setAutoZoom(checked);
872
856
  triggerReplay();
873
- },
874
- onClick: (_, e)=>{
875
- var _e_stopPropagation;
876
- return null == e ? void 0 : null == (_e_stopPropagation = e.stopPropagation) ? void 0 : _e_stopPropagation.call(e);
877
857
  }
878
858
  })
879
859
  ]
880
- })
881
- }
882
- ]
860
+ }),
861
+ /*#__PURE__*/ jsx("div", {
862
+ className: "player-settings-divider"
863
+ }),
864
+ /*#__PURE__*/ jsxs("div", {
865
+ style: {
866
+ display: 'flex',
867
+ alignItems: 'center',
868
+ gap: '4px',
869
+ height: '32px',
870
+ padding: '0 8px'
871
+ },
872
+ children: [
873
+ /*#__PURE__*/ jsx(ThunderboltOutlined, {
874
+ style: {
875
+ width: '16px',
876
+ height: '16px'
877
+ }
878
+ }),
879
+ /*#__PURE__*/ jsx("span", {
880
+ style: {
881
+ fontSize: '12px'
882
+ },
883
+ children: "Playback speed"
884
+ })
885
+ ]
886
+ }),
887
+ [
888
+ 0.5,
889
+ 1,
890
+ 1.5,
891
+ 2
892
+ ].map((speed)=>/*#__PURE__*/ jsxs("div", {
893
+ onClick: ()=>{
894
+ setPlaybackSpeed(speed);
895
+ triggerReplay();
896
+ },
897
+ style: {
898
+ height: '32px',
899
+ lineHeight: '32px',
900
+ padding: '0 8px 0 24px',
901
+ fontSize: '12px',
902
+ fontWeight: playbackSpeed === speed ? 600 : 'normal',
903
+ cursor: 'pointer',
904
+ borderRadius: '4px'
905
+ },
906
+ className: "player-speed-option",
907
+ children: [
908
+ speed,
909
+ "x"
910
+ ]
911
+ }, speed))
912
+ ]
913
+ }),
914
+ menu: {
915
+ items: []
883
916
  },
884
917
  children: /*#__PURE__*/ jsx("div", {
885
918
  className: "status-icon",
@@ -32,6 +32,7 @@ const BACKGROUND_VISIBLE_KEY = 'midscene-background-visible';
32
32
  const ELEMENTS_VISIBLE_KEY = 'midscene-elements-visible';
33
33
  const MODEL_CALL_DETAILS_KEY = 'midscene-model-call-details';
34
34
  const DARK_MODE_KEY = 'midscene-dark-mode';
35
+ const PLAYBACK_SPEED_KEY = 'midscene-playback-speed';
35
36
  const parseBooleanParam = (value)=>{
36
37
  if (null === value) return;
37
38
  const normalized = value.trim().toLowerCase();
@@ -59,6 +60,8 @@ const useGlobalPreference = store_create((set)=>{
59
60
  const savedElementsVisible = 'false' !== localStorage.getItem(ELEMENTS_VISIBLE_KEY);
60
61
  const savedModelCallDetails = 'true' === localStorage.getItem(MODEL_CALL_DETAILS_KEY);
61
62
  const savedDarkMode = 'true' === localStorage.getItem(DARK_MODE_KEY);
63
+ const parsedPlaybackSpeed = Number.parseFloat(localStorage.getItem(PLAYBACK_SPEED_KEY) || '1');
64
+ const savedPlaybackSpeed = Number.isNaN(parsedPlaybackSpeed) ? 1 : parsedPlaybackSpeed;
62
65
  const autoZoomFromQuery = getQueryPreference('focusOnCursor');
63
66
  const elementsVisibleFromQuery = getQueryPreference('showElementMarkers');
64
67
  const darkModeFromQuery = getQueryPreference('darkMode');
@@ -70,6 +73,12 @@ const useGlobalPreference = store_create((set)=>{
70
73
  autoZoom: void 0 === autoZoomFromQuery ? savedAutoZoom : autoZoomFromQuery,
71
74
  modelCallDetailsEnabled: savedModelCallDetails,
72
75
  darkModeEnabled: initialDarkMode,
76
+ playbackSpeed: [
77
+ 0.5,
78
+ 1,
79
+ 1.5,
80
+ 2
81
+ ].includes(savedPlaybackSpeed) ? savedPlaybackSpeed : 1,
73
82
  setBackgroundVisible: (visible)=>{
74
83
  set({
75
84
  backgroundVisible: visible
@@ -99,6 +108,12 @@ const useGlobalPreference = store_create((set)=>{
99
108
  darkModeEnabled: enabled
100
109
  });
101
110
  localStorage.setItem(DARK_MODE_KEY, enabled.toString());
111
+ },
112
+ setPlaybackSpeed: (speed)=>{
113
+ set({
114
+ playbackSpeed: speed
115
+ });
116
+ localStorage.setItem(PLAYBACK_SPEED_KEY, speed.toString());
102
117
  }
103
118
  };
104
119
  });
@@ -209,3 +209,33 @@
209
209
  background: rgba(255, 255, 255, .08);
210
210
  }
211
211
 
212
+ .player-settings-dropdown {
213
+ background-color: #fff;
214
+ border: 1px solid rgba(0, 0, 0, .08);
215
+ border-radius: 8px;
216
+ padding: 4px;
217
+ overflow: hidden;
218
+ box-shadow: 0 2px 8px rgba(0, 0, 0, .08);
219
+ }
220
+
221
+ .player-settings-divider {
222
+ background: rgba(0, 0, 0, .06);
223
+ height: 1px;
224
+ margin: 4px 0;
225
+ }
226
+
227
+ .player-speed-option:hover, .player-settings-item:hover {
228
+ background: rgba(0, 0, 0, .04);
229
+ }
230
+
231
+ [data-theme="dark"] .player-settings-dropdown {
232
+ color: #f8fafd;
233
+ background-color: #1f1f1f;
234
+ border-color: rgba(255, 255, 255, .08);
235
+ box-shadow: 0 2px 8px rgba(0, 0, 0, .3);
236
+ }
237
+
238
+ [data-theme="dark"] .player-settings-divider, [data-theme="dark"] .player-speed-option:hover, [data-theme="dark"] .player-settings-item:hover {
239
+ background: rgba(255, 255, 255, .08);
240
+ }
241
+
@@ -243,7 +243,7 @@ function Player(props) {
243
243
  var _scripts_;
244
244
  const [titleText, setTitleText] = (0, external_react_namespaceObject.useState)('');
245
245
  const [subTitleText, setSubTitleText] = (0, external_react_namespaceObject.useState)('');
246
- const { autoZoom, setAutoZoom } = (0, store_js_namespaceObject.useGlobalPreference)();
246
+ const { autoZoom, setAutoZoom, playbackSpeed, setPlaybackSpeed } = (0, store_js_namespaceObject.useGlobalPreference)();
247
247
  (0, external_react_namespaceObject.useEffect)(()=>{
248
248
  if ((null == props ? void 0 : props.autoZoom) !== void 0) setAutoZoom(props.autoZoom);
249
249
  }, [
@@ -588,7 +588,9 @@ function Player(props) {
588
588
  var _scripts_;
589
589
  if (!app || !appInitialized.current) throw new Error('app is not initialized');
590
590
  if (!scripts) throw new Error("scripts is required");
591
- const { frame, cancel, timeout, sleep } = frameKit();
591
+ const { frame, cancel, timeout, sleep: baseSleep } = frameKit();
592
+ const scaleByPlaybackSpeed = (duration)=>duration / playbackSpeed;
593
+ const sleep = (ms)=>baseSleep(scaleByPlaybackSpeed(ms));
592
594
  cancelFn = cancel;
593
595
  cancelAnimationRef.current = cancel;
594
596
  const allImages = scripts.filter((item)=>!!item.img).map((item)=>item.img);
@@ -601,7 +603,7 @@ function Player(props) {
601
603
  yield updatePointer(index_js_namespaceObject.mousePointer, imageWidth / 2, imageHeight / 2);
602
604
  yield repaintImage();
603
605
  yield updateCamera(_object_spread({}, basicCameraState));
604
- const totalDuration = scripts.reduce((acc, item)=>acc + item.duration + (item.camera && item.insightCameraDuration ? item.insightCameraDuration : 0), 0);
606
+ const totalDuration = scaleByPlaybackSpeed(scripts.reduce((acc, item)=>acc + item.duration + (item.camera && item.insightCameraDuration ? item.insightCameraDuration : 0), 0));
605
607
  const progressUpdateInterval = 200;
606
608
  const startTime = performance.now();
607
609
  setAnimationProgress(0);
@@ -637,13 +639,13 @@ function Player(props) {
637
639
  const highlightElements = item.highlightElement ? [
638
640
  item.highlightElement
639
641
  ] : [];
640
- yield insightElementsAnimation([], highlightElements, item.searchArea, item.duration, frame);
642
+ yield insightElementsAnimation([], highlightElements, item.searchArea, scaleByPlaybackSpeed(item.duration), frame);
641
643
  if (item.camera) {
642
644
  if (!item.insightCameraDuration) throw new Error('insightCameraDuration is required');
643
- yield cameraAnimation(item.camera, item.insightCameraDuration, frame);
645
+ yield cameraAnimation(item.camera, scaleByPlaybackSpeed(item.insightCameraDuration), frame);
644
646
  }
645
647
  } else if ('clear-insight' === item.type) {
646
- yield fadeOutItem(insightMarkContainer, item.duration, frame);
648
+ yield fadeOutItem(insightMarkContainer, scaleByPlaybackSpeed(item.duration), frame);
647
649
  insightMarkContainer.removeChildren();
648
650
  insightMarkContainer.alpha = 1;
649
651
  } else if ('img' === item.type) {
@@ -651,7 +653,7 @@ function Player(props) {
651
653
  currentImg.current = item.img;
652
654
  yield repaintImage(item.imageWidth, item.imageHeight);
653
655
  }
654
- if (item.camera) yield cameraAnimation(item.camera, item.duration, frame);
656
+ if (item.camera) yield cameraAnimation(item.camera, scaleByPlaybackSpeed(item.duration), frame);
655
657
  else yield sleep(item.duration);
656
658
  } else if ('pointer' === item.type) {
657
659
  if (!item.img) throw new Error('pointer img is required');
@@ -849,36 +851,18 @@ function Player(props) {
849
851
  overlayStyle: {
850
852
  minWidth: '148px'
851
853
  },
852
- dropdownRender: (menu)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
853
- style: {
854
- borderRadius: '8px',
855
- border: '1px solid rgba(0, 0, 0, 0.08)',
856
- backgroundColor: '#fff',
857
- boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)',
858
- overflow: 'hidden'
859
- },
860
- children: menu
861
- }),
862
- menu: {
863
- style: {
864
- borderRadius: '8px',
865
- padding: 0
866
- },
867
- items: [
868
- {
869
- key: 'autoZoom',
870
- style: {
871
- height: '39px',
872
- margin: 0,
873
- padding: '0 12px'
874
- },
875
- label: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
854
+ dropdownRender: ()=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
855
+ className: "player-settings-dropdown",
856
+ children: [
857
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
858
+ className: "player-settings-item",
876
859
  style: {
877
860
  display: 'flex',
878
861
  alignItems: 'center',
879
862
  justifyContent: 'space-between',
880
- width: '100%',
881
- height: '39px'
863
+ height: '32px',
864
+ padding: '0 8px',
865
+ borderRadius: '4px'
882
866
  },
883
867
  children: [
884
868
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
@@ -909,16 +893,65 @@ function Player(props) {
909
893
  onChange: (checked)=>{
910
894
  setAutoZoom(checked);
911
895
  triggerReplay();
912
- },
913
- onClick: (_, e)=>{
914
- var _e_stopPropagation;
915
- return null == e ? void 0 : null == (_e_stopPropagation = e.stopPropagation) ? void 0 : _e_stopPropagation.call(e);
916
896
  }
917
897
  })
918
898
  ]
919
- })
920
- }
921
- ]
899
+ }),
900
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
901
+ className: "player-settings-divider"
902
+ }),
903
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
904
+ style: {
905
+ display: 'flex',
906
+ alignItems: 'center',
907
+ gap: '4px',
908
+ height: '32px',
909
+ padding: '0 8px'
910
+ },
911
+ children: [
912
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(icons_namespaceObject.ThunderboltOutlined, {
913
+ style: {
914
+ width: '16px',
915
+ height: '16px'
916
+ }
917
+ }),
918
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
919
+ style: {
920
+ fontSize: '12px'
921
+ },
922
+ children: "Playback speed"
923
+ })
924
+ ]
925
+ }),
926
+ [
927
+ 0.5,
928
+ 1,
929
+ 1.5,
930
+ 2
931
+ ].map((speed)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
932
+ onClick: ()=>{
933
+ setPlaybackSpeed(speed);
934
+ triggerReplay();
935
+ },
936
+ style: {
937
+ height: '32px',
938
+ lineHeight: '32px',
939
+ padding: '0 8px 0 24px',
940
+ fontSize: '12px',
941
+ fontWeight: playbackSpeed === speed ? 600 : 'normal',
942
+ cursor: 'pointer',
943
+ borderRadius: '4px'
944
+ },
945
+ className: "player-speed-option",
946
+ children: [
947
+ speed,
948
+ "x"
949
+ ]
950
+ }, speed))
951
+ ]
952
+ }),
953
+ menu: {
954
+ items: []
922
955
  },
923
956
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
924
957
  className: "status-icon",
@@ -34,6 +34,7 @@ const BACKGROUND_VISIBLE_KEY = 'midscene-background-visible';
34
34
  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
+ const PLAYBACK_SPEED_KEY = 'midscene-playback-speed';
37
38
  const parseBooleanParam = (value)=>{
38
39
  if (null === value) return;
39
40
  const normalized = value.trim().toLowerCase();
@@ -61,6 +62,8 @@ const useGlobalPreference = create((set)=>{
61
62
  const savedElementsVisible = 'false' !== localStorage.getItem(ELEMENTS_VISIBLE_KEY);
62
63
  const savedModelCallDetails = 'true' === localStorage.getItem(MODEL_CALL_DETAILS_KEY);
63
64
  const savedDarkMode = 'true' === localStorage.getItem(DARK_MODE_KEY);
65
+ const parsedPlaybackSpeed = Number.parseFloat(localStorage.getItem(PLAYBACK_SPEED_KEY) || '1');
66
+ const savedPlaybackSpeed = Number.isNaN(parsedPlaybackSpeed) ? 1 : parsedPlaybackSpeed;
64
67
  const autoZoomFromQuery = getQueryPreference('focusOnCursor');
65
68
  const elementsVisibleFromQuery = getQueryPreference('showElementMarkers');
66
69
  const darkModeFromQuery = getQueryPreference('darkMode');
@@ -72,6 +75,12 @@ const useGlobalPreference = create((set)=>{
72
75
  autoZoom: void 0 === autoZoomFromQuery ? savedAutoZoom : autoZoomFromQuery,
73
76
  modelCallDetailsEnabled: savedModelCallDetails,
74
77
  darkModeEnabled: initialDarkMode,
78
+ playbackSpeed: [
79
+ 0.5,
80
+ 1,
81
+ 1.5,
82
+ 2
83
+ ].includes(savedPlaybackSpeed) ? savedPlaybackSpeed : 1,
75
84
  setBackgroundVisible: (visible)=>{
76
85
  set({
77
86
  backgroundVisible: visible
@@ -101,6 +110,12 @@ const useGlobalPreference = create((set)=>{
101
110
  darkModeEnabled: enabled
102
111
  });
103
112
  localStorage.setItem(DARK_MODE_KEY, enabled.toString());
113
+ },
114
+ setPlaybackSpeed: (speed)=>{
115
+ set({
116
+ playbackSpeed: speed
117
+ });
118
+ localStorage.setItem(PLAYBACK_SPEED_KEY, speed.toString());
104
119
  }
105
120
  };
106
121
  });
@@ -1,15 +1,18 @@
1
1
  import * as Z from 'zustand';
2
+ export type PlaybackSpeedType = 0.5 | 1 | 1.5 | 2;
2
3
  export declare const useGlobalPreference: Z.UseBoundStore<Z.StoreApi<{
3
4
  backgroundVisible: boolean;
4
5
  elementsVisible: boolean;
5
6
  autoZoom: boolean;
6
7
  modelCallDetailsEnabled: boolean;
7
8
  darkModeEnabled: boolean;
9
+ playbackSpeed: PlaybackSpeedType;
8
10
  setBackgroundVisible: (visible: boolean) => void;
9
11
  setElementsVisible: (visible: boolean) => void;
10
12
  setAutoZoom: (enabled: boolean) => void;
11
13
  setModelCallDetailsEnabled: (enabled: boolean) => void;
12
14
  setDarkModeEnabled: (enabled: boolean) => void;
15
+ setPlaybackSpeed: (speed: PlaybackSpeedType) => void;
13
16
  }>>;
14
17
  /**
15
18
  * Service Mode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/visualizer",
3
- "version": "1.3.7",
3
+ "version": "1.3.8-beta-20260206024209.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",
@@ -60,10 +60,10 @@
60
60
  "antd": "^5.21.6",
61
61
  "buffer": "6.0.3",
62
62
  "dayjs": "^1.11.11",
63
- "@midscene/core": "1.3.7",
64
- "@midscene/web": "1.3.7",
65
- "@midscene/shared": "1.3.7",
66
- "@midscene/playground": "1.3.7"
63
+ "@midscene/core": "1.3.8-beta-20260206024209.0",
64
+ "@midscene/playground": "1.3.8-beta-20260206024209.0",
65
+ "@midscene/web": "1.3.8-beta-20260206024209.0",
66
+ "@midscene/shared": "1.3.8-beta-20260206024209.0"
67
67
  },
68
68
  "license": "MIT",
69
69
  "scripts": {