@pluot/react 0.1.0 → 0.1.2

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 (45) hide show
  1. package/README.md +2 -0
  2. package/dist/C059-BdIta.ttf-Bdc938Uh.js +4 -0
  3. package/dist/C059-Bold.ttf-D54yVEIG.js +4 -0
  4. package/dist/C059-Italic.ttf-DLWXDpX2.js +4 -0
  5. package/dist/C059-Roman.ttf-B_4E2VG-.js +4 -0
  6. package/dist/D050000L.ttf-DThw2vhA.js +4 -0
  7. package/dist/NimbusMonoPS-Bold.ttf-DaeY0qBr.js +4 -0
  8. package/dist/NimbusMonoPS-BoldItalic.ttf-BWf8L4h2.js +4 -0
  9. package/dist/NimbusMonoPS-Italic.ttf-B6sVyRe1.js +4 -0
  10. package/dist/NimbusMonoPS-Regular.ttf-4U95hi4W.js +4 -0
  11. package/dist/NimbusRoman-Bold.ttf-CYfJBZ-D.js +4 -0
  12. package/dist/NimbusRoman-BoldItalic.ttf-IKgFHn3u.js +4 -0
  13. package/dist/NimbusRoman-Italic.ttf-DphHuaaV.js +4 -0
  14. package/dist/NimbusRoman-Regular.ttf-CyDfJ_2L.js +4 -0
  15. package/dist/NimbusSans-Bold.ttf-BgToHb0k.js +4 -0
  16. package/dist/NimbusSans-BoldItalic.ttf-DBTyNZML.js +4 -0
  17. package/dist/NimbusSans-BoldOblique.ttf-BsmbX-RQ.js +4 -0
  18. package/dist/NimbusSans-Italic.ttf-DXn1aKmU.js +4 -0
  19. package/dist/NimbusSans-Oblique.ttf-BnOkISci.js +4 -0
  20. package/dist/NimbusSans-Regular.ttf-BPUWfSNR.js +4 -0
  21. package/dist/NimbusSansNarrow-BdOblique.ttf-pMMXNfDW.js +4 -0
  22. package/dist/NimbusSansNarrow-Bold.ttf-CTqrnZ6z.js +4 -0
  23. package/dist/NimbusSansNarrow-BoldOblique.ttf-CDZKzRWR.js +4 -0
  24. package/dist/NimbusSansNarrow-Oblique.ttf-CmqouKBN.js +4 -0
  25. package/dist/NimbusSansNarrow-Regular.ttf-DOZi8TRM.js +4 -0
  26. package/dist/P052-Bold.ttf-F7VVlUHU.js +4 -0
  27. package/dist/P052-BoldItalic.ttf-CTaOaPJC.js +4 -0
  28. package/dist/P052-Italic.ttf-CfqenRHn.js +4 -0
  29. package/dist/P052-Roman.ttf-B-tZ3T0p.js +4 -0
  30. package/dist/StandardSymbolsPS.ttf-DQ9k8vPT.js +4 -0
  31. package/dist/URWBookman-Demi.ttf-gvfD6bGd.js +4 -0
  32. package/dist/URWBookman-DemiItalic.ttf-CTYueWh5.js +4 -0
  33. package/dist/URWBookman-Light.ttf-DK879rFB.js +4 -0
  34. package/dist/URWBookman-LightItalic.ttf-BWVZJTZv.js +4 -0
  35. package/dist/URWGothic-Book.ttf-BjKm3X4s.js +4 -0
  36. package/dist/URWGothic-BookOblique.ttf-UGkGTKkJ.js +4 -0
  37. package/dist/URWGothic-Demi.ttf-CUhEK02w.js +4 -0
  38. package/dist/URWGothic-DemiOblique.ttf-CP_D_bVd.js +4 -0
  39. package/dist/Z003-MediumItalic.ttf-BXc6HvHA.js +4 -0
  40. package/dist/index.js +1533 -4956
  41. package/dist-tsc/Pluot.d.ts.map +1 -1
  42. package/dist-tsc/Pluot.js +101 -195
  43. package/package.json +9 -3
  44. package/src/Pluot.jsx +118 -228
  45. package/src/index.js +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Pluot.d.ts","sourceRoot":"","sources":["../src/Pluot.jsx"],"names":[],"mappings":"AAgDA,uCA+fC"}
1
+ {"version":3,"file":"Pluot.d.ts","sourceRoot":"","sources":["../src/Pluot.jsx"],"names":[],"mappings":"AAiDA,uCAgZC"}
package/dist-tsc/Pluot.js CHANGED
@@ -4,7 +4,7 @@ import { mat4, vec4 } from "gl-matrix";
4
4
  import lzs from "lz-string";
5
5
  import { isEqual, throttle } from "lodash-es";
6
6
  import { FetchStore } from 'zarrita';
7
- import { initialize, getIsWasmReady, render_wasm, pick_wasm, setStore, getStore, create2dCamera, create3dCamera, getBounds, getCameraMatrixFromBounds, checkWebGpuFeatureDetection, } from '@pluot/core';
7
+ import { initialize, getIsWasmReady, render_wasm, pick_wasm, setStore, getStore, getBounds, getCameraMatrixFromBounds, checkWebGpuFeatureDetection, onMouseMove2d, onWheel2d, onMouseMove3d, onWheel3d, } from '@pluot/core';
8
8
  // Needed due to "SyntaxError: Named export 'decompressFromUint8Array' not found.
9
9
  // The requested module 'lz-string' is a CommonJS module,
10
10
  // which may not support all module.exports as named exports."
@@ -37,7 +37,31 @@ export function Pluot(props) {
37
37
  const { width: widthProp, height: heightProp, plotId, plotType, store, storeName: storeNameProp, plotParams, viewMode = "2d", marginBottom = 100.0, marginLeft = 100.0, marginTop = 100.0, marginRight = 100.0, aspectRatioMode = "Contain", // "Ignore", "Contain", "Cover"
38
38
  aspectRatioAlignmentMode = "Start", // "Center", "Start", "End"
39
39
  format = "Raster", // "Raster", "Vector"
40
- minTimeout = 32, maxTimeout = 32, allowSimultaneousRenders = true, debugMargins = false, } = props;
40
+ minTimeout = 32, maxTimeout = 5000, allowSimultaneousRenders = true, debugMargins = false, cameraMatrix: controlledCameraMatrix = null, setCameraMatrix: setControlledCameraMatrix = null, enablePicking = true, backgroundColor = undefined, } = props;
41
+ // If cameraMatrix is not provided, then we manage the camera matrix internally.
42
+ const [uncontrolledCameraMatrix, setUncontrolledCameraMatrix] = useState(
43
+ // Note: We use an initializer function here to avoid
44
+ // sharing the same Float32Array among multiple Pluot
45
+ // component instances that may be rendered on the same page.
46
+ () => Float32Array.from(
47
+ // If the cameraMatrix prop was provided, use that for the initial camera matrix;
48
+ // otherwise use the default matrix.
49
+ controlledCameraMatrix === null
50
+ ? (viewMode === "2d" ? DEFAULT_VIEW : DEFAULT_3D_VIEW)
51
+ : controlledCameraMatrix));
52
+ // Decide which camera matrix and setter to use.
53
+ // If the user provides the cameraMatrix prop but NOT the setCameraMatrix setter,
54
+ // then interpret the prop as the "initial" camera settings, but still treat as uncontrolled.
55
+ const isControlledCamera = typeof setControlledCameraMatrix === "function";
56
+ // Alternatively, if the user provides the setCameraMatrix setter, but NOT
57
+ // the cameraMatrix, interpret this as they want to use the default camera
58
+ // value initially, but they still want a controlled camera matrix.
59
+ const cameraMatrix = isControlledCamera && controlledCameraMatrix !== null
60
+ ? controlledCameraMatrix
61
+ : uncontrolledCameraMatrix;
62
+ const setCameraMatrix = isControlledCamera
63
+ ? setControlledCameraMatrix
64
+ : setUncontrolledCameraMatrix;
41
65
  const width = Math.floor(widthProp);
42
66
  const height = Math.floor(heightProp);
43
67
  const isVector = format === "Vector";
@@ -57,11 +81,11 @@ export function Pluot(props) {
57
81
  const [supportsWebGpu, supportsWebGpuMessage] = useMemo(checkWebGpuFeatureDetection, []);
58
82
  const svgRef = useRef(null);
59
83
  const canvasRef = useRef(null);
60
- const cameraRef = useRef(null);
84
+ const cameraElementRef = useRef(null);
61
85
  const tempButtonRef = useRef(null);
62
86
  // We may want to update these things without triggering a re-render.
63
87
  const isRenderingRef = useRef(false);
64
- const currentTimeout = useRef(maxTimeout);
88
+ const currentTimeout = useRef(minTimeout);
65
89
  // TODO: do we want to use the backlog approach or not?
66
90
  // (Similar to the one used in the Vitessce heatmap)
67
91
  // Reference: https://github.com/vitessce/vitessce/blob/71f17fb605768e0428fb15ed87b3ea34bcbb4803/packages/view-types/heatmap/src/Heatmap.js#L368
@@ -71,195 +95,41 @@ export function Pluot(props) {
71
95
  const [didFirstRender, setDidFirstRender] = useState(false);
72
96
  const [bailedEarly, setBailedEarly] = useState(true);
73
97
  const [pickingResult, setPickingResult] = useState(null);
74
- // TODO: handle a viewMatrix that is provided and set via props,
75
- // to enable usage as a controlled component
76
- // (e.g., for linked views with shared cameras).
77
- const [viewMatrix, setViewMatrix] = useState(
78
- // Note: We use an initializer function here to avoid
79
- // sharing the same Float32Array among multiple Pluot
80
- // component instances that may be rendered on the same page.
81
- () => new Float32Array(DEFAULT_VIEW));
82
98
  useLayoutEffect(() => {
83
99
  initialize().then(() => setIsWasmReady(getIsWasmReady()));
84
100
  }, []);
85
- useEffect(() => {
86
- // Reset view matrix on plot change.
87
- // Create a new Float32Array to avoid sharing a mutable array
88
- // among multiple Pluot component instances.
89
- setViewMatrix(new Float32Array(viewMode === "2d" ? DEFAULT_VIEW : DEFAULT_3D_VIEW));
90
- //viewMatrixRef.current = new Float32Array(DEFAULT_VIEW);
91
- }, [plotId, viewMode]);
92
- // Set up the camera.
93
- useEffect(() => {
94
- // Set up the camera.
95
- const cameraEl = cameraRef.current;
96
- if (!cameraEl) {
97
- return () => { };
98
- }
99
- let dispose = () => { };
100
- // Create a 2D camera for handling zoom and pan.
101
- if (viewMode === "2d") {
102
- function onCameraEvent(camera, event) {
103
- camera.tick();
104
- // Reference: https://github.com/flekschas/regl-scatterplot/blob/17a650c352fad313d1574472b2fdc5f58b9e1eca/src/index.js#L1648
105
- setViewMatrix(prev => {
106
- // Since camera events happen even on mousemove events that do not change the matrix,
107
- // we check for equality here to avoid unnecessary state updates and plot re-renders.
108
- if (isEqual(prev, camera.view)) {
109
- return prev;
110
- }
111
- return mat4.clone(camera.view);
112
- });
113
- currentTimeout.current = minTimeout;
114
- }
115
- const camera = create2dCamera(cameraEl, {
116
- isFixed: false,
117
- distance: 0.0,
118
- //target: [0.0, 0.0],
119
- //viewCenter: [0.5, 0.5], // Should this be used when the coordinate system is (0 to 1) rather than (-1 to 1)?
120
- viewCenter: [0.0, 0.0],
121
- defaultMouseDownMoveAction: "pan",
122
- onKeyDown: (event) => {
123
- onCameraEvent(camera, event);
124
- },
125
- onKeyUp: (event) => {
126
- onCameraEvent(camera, event);
127
- },
128
- onMouseDown: (event) => {
129
- onCameraEvent(camera, event);
130
- },
131
- onMouseUp: (event) => {
132
- onCameraEvent(camera, event);
133
- },
134
- onMouseMove: (event) => {
135
- onCameraEvent(camera, event);
136
- },
137
- onWheel: (event) => {
138
- onCameraEvent(camera, event);
139
- },
140
- aspectRatioMode: aspectRatioMode,
141
- aspectRatioAlignmentMode: aspectRatioAlignmentMode,
142
- });
143
- // Set the initial view matrix.
144
- // We need to ensure we create a new copy of the array.
145
- camera.setView(new Float32Array(viewMatrix));
146
- const tempHandler = e => {
147
- // camera.setScaleBounds([[xScaleMin, xScaleMax], [yScaleMin, yScaleMax]])
148
- //camera.lookAt([2.0, 2.0], 2.0);
149
- //onCameraEvent(camera, null);
150
- // Only zoom/pan the X axis; keep Y unchanged
151
- const nextCameraMatrix = getCameraMatrixFromBounds({ yMin: 0.0, yMax: 100.0 }, new Float32Array(viewMatrix), {
152
- width,
153
- height,
154
- aspectRatioMode,
155
- aspectRatioAlignmentMode,
156
- margins: {
157
- marginTop,
158
- marginBottom,
159
- marginLeft,
160
- marginRight
161
- },
162
- });
163
- console.log("done", nextCameraMatrix);
164
- camera.setView(nextCameraMatrix);
165
- onCameraEvent(camera, null);
166
- };
167
- tempButtonRef.current.addEventListener('click', tempHandler);
168
- // Set up an onClick handler.
169
- //
170
- const clickHandler = (event) => {
171
- pickFrame(event.offsetX, event.offsetY);
172
- };
173
- cameraEl.addEventListener("click", clickHandler);
174
- dispose = () => {
175
- camera.dispose();
176
- cameraEl.removeEventListener("click", clickHandler);
177
- tempButtonRef.current.removeEventListener('click', tempHandler);
178
- };
179
- }
180
- else if (viewMode === "3d") {
181
- function onCameraEvent(camera, event) {
182
- camera.tick();
183
- // Note: the 3D camera stores the matrix in camera.matrix (not camera.view).
184
- setViewMatrix(prev => {
185
- // Since camera events happen even on mousemove events that do not change the matrix,
186
- // we check for equality here to avoid unnecessary state updates and plot re-renders.
187
- if (isEqual(prev, camera.matrix)) {
188
- return prev;
189
- }
190
- return mat4.clone(camera.matrix);
191
- });
192
- }
193
- const camera = create3dCamera(cameraEl, {
194
- mode: "orbit",
195
- zoomSpeed: -5,
196
- });
197
- // TODO:
198
- // - fork 3d-view-controls and remove usage of "global" - then clean up vite config.
199
- // - define a camera.dispsose option.
200
- // Reference: https://github.com/flekschas/dom-2d-camera/blob/cd59ea035a0ea72c2c0535fa3721f8127946576c/src/index.js#L237C3-L315C71
201
- const keyUpHandler = (event) => {
202
- // TODO
203
- };
204
- const keyDownHandler = (event) => {
205
- // TODO
206
- };
207
- const mouseUpHandler = (event) => {
208
- // TODO
209
- };
210
- const mouseDownHandler = (event) => {
211
- // TODO
212
- };
213
- // TODO: use react state?
214
- var lastX = 0;
215
- var lastY = 0;
216
- // Reference: https://github.com/mikolalysenko/3d-view/blob/8269e02337bba1923173a750aa7f3f0f76c91ba5/example/minimal.js#L67
217
- const mouseMoveHandler = (event) => {
218
- /*
219
- var dx = (event.clientX - lastX) / width;
220
- var dy = -(event.clientY - lastY) / height;
221
- if (event.which === 1) {
222
- if (event.shiftKey) {
223
- //zoom
224
- camera.rotate(now(), 0, 0, dx);
225
- } else {
226
- //rotate
227
- camera.rotate(now(), dx, dy);
228
- }
229
- } else if (event.which === 3) {
230
- //pan
231
- camera.pan(now(), dx, dy);
232
- }
233
- lastX = event.clientX;
234
- lastY = event.clientY;
235
- */
236
- onCameraEvent(camera, event);
237
- };
238
- const wheelHandler = (event) => {
239
- //camera.pan(now(), 0, 0, event.deltaY);
240
- onCameraEvent(camera, event);
241
- };
242
- cameraEl.addEventListener("keydown", keyDownHandler);
243
- cameraEl.addEventListener("keyup", keyUpHandler);
244
- cameraEl.addEventListener("mousedown", mouseDownHandler);
245
- cameraEl.addEventListener("mouseup", mouseUpHandler);
246
- cameraEl.addEventListener("mousemove", mouseMoveHandler);
247
- cameraEl.addEventListener("wheel", wheelHandler);
248
- dispose = () => {
249
- cameraEl.removeEventListener("keydown", keyDownHandler);
250
- cameraEl.removeEventListener("keyup", keyUpHandler);
251
- cameraEl.removeEventListener("mousedown", mouseDownHandler);
252
- cameraEl.removeEventListener("mouseup", mouseUpHandler);
253
- cameraEl.removeEventListener("mousemove", mouseMoveHandler);
254
- cameraEl.removeEventListener("wheel", wheelHandler);
255
- };
256
- //camera.matrix = new Float32Array(viewMatrix);
257
- }
258
- else {
259
- throw new Error("Unknown mode found.");
260
- }
261
- return dispose;
262
- }, [cameraRef, viewMode, aspectRatioMode, aspectRatioAlignmentMode, width, height, marginLeft, marginRight, marginTop, marginBottom]);
101
+ const wheelHandler = useEffectEvent((event) => {
102
+ const onWheel = viewMode === "3d" ? onWheel3d : onWheel2d;
103
+ const nextCameraMatrix = onWheel({
104
+ width,
105
+ height,
106
+ aspectRatioMode,
107
+ aspectRatioAlignmentMode,
108
+ margins: {
109
+ marginTop,
110
+ marginBottom,
111
+ marginLeft,
112
+ marginRight,
113
+ },
114
+ }, cameraMatrix, event);
115
+ setCameraMatrix(nextCameraMatrix);
116
+ });
117
+ const mouseMoveHandler = useEffectEvent((event) => {
118
+ const onMouseMove = viewMode === "3d" ? onMouseMove3d : onMouseMove2d;
119
+ const nextCameraMatrix = onMouseMove({
120
+ width,
121
+ height,
122
+ aspectRatioMode,
123
+ aspectRatioAlignmentMode,
124
+ margins: {
125
+ marginTop,
126
+ marginBottom,
127
+ marginLeft,
128
+ marginRight,
129
+ },
130
+ }, cameraMatrix, event);
131
+ setCameraMatrix(nextCameraMatrix);
132
+ });
263
133
  // The picking callback.
264
134
  const pickFrame = useEffectEvent(async (screenCoordX, screenCoordY) => {
265
135
  const renderParams = {
@@ -276,7 +146,7 @@ export function Pluot(props) {
276
146
  view_mode: viewMode,
277
147
  pickable: false,
278
148
  // Should see the latest viewMatrix here, since renderFrame is wrapped in useEffectEvent.
279
- camera_view: viewMatrix,
149
+ camera_view: cameraMatrix,
280
150
  plot_id: plotId,
281
151
  plot_type: plotType,
282
152
  store_name: storeName,
@@ -294,6 +164,28 @@ export function Pluot(props) {
294
164
  // We also need to flip the Y coordinate so that positive is up.
295
165
  screenCoordX + marginLeft, marginBottom + (layerHeight - screenCoordY))));
296
166
  });
167
+ // Set up the camera and picking handlers.
168
+ useEffect(() => {
169
+ const cameraEl = cameraElementRef.current;
170
+ if (!cameraEl) {
171
+ return () => { };
172
+ }
173
+ // Create a 2D camera for handling zoom and pan.
174
+ cameraEl.addEventListener("mousemove", mouseMoveHandler);
175
+ cameraEl.addEventListener("wheel", wheelHandler);
176
+ // Set up an onClick handler for picking.
177
+ const clickHandler = (event) => {
178
+ if (enablePicking) {
179
+ pickFrame(event.offsetX, event.offsetY);
180
+ }
181
+ };
182
+ cameraEl.addEventListener("click", clickHandler);
183
+ return () => {
184
+ cameraEl.removeEventListener("mousemove", mouseMoveHandler);
185
+ cameraEl.removeEventListener("wheel", wheelHandler);
186
+ cameraEl.removeEventListener("click", clickHandler);
187
+ };
188
+ }, [viewMode, enablePicking]);
297
189
  // The renderFrame callback.
298
190
  // We use useEffectEvent because we want to "see"
299
191
  // the latest values of viewMatrix, plotProps, etc.
@@ -314,7 +206,7 @@ export function Pluot(props) {
314
206
  view_mode: viewMode,
315
207
  pickable: false,
316
208
  // Should see the latest viewMatrix here, since renderFrame is wrapped in useEffectEvent.
317
- camera_view: viewMatrix,
209
+ camera_view: cameraMatrix,
318
210
  plot_id: plotId,
319
211
  plot_type: plotType,
320
212
  store_name: storeName,
@@ -364,12 +256,17 @@ export function Pluot(props) {
364
256
  ctx.putImageData(imageData, 0, 0);
365
257
  const frameBailedEarly = arr.at(-1) === 1;
366
258
  if (frameBailedEarly) {
367
- currentTimeout.current = maxTimeout;
259
+ // We multiply the current timeout by two to implement an exponential backoff
260
+ // while the Rust side is bailing early.
261
+ // A downstream useEffect restarts the exponential backoff from scratch
262
+ // if any other plotting parameters change.
263
+ currentTimeout.current = Math.min(currentTimeout.current * 2, maxTimeout);
368
264
  incBacklogIteration(); // Increment this to force a re-render.
369
265
  setBailedEarly(true); // Update this to show the loading indicator.
370
266
  }
371
267
  else {
372
268
  // Successful render.
269
+ currentTimeout.current = minTimeout;
373
270
  setBailedEarly(false); // Update this to hide the loading indicator.
374
271
  // Clear the LRU cache for the store (via its store_name) corresponding to the rendered plot.
375
272
  const storeUsed = getStore(renderParams.store_name);
@@ -389,6 +286,15 @@ export function Pluot(props) {
389
286
  useEffect(() => {
390
287
  return () => throttledRender.cancel();
391
288
  }, [throttledRender]);
289
+ // Reset the backoff timeout whenever plot parameters change so the next
290
+ // sequence of bailed-early renders starts from the minimum again.
291
+ useEffect(() => {
292
+ currentTimeout.current = minTimeout;
293
+ }, [plotId, plotType, plotParams, storeName, format,
294
+ width, height, aspectRatioMode, aspectRatioAlignmentMode,
295
+ marginLeft, marginRight, marginTop, marginBottom,
296
+ cameraMatrix,
297
+ ]);
392
298
  // TODO: use react-query?
393
299
  useEffect(() => {
394
300
  if (!isWasmReady) {
@@ -404,9 +310,9 @@ export function Pluot(props) {
404
310
  }
405
311
  // Render on the next animation frame.
406
312
  throttledRender();
407
- }, [isWasmReady, didFirstRender, viewMatrix, backlogIteration, plotId, plotType, plotParams, storeName, format,
313
+ }, [isWasmReady, didFirstRender, cameraMatrix, backlogIteration, plotId, plotType, plotParams, storeName, format,
408
314
  width, height, aspectRatioMode, aspectRatioAlignmentMode, marginLeft, marginRight, marginTop, marginBottom]);
409
- return (_jsxs(_Fragment, { children: [_jsxs("div", { style: { width, height, position: "relative" }, children: [!supportsWebGpu ? (_jsx("p", { children: supportsWebGpuMessage })) : null, _jsx("div", { ref: cameraRef, style: {
315
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { style: { width, height, position: "relative", backgroundColor }, children: [!supportsWebGpu ? (_jsx("p", { children: supportsWebGpuMessage })) : null, _jsx("div", { ref: cameraElementRef, style: {
410
316
  position: "absolute",
411
317
  top: marginTop,
412
318
  left: marginLeft,
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "@pluot/react",
3
3
  "private": false,
4
- "version": "0.1.0",
5
- "description": "",
4
+ "version": "0.1.2",
5
+ "description": "React component for visualization with Pluot",
6
6
  "license": "Apache-2.0",
7
+ "author": "Mark Keller",
8
+ "homepage": "https://pluot.dev",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/keller-mark/pluot.git"
12
+ },
7
13
  "type": "module",
8
14
  "main": "dist/index.js",
9
15
  "files": [
@@ -30,7 +36,7 @@
30
36
  "mouse-wheel": "^1.0.2",
31
37
  "lz-string": "^1.5.0",
32
38
  "lodash-es": "^4.17.23",
33
- "@pluot/core": "0.1.0"
39
+ "@pluot/core": "0.1.2"
34
40
  },
35
41
  "devDependencies": {
36
42
  "vitest": "^3.2.4",