copper3d 3.4.6 → 3.4.8

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 (31) hide show
  1. package/dist/Utils/segmentation/DrawToolCore.d.ts +19 -2
  2. package/dist/Utils/segmentation/DrawToolCore.js +58 -13
  3. package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
  4. package/dist/Utils/segmentation/NrrdTools.d.ts +0 -1
  5. package/dist/Utils/segmentation/NrrdTools.js +8 -7
  6. package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
  7. package/dist/Utils/segmentation/core/types.d.ts +0 -1
  8. package/dist/Utils/segmentation/core/types.js.map +1 -1
  9. package/dist/Utils/segmentation/coreTools/gui.d.ts +0 -1
  10. package/dist/Utils/segmentation/coreTools/gui.js +21 -29
  11. package/dist/Utils/segmentation/coreTools/gui.js.map +1 -1
  12. package/dist/Utils/segmentation/tools/DrawingTool.d.ts +9 -2
  13. package/dist/Utils/segmentation/tools/DrawingTool.js +28 -19
  14. package/dist/Utils/segmentation/tools/DrawingTool.js.map +1 -1
  15. package/dist/Utils/segmentation/tools/ToolHost.d.ts +2 -3
  16. package/dist/Utils/utils.d.ts +0 -1
  17. package/dist/Utils/utils.js +0 -80
  18. package/dist/Utils/utils.js.map +1 -1
  19. package/dist/bundle.esm.js +115 -147
  20. package/dist/bundle.umd.js +115 -147
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +1 -1
  23. package/dist/types/Utils/segmentation/DrawToolCore.d.ts +19 -2
  24. package/dist/types/Utils/segmentation/NrrdTools.d.ts +0 -1
  25. package/dist/types/Utils/segmentation/core/types.d.ts +0 -1
  26. package/dist/types/Utils/segmentation/coreTools/gui.d.ts +0 -1
  27. package/dist/types/Utils/segmentation/tools/DrawingTool.d.ts +9 -2
  28. package/dist/types/Utils/segmentation/tools/ToolHost.d.ts +2 -3
  29. package/dist/types/Utils/utils.d.ts +0 -1
  30. package/dist/types/index.d.ts +1 -1
  31. package/package.json +1 -1
@@ -40606,86 +40606,6 @@ function switchPencilIcon(icon, urls) {
40606
40606
  }
40607
40607
  return url;
40608
40608
  }
40609
- function switchEraserSize(size, urls) {
40610
- let url = "";
40611
- if (!!urls && urls.length > 0) {
40612
- if (size <= 3) {
40613
- url = `url(${urls[0]}) 3 3, crosshair`;
40614
- }
40615
- else if (3 < size && size <= 8) {
40616
- url = `url(${urls[1]}) 8 8, crosshair`;
40617
- }
40618
- else if (8 < size && size <= 13) {
40619
- url = `url(${urls[2]}) 13 13, crosshair`;
40620
- }
40621
- else if (13 < size && size <= 18) {
40622
- url = `url(${urls[3]}) 18 18, crosshair`;
40623
- }
40624
- else if (18 < size && size <= 23) {
40625
- url = `url(${urls[4]}) 23 23, crosshair`;
40626
- }
40627
- else if (23 < size && size <= 28) {
40628
- url = `url(${urls[5]}) 28 28, crosshair`;
40629
- }
40630
- else if (28 < size && size <= 33) {
40631
- url = `url(${urls[6]}) 33 33, crosshair`;
40632
- }
40633
- else if (33 < size && size <= 38) {
40634
- url = `url(${urls[7]}) 38 38, crosshair`;
40635
- }
40636
- else if (38 < size && size <= 43) {
40637
- url = `url(${urls[8]}) 43 43, crosshair`;
40638
- }
40639
- else if (43 < size && size <= 48) {
40640
- url = `url(${urls[9]}) 48 48, crosshair`;
40641
- }
40642
- else if (48 < size && size <= 53) {
40643
- url = `url(${urls[10]}) 52 52, crosshair`;
40644
- }
40645
- else {
40646
- url = `url(${urls[11]}) 52 52, crosshair`;
40647
- }
40648
- }
40649
- else {
40650
- if (size <= 3) {
40651
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_3.png) 3 3, crosshair`;
40652
- }
40653
- else if (3 < size && size <= 8) {
40654
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_8.png) 8 8, crosshair`;
40655
- }
40656
- else if (8 < size && size <= 13) {
40657
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_13.png) 13 13, crosshair`;
40658
- }
40659
- else if (13 < size && size <= 18) {
40660
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_18.png) 18 18, crosshair`;
40661
- }
40662
- else if (18 < size && size <= 23) {
40663
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_23.png) 23 23, crosshair`;
40664
- }
40665
- else if (23 < size && size <= 28) {
40666
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_28.png) 28 28, crosshair`;
40667
- }
40668
- else if (28 < size && size <= 33) {
40669
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_33.png) 33 33, crosshair`;
40670
- }
40671
- else if (33 < size && size <= 38) {
40672
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_38.png) 38 38, crosshair`;
40673
- }
40674
- else if (38 < size && size <= 43) {
40675
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_43.png) 43 43, crosshair`;
40676
- }
40677
- else if (43 < size && size <= 48) {
40678
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_48.png) 48 48, crosshair`;
40679
- }
40680
- else if (48 < size && size <= 53) {
40681
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_52.png) 52 52, crosshair`;
40682
- }
40683
- else {
40684
- url = `url(https://raw.githubusercontent.com/LinkunGao/copper3d-datasets/main/icons/eraser/circular-cursor_52.png) 52 52, crosshair`;
40685
- }
40686
- }
40687
- return url;
40688
- }
40689
40609
  function throttle(callback, wait) {
40690
40610
  let start = 0;
40691
40611
  return function (event) {
@@ -73002,10 +72922,7 @@ function setupGui(configs) {
73002
72922
  .name("BrushAndEraserSize")
73003
72923
  .min(5)
73004
72924
  .max(50)
73005
- .step(1)
73006
- .onChange(() => {
73007
- updateGuiBrushAndEraserSize();
73008
- });
72925
+ .step(1);
73009
72926
  actionsFolder.add(configs.gui_states.mode, "eraser").onChange((value) => {
73010
72927
  updateGuiEraserState();
73011
72928
  });
@@ -73133,37 +73050,33 @@ function setupGui(configs) {
73133
73050
  configs.gui_states.viewConfig.readyToUpdate = true;
73134
73051
  });
73135
73052
  actionsFolder.open();
73136
- const updateGuiBrushAndEraserSize = () => {
73137
- if (configs.gui_states.mode.eraser) {
73138
- configs.eraserUrls.length > 0
73139
- ? (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize, configs.eraserUrls))
73140
- : (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize));
73141
- }
73142
- };
73143
- const updatePencilState = () => {
73144
- if (configs.gui_states.mode.pencil) {
73145
- // add canvas brush circle move event listeners
73146
- configs.drawingCanvas.removeEventListener("mouseover", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
73147
- configs.drawingCanvas.removeEventListener("mouseout", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
73053
+ // Add/remove the hover-tracking listeners that feed the brush/eraser preview
73054
+ // ring (mouseOver position). Present for brush & eraser, removed for pencil.
73055
+ const setBrushHoverTracking = (enabled) => {
73056
+ const handler = configs.drawingPrameters.handleOnDrawingBrushCricleMove;
73057
+ if (enabled) {
73058
+ configs.drawingCanvas.addEventListener("mouseover", handler);
73059
+ configs.drawingCanvas.addEventListener("mouseout", handler);
73148
73060
  }
73149
73061
  else {
73150
- // add canvas brush circle move event listeners
73151
- configs.drawingCanvas.addEventListener("mouseover", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
73152
- configs.drawingCanvas.addEventListener("mouseout", configs.drawingPrameters.handleOnDrawingBrushCricleMove);
73062
+ configs.drawingCanvas.removeEventListener("mouseover", handler);
73063
+ configs.drawingCanvas.removeEventListener("mouseout", handler);
73153
73064
  }
73065
+ };
73066
+ const updatePencilState = () => {
73067
+ // Pencil has no preview ring; brush keeps the hover-tracking listeners.
73068
+ setBrushHoverTracking(!configs.gui_states.mode.pencil);
73154
73069
  configs.drawingCanvas.style.cursor = configs.gui_states.viewConfig.defaultPaintCursor;
73155
73070
  };
73156
73071
  const updateGuiEraserState = () => {
73157
- // configs.gui_states.mode.eraser = value;
73072
+ // The eraser shows a dashed preview ring (rendered in DrawToolCore.start),
73073
+ // so it needs the same hover-tracking as the brush. The canvas keeps the
73074
+ // default paint cursor; the ring conveys size (resize via Shift+wheel).
73158
73075
  if (configs.gui_states.mode.eraser) {
73159
- configs.eraserUrls.length > 0
73160
- ? (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize, configs.eraserUrls))
73161
- : (configs.drawingCanvas.style.cursor = switchEraserSize(configs.gui_states.drawing.brushAndEraserSize));
73162
- }
73163
- else {
73164
- configs.drawingCanvas.style.cursor =
73165
- configs.gui_states.viewConfig.defaultPaintCursor;
73076
+ setBrushHoverTracking(true);
73166
73077
  }
73078
+ configs.drawingCanvas.style.cursor =
73079
+ configs.gui_states.viewConfig.defaultPaintCursor;
73167
73080
  };
73168
73081
  const updateGuiSphereState = () => {
73169
73082
  var _a, _b, _c, _d;
@@ -73219,7 +73132,6 @@ function setupGui(configs) {
73219
73132
  min: 5,
73220
73133
  max: 50,
73221
73134
  step: 1,
73222
- onChange: updateGuiBrushAndEraserSize,
73223
73135
  },
73224
73136
  eraser: {
73225
73137
  name: "Eraser",
@@ -74948,18 +74860,11 @@ class DrawingTool extends BaseTool {
74948
74860
  this.drawingLines = [];
74949
74861
  this.isPainting = true;
74950
74862
  this.ctx.protectedData.isDrawing = true;
74951
- // Set cursor based on mode
74952
- if (this.ctx.gui_states.mode.eraser) {
74953
- const urls = this.callbacks.getEraserUrls();
74954
- this.ctx.protectedData.canvases.drawingCanvas.style.cursor =
74955
- urls.length > 0
74956
- ? switchEraserSize(this.ctx.gui_states.drawing.brushAndEraserSize, urls)
74957
- : switchEraserSize(this.ctx.gui_states.drawing.brushAndEraserSize);
74958
- }
74959
- else {
74960
- this.ctx.protectedData.canvases.drawingCanvas.style.cursor =
74961
- this.ctx.gui_states.viewConfig.defaultPaintCursor;
74962
- }
74863
+ // Brush and eraser both show their size via the dashed/solid preview ring
74864
+ // rendered in DrawToolCore.start(); the canvas keeps the default paint
74865
+ // cursor underneath. (The eraser previously swapped in a sized PNG cursor.)
74866
+ this.ctx.protectedData.canvases.drawingCanvas.style.cursor =
74867
+ this.ctx.gui_states.viewConfig.defaultPaintCursor;
74963
74868
  // Record draw start position
74964
74869
  this.ctx.nrrd_states.interaction.drawStartPos.x = e.offsetX;
74965
74870
  this.ctx.nrrd_states.interaction.drawStartPos.y = e.offsetY;
@@ -75097,20 +75002,37 @@ class DrawingTool extends BaseTool {
75097
75002
  return handler;
75098
75003
  }
75099
75004
  /**
75100
- * Render brush circle preview on the drawing context.
75005
+ * Render the size-preview ring for the brush / eraser on the drawing context.
75006
+ *
75007
+ * - Brush: solid outline in the current brush colour.
75008
+ * - Eraser: red dashed outline (matches the sphereEraser preview), so the
75009
+ * eraser no longer needs a sized PNG cursor — the ring tracks the live
75010
+ * `brushAndEraserSize` and is what the user resizes with Shift+wheel.
75011
+ *
75012
+ * Only the pencil has no preview ring (its stroke width is fixed).
75101
75013
  */
75102
- renderBrushPreview(ctx, width, height) {
75014
+ renderBrushPreview(ctx, _width, _height) {
75103
75015
  if (this.ctx.gui_states.mode.pencil ||
75104
- this.ctx.gui_states.mode.eraser ||
75105
75016
  !this.ctx.nrrd_states.interaction.mouseOver) {
75106
75017
  return;
75107
75018
  }
75108
- ctx.clearRect(0, 0, width, height);
75109
- ctx.fillStyle = this.ctx.gui_states.drawing.brushColor;
75019
+ const isEraser = this.ctx.gui_states.mode.eraser;
75020
+ // No clearRect here: DrawToolCore.start() clears drawingCtx once per frame
75021
+ // before compositing, and this ring is now drawn on top of the mask so it
75022
+ // stays visible during an active stroke (e.g. while Shift+wheel resizing).
75023
+ ctx.save();
75110
75024
  ctx.beginPath();
75111
75025
  ctx.arc(this.ctx.nrrd_states.interaction.mouseOverX, this.ctx.nrrd_states.interaction.mouseOverY, this.ctx.gui_states.drawing.brushAndEraserSize / 2 + 1, 0, Math.PI * 2);
75112
- ctx.strokeStyle = this.ctx.gui_states.drawing.brushColor;
75026
+ if (isEraser) {
75027
+ ctx.strokeStyle = "#ff4444";
75028
+ ctx.lineWidth = 2;
75029
+ ctx.setLineDash([4, 4]);
75030
+ }
75031
+ else {
75032
+ ctx.strokeStyle = this.ctx.gui_states.drawing.brushColor;
75033
+ }
75113
75034
  ctx.stroke();
75035
+ ctx.restore();
75114
75036
  }
75115
75037
  // ── Brush mode: direct voxel write ────────────────────────────
75116
75038
  /**
@@ -76251,7 +76173,6 @@ class DrawToolCore {
76251
76173
  handleOnContrastMouseUp: (ev) => { },
76252
76174
  handleOnContrastMouseLeave: (ev) => { },
76253
76175
  };
76254
- this.eraserUrls = [];
76255
76176
  this.pencilUrls = [];
76256
76177
  this.undoManager = new UndoManager();
76257
76178
  /** Slice index recorded when paintOnCanvas() starts, guards stale-click */
@@ -76326,7 +76247,6 @@ class DrawToolCore {
76326
76247
  filterDrawedImage: (axis, index) => this.renderer.filterDrawedImage(axis, index),
76327
76248
  getVolumeForLayer: (layer) => this.renderer.getVolumeForLayer(layer),
76328
76249
  pushUndoDelta: (delta) => this.undoManager.push(delta),
76329
- getEraserUrls: () => this.eraserUrls,
76330
76250
  renderSliceToCanvas: (layer, axis, sliceIndex, buffer, ctx, w, h) => this.renderer.renderSliceToCanvas(layer, axis, sliceIndex, buffer, ctx, w, h),
76331
76251
  getOrCreateSliceBuffer: (axis) => this.renderer.getOrCreateSliceBuffer(axis),
76332
76252
  });
@@ -76338,7 +76258,6 @@ class DrawToolCore {
76338
76258
  getOrCreateSliceBuffer: (axis) => this.renderer.getOrCreateSliceBuffer(axis),
76339
76259
  setEmptyCanvasSize: (axis) => this.setEmptyCanvasSize(axis),
76340
76260
  reloadMasksFromVolume: () => this.reloadMasksFromVolume(),
76341
- getEraserUrls: () => this.eraserUrls,
76342
76261
  });
76343
76262
  }
76344
76263
  initDrawToolCore() {
@@ -76493,6 +76412,12 @@ class DrawToolCore {
76493
76412
  });
76494
76413
  // Register wheel handler with EventRouter
76495
76414
  this.eventRouter.setWheelHandler((e) => {
76415
+ // Shift + wheel resizes the brush/eraser (like sphereBrush/sphereEraser
76416
+ // radius), independent of whether the left button is held. Consumes the
76417
+ // event so it never falls through to zoom/slice. Pencil is excluded even
76418
+ // though it also uses Shift — see tryBrushEraserResizeWheel.
76419
+ if (this.tryBrushEraserResizeWheel(e))
76420
+ return;
76496
76421
  if (this.activeWheelMode === 'zoom') {
76497
76422
  this.drawingPrameters.handleMouseZoomSliceWheel(e);
76498
76423
  }
@@ -76506,8 +76431,47 @@ class DrawToolCore {
76506
76431
  // Bind all event listeners
76507
76432
  this.eventRouter.bindAll();
76508
76433
  }
76509
- setEraserUrls(urls) {
76510
- this.eraserUrls = urls;
76434
+ /**
76435
+ * Shift + mouse-wheel resize for the brush and eraser tools.
76436
+ *
76437
+ * Mirrors the sphereBrush/sphereEraser "scroll to change radius" UX so the
76438
+ * user no longer has to reach for the B&E Size slider mid-annotation. Active
76439
+ * whenever the EventRouter is in `draw` mode (i.e. Shift is held — with or
76440
+ * without the left button down) and the current tool is brush or eraser.
76441
+ *
76442
+ * Pencil is deliberately excluded: it also draws with Shift, but its stroke
76443
+ * width is fixed and unrelated to `brushAndEraserSize`. Sphere-family tools
76444
+ * keep their own wheel-radius handler (`activeWheelMode === 'sphereBrush'`).
76445
+ *
76446
+ * `gui_states.mode` is the source of truth for the active tool here, not
76447
+ * `eventRouter.getGuiTool()` — the latter is only updated for sphere tools.
76448
+ *
76449
+ * @returns true if the event was handled (and should not fall through to
76450
+ * the zoom/slice/sphere wheel handlers).
76451
+ */
76452
+ tryBrushEraserResizeWheel(e) {
76453
+ // `draw` mode means Shift is held and neither crosshair nor contrast is
76454
+ // active (EventRouter only enters it for drawing tools under those rules),
76455
+ // so it doubles as the "Shift held, not blocked" gate.
76456
+ if (this.eventRouter.getMode() !== 'draw')
76457
+ return false;
76458
+ const mode = this.state.gui_states.mode;
76459
+ // Brush = no flag set; eraser = mode.eraser. Exclude pencil and all
76460
+ // sphere-family tools.
76461
+ if (mode.pencil || mode.sphere || mode.sphereBrush || mode.sphereEraser) {
76462
+ return false;
76463
+ }
76464
+ e.preventDefault();
76465
+ const drawing = this.state.gui_states.drawing;
76466
+ // Step/bounds match the B&E Size slider config (min 5, max 50, step 1).
76467
+ const next = Math.max(5, Math.min(50, drawing.brushAndEraserSize + (e.deltaY < 0 ? 1 : -1)));
76468
+ if (next === drawing.brushAndEraserSize)
76469
+ return true;
76470
+ drawing.brushAndEraserSize = next;
76471
+ // Both brush and eraser draw a size-preview ring in start() that reads
76472
+ // brushAndEraserSize live, so the new size shows up on the next frame with
76473
+ // no extra work here.
76474
+ return true;
76511
76475
  }
76512
76476
  setPencilIconUrls(urls) {
76513
76477
  this.pencilUrls = urls;
@@ -76676,6 +76640,7 @@ class DrawToolCore {
76676
76640
  this.state.protectedData.ctxes.drawingCtx.clearRect(0, 0, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
76677
76641
  this.state.protectedData.ctxes.drawingCtx.globalAlpha =
76678
76642
  this.state.gui_states.drawing.globalAlpha;
76643
+ const currentMode = this.eventRouter.getMode();
76679
76644
  if (this.state.protectedData.isDrawing) {
76680
76645
  this.state.protectedData.ctxes.drawingLayerMasterCtx.lineCap = "round";
76681
76646
  this.state.protectedData.ctxes.drawingLayerMasterCtx.globalAlpha = 1;
@@ -76684,16 +76649,18 @@ class DrawToolCore {
76684
76649
  target.ctx.globalAlpha = 1;
76685
76650
  }
76686
76651
  }
76687
- else {
76688
- const currentMode = this.eventRouter.getMode();
76689
- if (currentMode === 'draw') {
76690
- this.drawingTool.renderBrushPreview(this.state.protectedData.ctxes.drawingCtx, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
76691
- }
76692
- else if (currentMode === 'crosshair' || this.eventRouter.isCrosshairEnabled()) {
76693
- this.crosshairTool.renderCrosshair(this.state.protectedData.ctxes.drawingCtx, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
76694
- }
76652
+ else if (currentMode === 'crosshair' || this.eventRouter.isCrosshairEnabled()) {
76653
+ this.crosshairTool.renderCrosshair(this.state.protectedData.ctxes.drawingCtx, this.state.nrrd_states.view.changedWidth, this.state.nrrd_states.view.changedHeight);
76695
76654
  }
76696
76655
  this.state.protectedData.ctxes.drawingCtx.drawImage(this.state.protectedData.canvases.drawingCanvasLayerMaster, 0, 0);
76656
+ // Brush/eraser size ring is drawn AFTER the mask composite so it stays
76657
+ // visible during an active stroke (not just on hover) — e.g. while the
76658
+ // user resizes with Shift+wheel mid-paint. Gated on draw mode so it only
76659
+ // shows for brush/eraser with Shift held (renderBrushPreview itself
76660
+ // skips pencil and the no-hover case).
76661
+ if (currentMode === 'draw') {
76662
+ this.drawingTool.renderBrushPreview(this.state.protectedData.ctxes.drawingCtx);
76663
+ }
76697
76664
  if (this.state.gui_states.mode.sphere
76698
76665
  || this.state.gui_states.mode.sphereBrush
76699
76666
  || this.state.gui_states.mode.sphereEraser) {
@@ -78405,7 +78372,6 @@ class NrrdTools {
78405
78372
  nrrd_states: this.state.nrrd_states,
78406
78373
  drawingCanvas: this.state.protectedData.canvases.drawingCanvas,
78407
78374
  drawingPrameters: this.drawCore.drawingPrameters,
78408
- eraserUrls: this.drawCore.eraserUrls,
78409
78375
  pencilUrls: this.drawCore.pencilUrls,
78410
78376
  mainPreSlices: this.state.protectedData.mainPreSlices,
78411
78377
  protectedData: this.state.protectedData,
@@ -78438,13 +78404,18 @@ class NrrdTools {
78438
78404
  this.guiCallbacks = {
78439
78405
  updatePencilState: this.guiParameterSettings.pencil.onChange,
78440
78406
  updateEraserState: this.guiParameterSettings.eraser.onChange,
78441
- updateBrushAndEraserSize: this.guiParameterSettings.brushAndEraserSize.onChange,
78442
78407
  updateSphereState: this.guiParameterSettings.sphere.onChange,
78443
78408
  updateCalDistance: this.guiParameterSettings.activeSphereType.onChange,
78444
78409
  updateWindowHigh: this.guiParameterSettings.windowHigh.onChange,
78445
78410
  updateWindowLow: this.guiParameterSettings.windowLow.onChange,
78446
78411
  finishContrastAdjustment: this.guiParameterSettings.windowHigh.onFinished,
78447
78412
  };
78413
+ // setupGUI may run AFTER images are loaded (e.g. the register/origin-switch load
78414
+ // path), in which case the on-load syncGuiParameterSettings() ran while
78415
+ // guiParameterSettings was still undefined and silently skipped the binding. Bind
78416
+ // now so the window slider reflects the current volume's real min/max/window instead
78417
+ // of the default 0/0 (which froze the slider and turned the image white on zoom).
78418
+ this.syncGuiParameterSettings();
78448
78419
  }
78449
78420
  /**
78450
78421
  * Sync guiParameterSettings with current volume metadata.
@@ -78551,9 +78522,9 @@ class NrrdTools {
78551
78522
  return this.state.gui_states.drawing.globalAlpha;
78552
78523
  }
78553
78524
  setBrushSize(size) {
78554
- var _a;
78525
+ // No cursor side-effect needed: the brush/eraser preview ring reads this
78526
+ // value live each frame (see DrawingTool.renderBrushPreview).
78555
78527
  this.state.gui_states.drawing.brushAndEraserSize = Math.max(5, Math.min(50, size));
78556
- (_a = this.guiCallbacks) === null || _a === void 0 ? void 0 : _a.updateBrushAndEraserSize();
78557
78528
  }
78558
78529
  getBrushSize() {
78559
78530
  return this.state.gui_states.drawing.brushAndEraserSize;
@@ -78788,9 +78759,6 @@ class NrrdTools {
78788
78759
  enableContrastDragEvents(callback) {
78789
78760
  this.drawCore.setupConrastEvents(callback);
78790
78761
  }
78791
- setEraserUrls(urls) {
78792
- this.drawCore.setEraserUrls(urls);
78793
- }
78794
78762
  setPencilIconUrls(urls) {
78795
78763
  this.drawCore.setPencilIconUrls(urls);
78796
78764
  }
@@ -79480,7 +79448,7 @@ function evaluateElement(element, weights) {
79480
79448
  }
79481
79449
 
79482
79450
  // import * as kiwrious from "copper3d_plugin_heart_k";
79483
- const REVISION = "v3.4.6-beta";
79451
+ const REVISION = "v3.4.8-beta";
79484
79452
  console.log(`%cCopper3D Visualisation %cBeta:${REVISION}`, "padding: 3px;color:white; background:#023047", "padding: 3px;color:white; background:#f50a25");
79485
79453
 
79486
79454
  export { CHANNEL_COLORS, CHANNEL_HEX_COLORS, CameraViewPoint, Copper3dTrackballControls, GaussianSmoother, MeshNodeTool, NrrdTools, REVISION, addBoxHelper, addLabelToScene, configKiwriousHeart, convert3DPostoScreenPos, convertScreenPosto3DPos, copperMScene, copperMSceneRenderer, copperRenderer, copperRendererOnDemond, copperScene, copperSceneOnDemond, createTexture2D_NRRD, fullScreenListenner, kiwrious, loading, removeGuiFolderChilden, rgbaToCss, rgbaToHex, setHDRFilePath, throttle };