kritzel-stencil 0.3.11 → 0.3.13

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 (178) hide show
  1. package/dist/cjs/{index-CFnj_FXt.js → index-Xav9JFHg.js} +1 -1
  2. package/dist/cjs/index.cjs.js +41 -3
  3. package/dist/cjs/kritzel-active-users_42.cjs.entry.js +344 -138
  4. package/dist/cjs/kritzel-brush-style.cjs.entry.js +1 -1
  5. package/dist/cjs/loader.cjs.js +2 -2
  6. package/dist/cjs/{schema.constants-BNMNpzvA.js → schema.constants-CMFOYyBj.js} +26 -43
  7. package/dist/cjs/stencil.cjs.js +3 -3
  8. package/dist/collection/classes/core/viewport.class.js +16 -8
  9. package/dist/collection/classes/objects/shape.class.js +3 -2
  10. package/dist/collection/classes/tools/base-tool.class.js +2 -0
  11. package/dist/collection/classes/tools/brush-tool.class.js +1 -0
  12. package/dist/collection/classes/tools/eraser-tool.class.js +1 -0
  13. package/dist/collection/classes/tools/image-tool.class.js +1 -0
  14. package/dist/collection/classes/tools/line-tool.class.js +1 -0
  15. package/dist/collection/classes/tools/selection-tool.class.js +1 -0
  16. package/dist/collection/classes/tools/shape-tool.class.js +1 -0
  17. package/dist/collection/classes/tools/text-tool.class.js +1 -0
  18. package/dist/collection/collection-manifest.json +1 -1
  19. package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +166 -22
  20. package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +408 -37
  21. package/dist/collection/components/shared/kritzel-dropdown/kritzel-dropdown.css +3 -3
  22. package/dist/collection/components/shared/kritzel-input/kritzel-input.css +1 -1
  23. package/dist/collection/components/shared/kritzel-numeric-input/kritzel-numeric-input.css +2 -2
  24. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.css +7 -0
  25. package/dist/collection/components/ui/kritzel-context-menu/kritzel-context-menu.js +7 -1
  26. package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +27 -6
  27. package/dist/collection/components/ui/kritzel-export/kritzel-export.css +1 -1
  28. package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +2 -2
  29. package/dist/collection/configs/default-asset-storage.config.js +1 -2
  30. package/dist/collection/configs/default-brush-tool.config.js +1 -0
  31. package/dist/collection/configs/default-line-tool.config.js +1 -0
  32. package/dist/collection/configs/default-shape-tool.config.js +1 -0
  33. package/dist/collection/configs/default-sync.config.js +2 -5
  34. package/dist/collection/configs/default-text-tool.config.js +1 -0
  35. package/dist/collection/constants/version.js +1 -1
  36. package/dist/collection/helpers/tool-config.helper.js +58 -65
  37. package/dist/collection/interfaces/tool-type.interface.js +1 -0
  38. package/dist/collection/themes/dark-theme.js +5 -0
  39. package/dist/collection/themes/light-theme.js +5 -0
  40. package/dist/components/index.js +1 -1
  41. package/dist/components/kritzel-active-users.js +1 -1
  42. package/dist/components/kritzel-avatar.js +1 -1
  43. package/dist/components/kritzel-awareness-cursors.js +1 -1
  44. package/dist/components/kritzel-back-to-content.js +1 -1
  45. package/dist/components/kritzel-brush-style.js +1 -1
  46. package/dist/components/kritzel-button.js +1 -1
  47. package/dist/components/kritzel-color-palette.js +1 -1
  48. package/dist/components/kritzel-color.js +1 -1
  49. package/dist/components/kritzel-context-menu.js +1 -1
  50. package/dist/components/kritzel-controls.js +1 -1
  51. package/dist/components/kritzel-current-user-dialog.js +1 -1
  52. package/dist/components/kritzel-current-user.js +1 -1
  53. package/dist/components/kritzel-cursor-trail.js +1 -1
  54. package/dist/components/kritzel-dialog.js +1 -1
  55. package/dist/components/kritzel-dropdown.js +1 -1
  56. package/dist/components/kritzel-editor.js +1 -1
  57. package/dist/components/kritzel-engine.js +1 -1
  58. package/dist/components/kritzel-export.js +1 -1
  59. package/dist/components/kritzel-font-family.js +1 -1
  60. package/dist/components/kritzel-font-size.js +1 -1
  61. package/dist/components/kritzel-font.js +1 -1
  62. package/dist/components/kritzel-icon.js +1 -1
  63. package/dist/components/kritzel-input.js +1 -1
  64. package/dist/components/kritzel-line-endings.js +1 -1
  65. package/dist/components/kritzel-login-dialog.js +1 -1
  66. package/dist/components/kritzel-master-detail.js +1 -1
  67. package/dist/components/kritzel-menu-item.js +1 -1
  68. package/dist/components/kritzel-menu.js +1 -1
  69. package/dist/components/kritzel-more-menu.js +1 -1
  70. package/dist/components/kritzel-numeric-input.js +1 -1
  71. package/dist/components/kritzel-opacity-slider.js +1 -1
  72. package/dist/components/kritzel-pill-tabs.js +1 -1
  73. package/dist/components/kritzel-portal.js +1 -1
  74. package/dist/components/kritzel-settings.js +1 -1
  75. package/dist/components/kritzel-shape-fill.js +1 -1
  76. package/dist/components/kritzel-share-dialog.js +1 -1
  77. package/dist/components/kritzel-slide-toggle.js +1 -1
  78. package/dist/components/kritzel-split-button.js +1 -1
  79. package/dist/components/kritzel-stroke-size.js +1 -1
  80. package/dist/components/kritzel-tool-config.js +1 -1
  81. package/dist/components/kritzel-tooltip.js +1 -1
  82. package/dist/components/kritzel-utility-panel.js +1 -1
  83. package/dist/components/kritzel-workspace-manager.js +1 -1
  84. package/dist/components/p-2xYAGd0I.js +1 -0
  85. package/dist/components/{p-DdmJquQr.js → p-B2Os1ya_.js} +1 -1
  86. package/dist/components/p-B2w8X7vn.js +1 -0
  87. package/dist/components/{p-DRB3TZzI.js → p-B4b6TDxp.js} +1 -1
  88. package/dist/components/p-B5xxfwKF.js +1 -0
  89. package/dist/components/p-B9hLySCl.js +1 -0
  90. package/dist/components/{p-D0aom7Yu.js → p-BFYtCsZu.js} +1 -1
  91. package/dist/components/{p-CARNM9pf.js → p-BFoK4W--.js} +1 -1
  92. package/dist/components/{p-x38RbGJA.js → p-BYmp9Ovv.js} +1 -1
  93. package/dist/components/{p-KVG5rztB.js → p-BbactVA0.js} +1 -1
  94. package/dist/components/{p-B_JH91jB.js → p-BfNHpqQ8.js} +1 -1
  95. package/dist/components/{p-DXgUuzXW.js → p-BiG1dxPS.js} +1 -1
  96. package/dist/components/{p-Dov3qOAR.js → p-Bj2laX89.js} +1 -1
  97. package/dist/components/{p-Cr7xOsIZ.js → p-BqwqGFQY.js} +1 -1
  98. package/dist/components/{p-DmTG0Y5h.js → p-BzYU3-MJ.js} +1 -1
  99. package/dist/components/p-C-aFOO5p.js +1 -0
  100. package/dist/components/p-C0TN5IAi.js +1 -0
  101. package/dist/components/{p-RnuCSIt-.js → p-C2SX-XRr.js} +1 -1
  102. package/dist/components/{p-guqEWGgV.js → p-CFgkUYoO.js} +1 -1
  103. package/dist/components/{p-BTSOqHMI.js → p-CHrSFOSI.js} +1 -1
  104. package/dist/components/p-CJOhfMU5.js +1 -0
  105. package/dist/components/{p-DJLJfKY2.js → p-COLHjboZ.js} +1 -1
  106. package/dist/components/{p-CKY7AvGR.js → p-COgo9OWy.js} +1 -1
  107. package/dist/components/p-CVzH1Oil.js +1 -0
  108. package/dist/components/{p-DhAM4qeQ.js → p-CXpv9Rxe.js} +1 -1
  109. package/dist/components/{p-Bp3kdH4l.js → p-CcyIAi9S.js} +1 -1
  110. package/dist/components/{p-COIxq81R.js → p-CmuNn1Tc.js} +1 -1
  111. package/dist/components/{p-DfH7YY2C.js → p-D-sRVAbQ.js} +1 -1
  112. package/dist/components/{p-ZgZqbJ58.js → p-DDYoDSrm.js} +1 -1
  113. package/dist/components/{p-u0b2RJAn.js → p-DEy7zJCe.js} +1 -1
  114. package/dist/components/{p-BPEn0_hr.js → p-DM11KXUT.js} +1 -1
  115. package/dist/components/{p-CJERvHdy.js → p-DbB730vO.js} +1 -1
  116. package/dist/components/{p-C8ggg-5h.js → p-Df3BwVGy.js} +1 -1
  117. package/dist/components/{p-Dx_xz_El.js → p-DlwYHzSj.js} +1 -1
  118. package/dist/components/p-DplAQ6jk.js +9 -0
  119. package/dist/components/{p-CJ2V42sz.js → p-FK7b3BGt.js} +1 -1
  120. package/dist/components/{p-CxtTuKCy.js → p-JhOYwUOj.js} +1 -1
  121. package/dist/components/{p-Dw9sKOsb.js → p-SptaSMno.js} +1 -1
  122. package/dist/components/{p-KjtNlFTl.js → p-UoPj5QjH.js} +1 -1
  123. package/dist/components/{p-CYR9wbJg.js → p-dcAernE1.js} +1 -1
  124. package/dist/components/{p-B0VnbmWu.js → p-ijIqLY9g.js} +1 -1
  125. package/dist/components/{p-BI_UUiTr.js → p-skWUIStn.js} +1 -1
  126. package/dist/components/{p-DgtrNOWm.js → p-x6doYeiI.js} +1 -1
  127. package/dist/esm/{index-D9HaikfQ.js → index-Dhio9uis.js} +1 -1
  128. package/dist/esm/index.js +42 -4
  129. package/dist/esm/kritzel-active-users_42.entry.js +344 -138
  130. package/dist/esm/kritzel-brush-style.entry.js +1 -1
  131. package/dist/esm/loader.js +3 -3
  132. package/dist/esm/{schema.constants-CqBoZbmA.js → schema.constants-NrtFvKER.js} +27 -43
  133. package/dist/esm/stencil.js +4 -4
  134. package/dist/stencil/index.esm.js +1 -1
  135. package/dist/stencil/p-9adee165.entry.js +9 -0
  136. package/dist/stencil/p-NrtFvKER.js +1 -0
  137. package/dist/stencil/{p-69298b5f.entry.js → p-fb32cd8f.entry.js} +1 -1
  138. package/dist/stencil/stencil.esm.js +1 -1
  139. package/dist/types/classes/core/viewport.class.d.ts +8 -0
  140. package/dist/types/classes/objects/base-object.class.d.ts +1 -1
  141. package/dist/types/classes/objects/shape.class.d.ts +1 -1
  142. package/dist/types/classes/tools/base-tool.class.d.ts +3 -0
  143. package/dist/types/classes/tools/brush-tool.class.d.ts +1 -0
  144. package/dist/types/classes/tools/eraser-tool.class.d.ts +1 -0
  145. package/dist/types/classes/tools/image-tool.class.d.ts +1 -0
  146. package/dist/types/classes/tools/line-tool.class.d.ts +1 -0
  147. package/dist/types/classes/tools/selection-tool.class.d.ts +1 -0
  148. package/dist/types/classes/tools/shape-tool.class.d.ts +1 -0
  149. package/dist/types/classes/tools/text-tool.class.d.ts +1 -0
  150. package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +5 -0
  151. package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +48 -0
  152. package/dist/types/components/ui/kritzel-context-menu/kritzel-context-menu.d.ts +1 -0
  153. package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +1 -0
  154. package/dist/types/components.d.ts +69 -14
  155. package/dist/types/configs/default-asset-storage.config.d.ts +1 -1
  156. package/dist/types/configs/default-sync.config.d.ts +1 -1
  157. package/dist/types/constants/version.d.ts +1 -1
  158. package/dist/types/interfaces/object.interface.d.ts +1 -1
  159. package/dist/types/interfaces/theme.interface.d.ts +8 -3
  160. package/dist/types/interfaces/tool-config.interface.d.ts +3 -6
  161. package/dist/types/interfaces/tool-type.interface.d.ts +1 -0
  162. package/dist/types/interfaces/tool.interface.d.ts +1 -0
  163. package/dist/types/interfaces/toolbar-control.interface.d.ts +4 -0
  164. package/dist/types/stencil-public-runtime.d.ts +1 -0
  165. package/package.json +1 -1
  166. package/dist/components/p-BFgWBbpu.js +0 -1
  167. package/dist/components/p-C0wFAtT_.js +0 -1
  168. package/dist/components/p-CB7ynHtI.js +0 -1
  169. package/dist/components/p-CWgI1dA0.js +0 -1
  170. package/dist/components/p-D15NO5kE.js +0 -1
  171. package/dist/components/p-DH-H7om7.js +0 -1
  172. package/dist/components/p-DLlIaDNn.js +0 -9
  173. package/dist/components/p-IiG44Unz.js +0 -1
  174. package/dist/components/p-K7ySy791.js +0 -1
  175. package/dist/stencil/p-94992a11.entry.js +0 -9
  176. package/dist/stencil/p-CqBoZbmA.js +0 -1
  177. /package/dist/components/{p-BWj1eE2b.js → p-B43upypT.js} +0 -0
  178. /package/dist/stencil/{p-D9HaikfQ.js → p-Dhio9uis.js} +0 -0
@@ -93,8 +93,18 @@ export class KritzelEngine {
93
93
  }
94
94
  /** Context menu items shown when right-clicking the canvas background. */
95
95
  globalContextMenuItems;
96
+ onGlobalContextMenuItemsChange(newValue) {
97
+ if (this.contextMenuHandler) {
98
+ this.contextMenuHandler.globalContextMenuItems = newValue ?? [];
99
+ }
100
+ }
96
101
  /** Context menu items shown when right-clicking a selected object. */
97
102
  objectContextMenuItems;
103
+ onObjectContextMenuItemsChange(newValue) {
104
+ if (this.contextMenuHandler) {
105
+ this.contextMenuHandler.objectContextMenuItems = newValue ?? [];
106
+ }
107
+ }
98
108
  /** Maximum zoom scale allowed. Clamped to the absolute maximum defined by the engine. */
99
109
  scaleMax = ABSOLUTE_SCALE_MAX;
100
110
  validateScaleMax(newValue) {
@@ -129,6 +139,11 @@ export class KritzelEngine {
129
139
  onLockDrawingScaleChange(newValue) {
130
140
  this.core.store.state.lockDrawingScale = newValue;
131
141
  }
142
+ /** When true, objects fade based on distance to the viewport center. */
143
+ isObjectDistanceFadingActive = false;
144
+ onIsObjectDistanceFadingActiveChange() {
145
+ this.core.rerender();
146
+ }
132
147
  /** The current theme to apply to the editor */
133
148
  theme = 'light';
134
149
  onThemeChange(newValue) {
@@ -563,7 +578,7 @@ export class KritzelEngine {
563
578
  this.core.deselectAllObjects();
564
579
  object.id = object.generateId();
565
580
  object._core = this.core;
566
- object.scale = this.core.store.state.scale;
581
+ object.scale = object.scale ?? this.core.store.state.scale;
567
582
  object.zIndex = this.core.store.currentZIndex;
568
583
  object.workspaceId = this.core.store.state.activeWorkspace.id;
569
584
  // Handle KritzelText: recreate the editor now that _core is available
@@ -592,7 +607,7 @@ export class KritzelEngine {
592
607
  const oldId = child.id;
593
608
  child.id = child.generateId();
594
609
  child._core = this.core;
595
- child.scale = this.core.store.state.scale;
610
+ child.scale = child.scale ?? this.core.store.state.scale;
596
611
  child.zIndex = this.core.store.currentZIndex;
597
612
  child.workspaceId = this.core.store.state.activeWorkspace.id;
598
613
  idRemapping.set(oldId, child.id);
@@ -638,6 +653,82 @@ export class KritzelEngine {
638
653
  this.emitObjectsAdded([object]);
639
654
  return object;
640
655
  }
656
+ /**
657
+ * Adds multiple objects to the canvas in a single batch operation.
658
+ * All objects are inserted within one Yjs transaction (single undo step),
659
+ * triggering only one rerender cycle. Intended for programmatic streaming
660
+ * scenarios where per-object overhead would cause stutter.
661
+ * @param objects - The object instances to add.
662
+ * @returns The added objects.
663
+ */
664
+ async addObjects(objects) {
665
+ if (objects.length === 0) {
666
+ return [];
667
+ }
668
+ this.core.store.objects.transaction(() => {
669
+ for (const object of objects) {
670
+ object.id = object.generateId();
671
+ object._core = this.core;
672
+ object.zIndex = this.core.store.currentZIndex;
673
+ object.workspaceId = this.core.store.state.activeWorkspace.id;
674
+ if (KritzelClassHelper.isInstanceOf(object, 'KritzelText')) {
675
+ const pendingContent = object.content;
676
+ object.editor = object.createEditor();
677
+ if (pendingContent) {
678
+ object.setContent(pendingContent);
679
+ }
680
+ }
681
+ if (KritzelClassHelper.isInstanceOf(object, 'KritzelGroup') && object._pendingChildren.length > 0) {
682
+ const idRemapping = new Map();
683
+ const allFlushedChildren = [];
684
+ const flushGroup = (group) => {
685
+ if (group._pendingChildren.length === 0) {
686
+ return;
687
+ }
688
+ const pending = group._pendingChildren;
689
+ group._pendingChildren = [];
690
+ group.childIds = [];
691
+ pending.forEach(child => {
692
+ const oldId = child.id;
693
+ child.id = child.generateId();
694
+ child._core = this.core;
695
+ child.zIndex = this.core.store.currentZIndex;
696
+ child.workspaceId = this.core.store.state.activeWorkspace.id;
697
+ idRemapping.set(oldId, child.id);
698
+ group.childIds.push(child.id);
699
+ allFlushedChildren.push(child);
700
+ if (KritzelClassHelper.isInstanceOf(child, 'KritzelGroup')) {
701
+ flushGroup(child);
702
+ }
703
+ });
704
+ };
705
+ flushGroup(object);
706
+ allFlushedChildren.forEach(child => {
707
+ if (KritzelClassHelper.isInstanceOf(child, 'KritzelLine')) {
708
+ if (child.startAnchor && idRemapping.has(child.startAnchor.objectId)) {
709
+ child.startAnchor = { objectId: idRemapping.get(child.startAnchor.objectId) };
710
+ }
711
+ if (child.endAnchor && idRemapping.has(child.endAnchor.objectId)) {
712
+ child.endAnchor = { objectId: idRemapping.get(child.endAnchor.objectId) };
713
+ }
714
+ }
715
+ });
716
+ allFlushedChildren.forEach(child => {
717
+ this.core.addObject(child);
718
+ });
719
+ object.finalize();
720
+ this.core.anchorManager.rebuildIndex();
721
+ }
722
+ this.core.addObject(object);
723
+ }
724
+ });
725
+ this.core.rerender();
726
+ await new Promise(resolve => {
727
+ requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
728
+ });
729
+ this.emitObjectsAdded(objects);
730
+ return objects;
731
+ }
641
732
  /**
642
733
  * Updates properties of an existing canvas object.
643
734
  * @param object - The object to update.
@@ -667,6 +758,28 @@ export class KritzelEngine {
667
758
  this.emitObjectsRemoved([object]);
668
759
  return object;
669
760
  }
761
+ /**
762
+ * Removes multiple objects from the canvas in a single batch operation.
763
+ * All removals happen within one Yjs transaction (single undo step),
764
+ * triggering only one rerender cycle. Intended for programmatic streaming
765
+ * scenarios where per-object overhead would cause stutter.
766
+ * @param objects - The objects to remove.
767
+ * @returns The removed objects.
768
+ */
769
+ async removeObjects(objects) {
770
+ const objectsMap = this.core.store.objects;
771
+ if (!objectsMap || objects.length === 0) {
772
+ return [];
773
+ }
774
+ objectsMap.transaction(() => {
775
+ for (const object of objects) {
776
+ this.core.removeObject(object);
777
+ }
778
+ });
779
+ this.core.rerender();
780
+ this.emitObjectsRemoved(objects);
781
+ return objects;
782
+ }
670
783
  /** Returns the currently selected objects. Returns an empty array if nothing is selected. */
671
784
  async getSelectedObjects() {
672
785
  const selectionGroup = this.core.store.selectionGroup;
@@ -716,6 +829,14 @@ export class KritzelEngine {
716
829
  this.core.rerender();
717
830
  return object;
718
831
  }
832
+ /**
833
+ * Pans the viewport to center on the given object without changing the zoom level.
834
+ * Unlike `centerObjectInViewport`, this moves the camera — not the object.
835
+ * @param object - The object whose center the viewport should pan to.
836
+ */
837
+ async panToObject(object) {
838
+ this.viewport.panTo(object.centerX, object.centerY);
839
+ }
719
840
  /**
720
841
  * Pans and zooms the viewport to fit the nearest content, with padding.
721
842
  * Useful when the user has panned away from all objects.
@@ -733,6 +854,16 @@ export class KritzelEngine {
733
854
  async centerAllObjects(animate = true) {
734
855
  return this.viewport.centerFitAllObjects(animate);
735
856
  }
857
+ /**
858
+ * Pans and zooms the viewport to fit the provided objects.
859
+ * Calculates the combined bounding box of the given objects and centers the viewport to show them.
860
+ * @param objects - The objects to center and fit in the viewport.
861
+ * @param animate - Whether to animate the viewport transition (default: true).
862
+ * @returns `true` if objects were provided and the viewport was adjusted, `false` otherwise.
863
+ */
864
+ async centerObjects(objects, animate = true) {
865
+ return this.viewport.centerFitObjects(objects, animate);
866
+ }
736
867
  /**
737
868
  * Sets the viewport to center on the given world coordinates at the specified scale.
738
869
  * @param x - X position in world coordinates to center on.
@@ -1321,6 +1452,12 @@ export class KritzelEngine {
1321
1452
  undoStackSize: 0,
1322
1453
  redoStackSize: 0,
1323
1454
  };
1455
+ _objectDistanceFadeNearScale = 1;
1456
+ _objectDistanceFadeFarScale = 0.15;
1457
+ _objectDistanceFadeMinOpacity = 0;
1458
+ _objectDistanceFadeCloseStartScale = 2;
1459
+ _objectDistanceFadeCloseMaxScale = 4;
1460
+ _objectDistanceFadeCloseMinOpacity = 0;
1324
1461
  syncLoadingState() {
1325
1462
  this.core.store.state.isLoading = this._isWorkspaceLoading || this.isLoading;
1326
1463
  }
@@ -1629,6 +1766,54 @@ export class KritzelEngine {
1629
1766
  KritzelKeyboardHelper.forceHideKeyboard();
1630
1767
  this.core.rerender();
1631
1768
  }
1769
+ getObjectDistanceFadeMultiplier(objectScale, viewportScale) {
1770
+ if (!this.isObjectDistanceFadingActive) {
1771
+ return 1;
1772
+ }
1773
+ const safeViewportScale = Math.max(Number.isFinite(viewportScale) ? viewportScale : 1, Number.EPSILON);
1774
+ const safeObjectScale = Math.max(Number.isFinite(objectScale) ? objectScale : 1, Number.EPSILON);
1775
+ const normalizedScale = safeViewportScale / safeObjectScale;
1776
+ const farFadeMultiplier = this.getFarDistanceFadeMultiplier(normalizedScale);
1777
+ const closeFadeMultiplier = this.getCloseDistanceFadeMultiplier(normalizedScale);
1778
+ return Math.min(farFadeMultiplier, closeFadeMultiplier);
1779
+ }
1780
+ getFarDistanceFadeMultiplier(normalizedScale) {
1781
+ if (normalizedScale >= this._objectDistanceFadeNearScale) {
1782
+ return 1;
1783
+ }
1784
+ if (normalizedScale <= this._objectDistanceFadeFarScale) {
1785
+ return this._objectDistanceFadeMinOpacity;
1786
+ }
1787
+ const progress = (this._objectDistanceFadeNearScale - normalizedScale) /
1788
+ (this._objectDistanceFadeNearScale - this._objectDistanceFadeFarScale);
1789
+ const smooth = progress * progress * (3 - 2 * progress);
1790
+ return 1 - smooth * (1 - this._objectDistanceFadeMinOpacity);
1791
+ }
1792
+ getCloseDistanceFadeMultiplier(normalizedScale) {
1793
+ if (normalizedScale <= this._objectDistanceFadeCloseStartScale) {
1794
+ return 1;
1795
+ }
1796
+ if (normalizedScale >= this._objectDistanceFadeCloseMaxScale) {
1797
+ return this._objectDistanceFadeCloseMinOpacity;
1798
+ }
1799
+ const progress = (normalizedScale - this._objectDistanceFadeCloseStartScale) /
1800
+ (this._objectDistanceFadeCloseMaxScale - this._objectDistanceFadeCloseStartScale);
1801
+ const smooth = progress * progress * (3 - 2 * progress);
1802
+ return 1 - smooth * (1 - this._objectDistanceFadeCloseMinOpacity);
1803
+ }
1804
+ shouldApplyDistanceFade(object) {
1805
+ return (!KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup') &&
1806
+ !KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionBox'));
1807
+ }
1808
+ getObjectEffectiveOpacity(object, viewportScale) {
1809
+ const safeObjectOpacity = Number.isFinite(object.opacity) ? object.opacity : 1;
1810
+ const distanceFadeMultiplier = this.shouldApplyDistanceFade(object)
1811
+ ? this.getObjectDistanceFadeMultiplier(object.scale, viewportScale)
1812
+ : 1;
1813
+ const multiplied = (object.markedForRemoval ? 0.5 : 1) * safeObjectOpacity * distanceFadeMultiplier;
1814
+ const overridden = ((object.markedForRemoval ? 0.5 : safeObjectOpacity) * distanceFadeMultiplier).toString();
1815
+ return { multiplied, overridden };
1816
+ }
1632
1817
  render() {
1633
1818
  if (!this.viewport) {
1634
1819
  return (h(Host, null, this.core.store.state.isLoading && (h("div", { class: "workspace-loading-overlay" }, h("span", { class: "workspace-loading-spinner" }), "Loading..."))));
@@ -1638,6 +1823,7 @@ export class KritzelEngine {
1638
1823
  const baseHandleSizePx = computedStyle.getPropertyValue('--kritzel-selection-handle-size').trim() || '6px';
1639
1824
  const baseHandleSize = parseFloat(baseHandleSizePx);
1640
1825
  const baseHandleTouchSize = baseHandleSize * 2 < 14 ? 14 : baseHandleSize;
1826
+ const viewportScale = this.core.store.state.scale;
1641
1827
  const viewportCenterX = this.core.store.state.viewportWidth / 2 + this.core.store.state.translateX;
1642
1828
  const viewportCenterY = this.core.store.state.viewportHeight / 2 + this.core.store.state.translateY;
1643
1829
  const visibleObjects = this.core.store.objectsInViewport;
@@ -1651,39 +1837,34 @@ export class KritzelEngine {
1651
1837
  return (h(Host, null, this.core.store.state.isLoading && (h("div", { class: "workspace-loading-overlay" }, h("span", { class: "workspace-loading-spinner" }), "Loading...")), this.core.store.state.debugInfo.showViewportInfo && (h("div", { class: "debug-panel" }, h("div", null, "ActiveWorkspaceId: ", this.core.store.state?.activeWorkspace?.id), h("div", null, "ActiveWorkspaceName: ", this.core.store.state?.activeWorkspace?.name), h("div", null, "TranslateX: ", this.core.store.state?.translateX), h("div", null, "TranslateY: ", this.core.store.state?.translateY), h("div", null, "ViewportWidth: ", this.core.store.state?.viewportWidth), h("div", null, "ViewportHeight: ", this.core.store.state?.viewportHeight), h("div", null, "PointerCount: ", this.core.store.state.pointers.size), h("div", null, "Scale: ", this.core.store.state?.scale), h("div", null, "ActiveTool: ", this.core.store.state?.activeTool?.name), h("div", null, "HasViewportChanged: ", this.core.store.state?.hasViewportChanged ? 'true' : 'false'), h("div", null, "IsEnabled: ", this.core.store.state?.isEnabled ? 'true' : 'false'), h("div", null, "IsScaling: ", this.core.store.state?.isScaling ? 'true' : 'false'), h("div", null, "IsPanning: ", this.core.store.state?.isPanning ? 'true' : 'false'), h("div", null, "IsSelecting: ", this.isSelecting ? 'true' : 'false'), h("div", null, "IsSelectionActive: ", this.isSelectionActive ? 'true' : 'false'), h("div", null, "IsResizeHandleSelected: ", this.core.store.state.isResizeHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleSelected: ", this.core.store.state.isRotationHandleSelected ? 'true' : 'false'), h("div", null, "IsRotationHandleHovered: ", this.core.store.state.isRotationHandleHovered ? 'true' : 'false'), h("div", null, "IsDrawing: ", this.core.store.state.isDrawing ? 'true' : 'false'), h("div", null, "IsWriting: ", this.core.store.state.isWriting ? 'true' : 'false'), h("div", null, "IsPointerDown: ", this.core.store.isPointerDown ? 'true' : 'false'), h("div", null, "PointerX: ", this.core.store.state?.pointerX), h("div", null, "PointerY: ", this.core.store.state?.pointerY), h("div", null, "TotalObjects: ", this.core.store.totalObjectCount), h("div", null, "ObjectsInViewport: ", this.core.store.objectsInViewport.length), h("div", null, "SelectedObjects: ", this.core.store.selectionGroup?.objects.length || 0), h("div", null, "ViewportCenter: (", viewportCenterX.toFixed(2), ", ", viewportCenterY.toFixed(2), ")"))), h("div", { id: "origin", class: "origin", style: {
1652
1838
  transform: `matrix(${this.core.store.state?.scale}, 0, 0, ${this.core.store.state?.scale}, ${this.core.store.state?.translateX}, ${this.core.store.state?.translateY})`,
1653
1839
  } }, visibleObjects?.map(object => {
1840
+ const { multiplied: effectiveOpacity, overridden: effectiveOpacityString } = this.getObjectEffectiveOpacity(object, viewportScale);
1654
1841
  return (h("div", { key: object.id, id: object.id, class: "object", style: {
1655
1842
  transform: object?.transformationMatrix,
1656
1843
  transformOrigin: 'top left',
1657
1844
  position: 'absolute',
1658
1845
  zIndex: object.zIndex.toString(),
1659
1846
  pointerEvents: this.core.store.state.isScaling ? 'none' : 'auto',
1660
- } }, KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (() => {
1661
- const effectiveOpacity = (object.markedForRemoval ? 0.5 : 1) * object.opacity;
1662
- return (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
1663
- height: object?.totalHeight + 'px',
1664
- width: object?.totalWidth + 'px',
1665
- left: '0',
1666
- top: '0',
1667
- position: 'absolute',
1668
- transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
1669
- transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1670
- pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1671
- overflow: 'visible',
1672
- }, viewBox: object?.viewBox }, h("path", { d: object?.d, fill: KritzelColorHelper.applyOpacity(object.fill, effectiveOpacity, currentTheme), stroke: KritzelColorHelper.applyOpacity(object?.stroke, effectiveOpacity, currentTheme), "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' })));
1673
- })(), KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (() => {
1674
- const effectiveOpacity = (object.markedForRemoval ? 0.5 : 1) * object.opacity;
1675
- return (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
1676
- height: object?.totalHeight + 'px',
1677
- width: object?.totalWidth + 'px',
1678
- left: '0',
1679
- top: '0',
1680
- position: 'absolute',
1681
- transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
1682
- transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1683
- pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1684
- overflow: 'visible',
1685
- }, viewBox: object?.viewBox }, (object.hasStartArrow || object.hasEndArrow) && (h("defs", null, object.hasStartArrow && (h("marker", { id: object.startMarkerId, markerWidth: object.getArrowSize('start'), markerHeight: object.getArrowSize('start'), refX: 0, refY: object.getArrowSize('start') / 2, orient: "auto-start-reverse", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.start?.style), fill: KritzelColorHelper.applyOpacity(object.getArrowFill('start'), effectiveOpacity), transform: `scale(${object.getArrowSize('start') / 10})` }))), object.hasEndArrow && (h("marker", { id: object.endMarkerId, markerWidth: object.getArrowSize('end'), markerHeight: object.getArrowSize('end'), refX: 0, refY: object.getArrowSize('end') / 2, orient: "auto", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.end?.style), fill: KritzelColorHelper.applyOpacity(object.getArrowFill('end'), effectiveOpacity), transform: `scale(${object.getArrowSize('end') / 10})` }))))), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: "transparent", "stroke-width": Math.max(object?.strokeWidth || 0, 10), "stroke-linecap": "round" }), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: KritzelColorHelper.applyOpacity(object?.stroke, effectiveOpacity, currentTheme), "stroke-width": object?.strokeWidth, "stroke-linecap": "round", "marker-start": object.hasStartArrow ? `url(#${object.startMarkerId})` : undefined, "marker-end": object.hasEndArrow ? `url(#${object.endMarkerId})` : undefined })));
1686
- })(), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && object.loadState === 'ready' && (h("img", { ref: el => el && object.mount(el), src: object.resolvedSrc || object.src, style: {
1847
+ } }, KritzelClassHelper.isInstanceOf(object, 'KritzelPath') && (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
1848
+ height: object?.totalHeight + 'px',
1849
+ width: object?.totalWidth + 'px',
1850
+ left: '0',
1851
+ top: '0',
1852
+ position: 'absolute',
1853
+ transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
1854
+ transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1855
+ pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1856
+ overflow: 'visible',
1857
+ }, viewBox: object?.viewBox }, h("path", { d: object?.d, fill: KritzelColorHelper.applyOpacity(object.fill, effectiveOpacity, currentTheme), stroke: KritzelColorHelper.applyOpacity(object?.stroke, effectiveOpacity, currentTheme), "shape-rendering": object.isLowRes() ? 'optimizeSpeed' : 'auto' }))), KritzelClassHelper.isInstanceOf(object, 'KritzelLine') && (h("svg", { ref: el => el && object.mount(el), xmlns: "http://www.w3.org/2000/svg", style: {
1858
+ height: object?.totalHeight + 'px',
1859
+ width: object?.totalWidth + 'px',
1860
+ left: '0',
1861
+ top: '0',
1862
+ position: 'absolute',
1863
+ transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
1864
+ transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1865
+ pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1866
+ overflow: 'visible',
1867
+ }, viewBox: object?.viewBox }, (object.hasStartArrow || object.hasEndArrow) && (h("defs", null, object.hasStartArrow && (h("marker", { id: object.startMarkerId, markerWidth: object.getArrowSize('start'), markerHeight: object.getArrowSize('start'), refX: 0, refY: object.getArrowSize('start') / 2, orient: "auto-start-reverse", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.start?.style), fill: KritzelColorHelper.applyOpacity(object.getArrowFill('start'), effectiveOpacity), transform: `scale(${object.getArrowSize('start') / 10})` }))), object.hasEndArrow && (h("marker", { id: object.endMarkerId, markerWidth: object.getArrowSize('end'), markerHeight: object.getArrowSize('end'), refX: 0, refY: object.getArrowSize('end') / 2, orient: "auto", markerUnits: "userSpaceOnUse" }, h("path", { d: object.getArrowPath(object.arrows?.end?.style), fill: KritzelColorHelper.applyOpacity(object.getArrowFill('end'), effectiveOpacity), transform: `scale(${object.getArrowSize('end') / 10})` }))))), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: "transparent", "stroke-width": Math.max(object?.strokeWidth || 0, 10), "stroke-linecap": "round" }), h("path", { d: this.core.anchorManager.computeClippedLinePath(object), fill: "none", stroke: KritzelColorHelper.applyOpacity(object?.stroke, effectiveOpacity, currentTheme), "stroke-width": object?.strokeWidth, "stroke-linecap": "round", "marker-start": object.hasStartArrow ? `url(#${object.startMarkerId})` : undefined, "marker-end": object.hasEndArrow ? `url(#${object.endMarkerId})` : undefined }))), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && object.loadState === 'ready' && (h("img", { ref: el => el && object.mount(el), src: object.resolvedSrc || object.src, style: {
1687
1868
  position: 'absolute',
1688
1869
  left: '0',
1689
1870
  top: '0',
@@ -1691,7 +1872,7 @@ export class KritzelEngine {
1691
1872
  height: object.totalHeight + 'px',
1692
1873
  transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
1693
1874
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1694
- opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
1875
+ opacity: effectiveOpacityString,
1695
1876
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1696
1877
  backgroundColor: KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
1697
1878
  borderColor: KritzelColorHelper.resolveThemeColor(object.borderColor, currentTheme),
@@ -1709,7 +1890,7 @@ export class KritzelEngine {
1709
1890
  height: object.totalHeight + 'px',
1710
1891
  transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
1711
1892
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1712
- opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
1893
+ opacity: effectiveOpacityString,
1713
1894
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1714
1895
  backgroundColor: KritzelColorHelper.resolveThemeColor({ light: '#e5e7eb', dark: '#2a2a2a' }, currentTheme),
1715
1896
  borderColor: object.loadState === 'error'
@@ -1733,7 +1914,7 @@ export class KritzelEngine {
1733
1914
  height: object.totalHeight + 'px',
1734
1915
  transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
1735
1916
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1736
- opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
1917
+ opacity: effectiveOpacityString,
1737
1918
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1738
1919
  backgroundColor: KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
1739
1920
  borderColor: KritzelColorHelper.resolveThemeColor(object.borderColor, currentTheme),
@@ -1774,7 +1955,7 @@ export class KritzelEngine {
1774
1955
  height: object.totalHeight + 'px',
1775
1956
  transform: object.rotationDegrees !== 0 ? `rotate(${object.rotationDegrees}deg)` : undefined,
1776
1957
  transformOrigin: object.rotationDegrees !== 0 ? `${object.totalWidth / 2}px ${object.totalHeight / 2}px` : undefined,
1777
- opacity: object.markedForRemoval ? '0.5' : object.opacity.toString(),
1958
+ opacity: effectiveOpacityString,
1778
1959
  pointerEvents: object.markedForRemoval ? 'none' : 'auto',
1779
1960
  } }, h("div", { id: "text-object", ref: el => el && object.mount(el), onPointerDown: e => object.handlePointerDown(e), onPointerMove: e => object.handlePointerMove(e), onPointerUp: e => object.handlePointerUp(e), style: {
1780
1961
  minWidth: object.initialWidth + 'px',
@@ -1787,7 +1968,6 @@ export class KritzelEngine {
1787
1968
  backgroundColor: KritzelColorHelper.resolveThemeColor(object.backgroundColor, currentTheme),
1788
1969
  overflow: 'visible',
1789
1970
  } }))), KritzelClassHelper.isInstanceOf(object, 'KritzelShape') && (() => {
1790
- const effectiveOpacity = (object.markedForRemoval ? 0.5 : 1) * object.opacity;
1791
1971
  const fillResolved = KritzelColorHelper.resolveThemeColor(object.fillColor, currentTheme);
1792
1972
  const strokeResolved = KritzelColorHelper.resolveThemeColor(object.strokeColor, currentTheme);
1793
1973
  const isFilled = !!fillResolved && fillResolved !== 'transparent';
@@ -1829,7 +2009,7 @@ export class KritzelEngine {
1829
2009
  left: `${object.totalWidth}px`,
1830
2010
  top: '0',
1831
2011
  zIndex: (object.zIndex + 2).toString(),
1832
- } }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "assetId: ", object.assetId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "mimeType: ", object.mimeType))))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
2012
+ } }, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "Id: ", object.id), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "userId: ", object.userId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "width: ", object.width), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "height: ", object.height), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateX: ", object.translateX), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "translateY: ", object.translateY), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "scale: ", object.scale), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "rotationDegrees: ", object.rotationDegrees), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "zIndex: ", object.zIndex), KritzelClassHelper.isInstanceOf(object, 'KritzelImage') && (h("div", null, h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "assetId: ", object.assetId), h("div", { style: { whiteSpace: 'nowrap', fontSize: '10px' } }, "mimeType: ", object.mimeType))))), (this.core.displaySelectionGroupUI(object) || this.core.displaySelectionLineUI(object)) &&
1833
2013
  (() => {
1834
2014
  const isSelectionGroup = KritzelClassHelper.isInstanceOf(object, 'KritzelSelectionGroup');
1835
2015
  const localClientId = this.core.store.objects?.localClientId;
@@ -2290,7 +2470,7 @@ export class KritzelEngine {
2290
2470
  "setter": false,
2291
2471
  "reflect": false,
2292
2472
  "attribute": "scale-max",
2293
- "defaultValue": "ABSOLUTE_SCALE_MAX"
2473
+ "defaultValue": "1000"
2294
2474
  },
2295
2475
  "scaleMin": {
2296
2476
  "type": "number",
@@ -2310,7 +2490,7 @@ export class KritzelEngine {
2310
2490
  "setter": false,
2311
2491
  "reflect": false,
2312
2492
  "attribute": "scale-min",
2313
- "defaultValue": "ABSOLUTE_SCALE_MIN"
2493
+ "defaultValue": "0.0001"
2314
2494
  },
2315
2495
  "cursorTarget": {
2316
2496
  "type": "unknown",
@@ -2354,6 +2534,26 @@ export class KritzelEngine {
2354
2534
  "attribute": "lock-drawing-scale",
2355
2535
  "defaultValue": "true"
2356
2536
  },
2537
+ "isObjectDistanceFadingActive": {
2538
+ "type": "boolean",
2539
+ "mutable": false,
2540
+ "complexType": {
2541
+ "original": "boolean",
2542
+ "resolved": "boolean",
2543
+ "references": {}
2544
+ },
2545
+ "required": false,
2546
+ "optional": false,
2547
+ "docs": {
2548
+ "tags": [],
2549
+ "text": "When true, objects fade based on distance to the viewport center."
2550
+ },
2551
+ "getter": false,
2552
+ "setter": false,
2553
+ "reflect": false,
2554
+ "attribute": "is-object-distance-fading-active",
2555
+ "defaultValue": "false"
2556
+ },
2357
2557
  "theme": {
2358
2558
  "type": "string",
2359
2559
  "mutable": false,
@@ -3573,6 +3773,61 @@ export class KritzelEngine {
3573
3773
  }]
3574
3774
  }
3575
3775
  },
3776
+ "addObjects": {
3777
+ "complexType": {
3778
+ "signature": "<T extends KritzelBaseObject>(objects: T[]) => Promise<T[]>",
3779
+ "parameters": [{
3780
+ "name": "objects",
3781
+ "type": "T[]",
3782
+ "docs": "- The object instances to add."
3783
+ }],
3784
+ "references": {
3785
+ "Promise": {
3786
+ "location": "global",
3787
+ "id": "global::Promise"
3788
+ },
3789
+ "T": {
3790
+ "location": "global",
3791
+ "id": "global::T"
3792
+ },
3793
+ "KritzelBaseObject": {
3794
+ "location": "import",
3795
+ "path": "../../../classes/objects/base-object.class",
3796
+ "id": "src/classes/objects/base-object.class.ts::KritzelBaseObject",
3797
+ "referenceLocation": "KritzelBaseObject"
3798
+ },
3799
+ "KritzelText": {
3800
+ "location": "import",
3801
+ "path": "../../../classes/objects/text.class",
3802
+ "id": "src/classes/objects/text.class.ts::KritzelText",
3803
+ "referenceLocation": "KritzelText"
3804
+ },
3805
+ "KritzelGroup": {
3806
+ "location": "import",
3807
+ "path": "../../../classes/objects/group.class",
3808
+ "id": "src/classes/objects/group.class.ts::KritzelGroup",
3809
+ "referenceLocation": "KritzelGroup"
3810
+ },
3811
+ "KritzelLine": {
3812
+ "location": "import",
3813
+ "path": "../../../classes/objects/line.class",
3814
+ "id": "src/classes/objects/line.class.ts::KritzelLine",
3815
+ "referenceLocation": "KritzelLine"
3816
+ }
3817
+ },
3818
+ "return": "Promise<T[]>"
3819
+ },
3820
+ "docs": {
3821
+ "text": "Adds multiple objects to the canvas in a single batch operation.\nAll objects are inserted within one Yjs transaction (single undo step),\ntriggering only one rerender cycle. Intended for programmatic streaming\nscenarios where per-object overhead would cause stutter.",
3822
+ "tags": [{
3823
+ "name": "param",
3824
+ "text": "objects - The object instances to add."
3825
+ }, {
3826
+ "name": "returns",
3827
+ "text": "The added objects."
3828
+ }]
3829
+ }
3830
+ },
3576
3831
  "updateObject": {
3577
3832
  "complexType": {
3578
3833
  "signature": "<T extends KritzelBaseObject>(object: T, updatedProperties: Partial<T>) => Promise<T | null>",
@@ -3658,6 +3913,43 @@ export class KritzelEngine {
3658
3913
  }]
3659
3914
  }
3660
3915
  },
3916
+ "removeObjects": {
3917
+ "complexType": {
3918
+ "signature": "<T extends KritzelBaseObject>(objects: T[]) => Promise<T[]>",
3919
+ "parameters": [{
3920
+ "name": "objects",
3921
+ "type": "T[]",
3922
+ "docs": "- The objects to remove."
3923
+ }],
3924
+ "references": {
3925
+ "Promise": {
3926
+ "location": "global",
3927
+ "id": "global::Promise"
3928
+ },
3929
+ "T": {
3930
+ "location": "global",
3931
+ "id": "global::T"
3932
+ },
3933
+ "KritzelBaseObject": {
3934
+ "location": "import",
3935
+ "path": "../../../classes/objects/base-object.class",
3936
+ "id": "src/classes/objects/base-object.class.ts::KritzelBaseObject",
3937
+ "referenceLocation": "KritzelBaseObject"
3938
+ }
3939
+ },
3940
+ "return": "Promise<T[]>"
3941
+ },
3942
+ "docs": {
3943
+ "text": "Removes multiple objects from the canvas in a single batch operation.\nAll removals happen within one Yjs transaction (single undo step),\ntriggering only one rerender cycle. Intended for programmatic streaming\nscenarios where per-object overhead would cause stutter.",
3944
+ "tags": [{
3945
+ "name": "param",
3946
+ "text": "objects - The objects to remove."
3947
+ }, {
3948
+ "name": "returns",
3949
+ "text": "The removed objects."
3950
+ }]
3951
+ }
3952
+ },
3661
3953
  "getSelectedObjects": {
3662
3954
  "complexType": {
3663
3955
  "signature": "() => Promise<KritzelBaseObject<any>[]>",
@@ -3813,6 +4105,36 @@ export class KritzelEngine {
3813
4105
  }]
3814
4106
  }
3815
4107
  },
4108
+ "panToObject": {
4109
+ "complexType": {
4110
+ "signature": "(object: KritzelBaseObject) => Promise<void>",
4111
+ "parameters": [{
4112
+ "name": "object",
4113
+ "type": "KritzelBaseObject<HTMLElement | SVGElement>",
4114
+ "docs": "- The object whose center the viewport should pan to."
4115
+ }],
4116
+ "references": {
4117
+ "Promise": {
4118
+ "location": "global",
4119
+ "id": "global::Promise"
4120
+ },
4121
+ "KritzelBaseObject": {
4122
+ "location": "import",
4123
+ "path": "../../../classes/objects/base-object.class",
4124
+ "id": "src/classes/objects/base-object.class.ts::KritzelBaseObject",
4125
+ "referenceLocation": "KritzelBaseObject"
4126
+ }
4127
+ },
4128
+ "return": "Promise<void>"
4129
+ },
4130
+ "docs": {
4131
+ "text": "Pans the viewport to center on the given object without changing the zoom level.\nUnlike `centerObjectInViewport`, this moves the camera \u2014 not the object.",
4132
+ "tags": [{
4133
+ "name": "param",
4134
+ "text": "object - The object whose center the viewport should pan to."
4135
+ }]
4136
+ }
4137
+ },
3816
4138
  "backToContent": {
3817
4139
  "complexType": {
3818
4140
  "signature": "() => Promise<boolean>",
@@ -3860,6 +4182,46 @@ export class KritzelEngine {
3860
4182
  }]
3861
4183
  }
3862
4184
  },
4185
+ "centerObjects": {
4186
+ "complexType": {
4187
+ "signature": "(objects: KritzelBaseObject[], animate?: boolean) => Promise<boolean>",
4188
+ "parameters": [{
4189
+ "name": "objects",
4190
+ "type": "KritzelBaseObject<HTMLElement | SVGElement>[]",
4191
+ "docs": "- The objects to center and fit in the viewport."
4192
+ }, {
4193
+ "name": "animate",
4194
+ "type": "boolean",
4195
+ "docs": "- Whether to animate the viewport transition (default: true)."
4196
+ }],
4197
+ "references": {
4198
+ "Promise": {
4199
+ "location": "global",
4200
+ "id": "global::Promise"
4201
+ },
4202
+ "KritzelBaseObject": {
4203
+ "location": "import",
4204
+ "path": "../../../classes/objects/base-object.class",
4205
+ "id": "src/classes/objects/base-object.class.ts::KritzelBaseObject",
4206
+ "referenceLocation": "KritzelBaseObject"
4207
+ }
4208
+ },
4209
+ "return": "Promise<boolean>"
4210
+ },
4211
+ "docs": {
4212
+ "text": "Pans and zooms the viewport to fit the provided objects.\nCalculates the combined bounding box of the given objects and centers the viewport to show them.",
4213
+ "tags": [{
4214
+ "name": "param",
4215
+ "text": "objects - The objects to center and fit in the viewport."
4216
+ }, {
4217
+ "name": "param",
4218
+ "text": "animate - Whether to animate the viewport transition (default: true)."
4219
+ }, {
4220
+ "name": "returns",
4221
+ "text": "`true` if objects were provided and the viewport was adjusted, `false` otherwise."
4222
+ }]
4223
+ }
4224
+ },
3863
4225
  "setViewport": {
3864
4226
  "complexType": {
3865
4227
  "signature": "(x: number, y: number, scale: number) => Promise<void>",
@@ -4712,6 +5074,12 @@ export class KritzelEngine {
4712
5074
  }, {
4713
5075
  "propName": "user",
4714
5076
  "methodName": "onUserChange"
5077
+ }, {
5078
+ "propName": "globalContextMenuItems",
5079
+ "methodName": "onGlobalContextMenuItemsChange"
5080
+ }, {
5081
+ "propName": "objectContextMenuItems",
5082
+ "methodName": "onObjectContextMenuItemsChange"
4715
5083
  }, {
4716
5084
  "propName": "scaleMax",
4717
5085
  "methodName": "validateScaleMax"
@@ -4724,6 +5092,9 @@ export class KritzelEngine {
4724
5092
  }, {
4725
5093
  "propName": "lockDrawingScale",
4726
5094
  "methodName": "onLockDrawingScaleChange"
5095
+ }, {
5096
+ "propName": "isObjectDistanceFadingActive",
5097
+ "methodName": "onIsObjectDistanceFadingActiveChange"
4727
5098
  }, {
4728
5099
  "propName": "theme",
4729
5100
  "methodName": "onThemeChange"