@lvl99dotcom/paintcanvas 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +131 -2
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +5 -0
  5. package/dist/lib/brushes/BrushTipCache/index.d.ts +32 -0
  6. package/dist/lib/brushes/BrushTipCache/index.js +60 -0
  7. package/dist/lib/brushes/StrokeEngine/index.d.ts +171 -0
  8. package/dist/lib/brushes/StrokeEngine/index.js +324 -0
  9. package/dist/lib/brushes/StrokePath/index.d.ts +53 -0
  10. package/dist/lib/brushes/StrokePath/index.js +161 -0
  11. package/dist/lib/brushes/StrokeSampler/index.d.ts +55 -0
  12. package/dist/lib/brushes/StrokeSampler/index.js +75 -0
  13. package/dist/lib/brushes/authors/index.d.ts +55 -0
  14. package/dist/lib/brushes/authors/index.js +60 -0
  15. package/dist/lib/brushes/configRanges/index.d.ts +52 -0
  16. package/dist/lib/brushes/configRanges/index.js +206 -0
  17. package/dist/lib/brushes/index.d.ts +5 -0
  18. package/dist/lib/brushes/index.js +19 -0
  19. package/dist/lib/brushes/params/index.d.ts +108 -0
  20. package/dist/lib/brushes/params/index.js +139 -0
  21. package/dist/lib/brushes/presetFile/index.d.ts +32 -0
  22. package/dist/lib/brushes/presetFile/index.js +55 -0
  23. package/dist/lib/brushes/presets/drawing/brush-pen.js +3 -0
  24. package/dist/lib/brushes/presets/drawing/felt-pen.js +3 -0
  25. package/dist/lib/brushes/presets/drawing/index.d.ts +13 -0
  26. package/dist/lib/brushes/presets/drawing/index.js +88 -0
  27. package/dist/lib/brushes/presets/drawing/pencil-2b.js +3 -0
  28. package/dist/lib/brushes/presets/drawing/pencil-hb.js +3 -0
  29. package/dist/lib/brushes/presets/painting/grass.js +3 -0
  30. package/dist/lib/brushes/presets/painting/hair.js +3 -0
  31. package/dist/lib/brushes/presets/painting/index.d.ts +18 -0
  32. package/dist/lib/brushes/presets/painting/index.js +118 -0
  33. package/dist/lib/brushes/presets/painting/splatter.js +3 -0
  34. package/dist/lib/brushes/presets/painting/textured-paint.js +3 -0
  35. package/dist/lib/brushes/presets/painting/watery-paint.js +3 -0
  36. package/dist/lib/brushes/presets/round/index.d.ts +9 -0
  37. package/dist/lib/brushes/presets/round/index.js +44 -0
  38. package/dist/lib/brushes/presets/round/round.js +3 -0
  39. package/dist/lib/brushes/presets/round/soft-round.js +3 -0
  40. package/dist/lib/brushes/presets/sized/index.d.ts +20 -0
  41. package/dist/lib/brushes/presets/sized/index.js +30 -0
  42. package/dist/lib/brushes/presets/sketching/index.d.ts +14 -0
  43. package/dist/lib/brushes/presets/sketching/index.js +107 -0
  44. package/dist/lib/brushes/presets/square/index.d.ts +7 -0
  45. package/dist/lib/brushes/presets/square/index.js +22 -0
  46. package/dist/lib/brushes/presets/square/square.js +3 -0
  47. package/dist/lib/brushes/shapeImage/index.d.ts +40 -0
  48. package/dist/lib/brushes/shapeImage/index.js +61 -0
  49. package/dist/lib/brushes/types/index.d.ts +243 -0
  50. package/dist/lib/brushes/types/index.js +20 -0
  51. package/dist/lib/classes/BackgroundWork/index.d.ts +55 -0
  52. package/dist/lib/classes/BackgroundWork/index.js +97 -0
  53. package/dist/lib/classes/BrushSettings/index.d.ts +91 -0
  54. package/dist/lib/classes/BrushSettings/index.js +152 -0
  55. package/dist/lib/classes/CustomPresets/index.d.ts +53 -0
  56. package/dist/lib/classes/CustomPresets/index.js +71 -0
  57. package/dist/lib/classes/ExternalSheets/index.d.ts +64 -0
  58. package/dist/lib/classes/ExternalSheets/index.js +112 -0
  59. package/dist/lib/classes/GestureTracker/index.d.ts +62 -0
  60. package/dist/lib/classes/GestureTracker/index.js +122 -0
  61. package/dist/lib/classes/History/index.d.ts +83 -0
  62. package/dist/lib/classes/History/index.js +126 -0
  63. package/dist/lib/classes/HistoryGuard/index.d.ts +58 -0
  64. package/dist/lib/classes/HistoryGuard/index.js +97 -0
  65. package/dist/lib/classes/InputSettings/index.d.ts +74 -0
  66. package/dist/lib/classes/InputSettings/index.js +101 -0
  67. package/dist/lib/classes/KeyboardShortcuts/index.d.ts +48 -0
  68. package/dist/lib/classes/KeyboardShortcuts/index.js +137 -0
  69. package/dist/lib/classes/Layer/index.d.ts +86 -0
  70. package/dist/lib/classes/Layer/index.js +111 -0
  71. package/dist/lib/classes/LayerAutosave/index.d.ts +180 -0
  72. package/dist/lib/classes/LayerAutosave/index.js +346 -0
  73. package/dist/lib/classes/LayerStack/index.d.ts +177 -0
  74. package/dist/lib/classes/LayerStack/index.js +394 -0
  75. package/dist/lib/classes/PaintCanvas/index.d.ts +537 -0
  76. package/dist/lib/classes/PaintCanvas/index.js +965 -0
  77. package/dist/lib/classes/StrokeLog/index.d.ts +149 -0
  78. package/dist/lib/classes/StrokeLog/index.js +257 -0
  79. package/dist/lib/classes/Viewport/index.d.ts +108 -0
  80. package/dist/lib/classes/Viewport/index.js +194 -0
  81. package/dist/lib/document/index.d.ts +17 -0
  82. package/dist/lib/document/index.js +25 -0
  83. package/dist/lib/document/schema.d.ts +132 -0
  84. package/dist/lib/document/schema.js +110 -0
  85. package/dist/lib/i18n/index.d.ts +94 -0
  86. package/dist/lib/i18n/index.js +182 -0
  87. package/dist/lib/image/index.d.ts +90 -0
  88. package/dist/lib/image/index.js +147 -0
  89. package/dist/lib/messages/PatchSender/index.d.ts +75 -0
  90. package/dist/lib/messages/PatchSender/index.js +125 -0
  91. package/dist/lib/messages/index.d.ts +26 -0
  92. package/dist/lib/messages/index.js +59 -0
  93. package/dist/lib/messages/schema.d.ts +1775 -0
  94. package/dist/lib/messages/schema.js +192 -0
  95. package/dist/lib/presets/index.d.ts +32 -0
  96. package/dist/lib/presets/index.js +35 -0
  97. package/dist/lib/presets/schema.d.ts +753 -0
  98. package/dist/lib/presets/schema.js +181 -0
  99. package/dist/lib/rendering/BrushTip/index.d.ts +63 -0
  100. package/dist/lib/rendering/BrushTip/index.js +112 -0
  101. package/dist/lib/rendering/checkerboard/index.d.ts +22 -0
  102. package/dist/lib/rendering/checkerboard/index.js +31 -0
  103. package/dist/lib/rendering/compositing/index.d.ts +64 -0
  104. package/dist/lib/rendering/compositing/index.js +124 -0
  105. package/dist/lib/rendering/cursor/index.d.ts +14 -0
  106. package/dist/lib/rendering/cursor/index.js +39 -0
  107. package/dist/lib/rendering/cursors/index.d.ts +18 -0
  108. package/dist/lib/rendering/cursors/index.js +23 -0
  109. package/dist/lib/rendering/maskOutline/index.d.ts +22 -0
  110. package/dist/lib/rendering/maskOutline/index.js +78 -0
  111. package/dist/lib/rendering/outline/index.d.ts +36 -0
  112. package/dist/lib/rendering/outline/index.js +120 -0
  113. package/dist/lib/rendering/sample/index.d.ts +55 -0
  114. package/dist/lib/rendering/sample/index.js +83 -0
  115. package/dist/lib/rendering/screenshot/index.d.ts +67 -0
  116. package/dist/lib/rendering/screenshot/index.js +96 -0
  117. package/dist/lib/rendering/transformBox/index.d.ts +10 -0
  118. package/dist/lib/rendering/transformBox/index.js +57 -0
  119. package/dist/lib/selection/Lasso/index.d.ts +70 -0
  120. package/dist/lib/selection/Lasso/index.js +156 -0
  121. package/dist/lib/selection/Selection/index.d.ts +86 -0
  122. package/dist/lib/selection/Selection/index.js +228 -0
  123. package/dist/lib/selection/geometry/index.d.ts +37 -0
  124. package/dist/lib/selection/geometry/index.js +57 -0
  125. package/dist/lib/storage/index.d.ts +63 -0
  126. package/dist/lib/storage/index.js +114 -0
  127. package/dist/lib/transform/Transformer/index.d.ts +124 -0
  128. package/dist/lib/transform/Transformer/index.js +286 -0
  129. package/dist/lib/transform/geometry/index.d.ts +95 -0
  130. package/dist/lib/transform/geometry/index.js +258 -0
  131. package/dist/lib/utils/array/index.d.ts +10 -0
  132. package/dist/lib/utils/array/index.js +21 -0
  133. package/dist/lib/utils/gestures/index.d.ts +35 -0
  134. package/dist/lib/utils/gestures/index.js +81 -0
  135. package/dist/lib/utils/navigation/index.d.ts +51 -0
  136. package/dist/lib/utils/navigation/index.js +59 -0
  137. package/dist/lib/utils/random/index.d.ts +18 -0
  138. package/dist/lib/utils/random/index.js +27 -0
  139. package/dist/lib/utils/shortcuts/index.d.ts +74 -0
  140. package/dist/lib/utils/shortcuts/index.js +189 -0
  141. package/dist/lib/validation/validators.generated.d.ts +27 -0
  142. package/dist/lib/validation/validators.generated.js +19826 -0
  143. package/dist/locales/en-GB.js +188 -0
  144. package/dist/locales/en-US.js +188 -0
  145. package/dist/locales/fr.js +188 -0
  146. package/dist/locales/ja.js +188 -0
  147. package/dist/locales/ko.js +188 -0
  148. package/dist/locales/zh-Hans.js +188 -0
  149. package/dist/locales/zh-Hant.js +188 -0
  150. package/dist/package.js +3 -0
  151. package/dist/testing/app.d.ts +7 -0
  152. package/dist/testing/app.js +16 -0
  153. package/dist/testing/elements.d.ts +42 -0
  154. package/dist/testing/elements.js +58 -0
  155. package/dist/testing/fakeCanvas.d.ts +21 -0
  156. package/dist/testing/fakeCanvas.js +26 -0
  157. package/dist/testing/layerStore.d.ts +26 -0
  158. package/dist/testing/layerStore.js +43 -0
  159. package/dist/testing/locks.d.ts +15 -0
  160. package/dist/testing/locks.js +41 -0
  161. package/dist/testing/recordingCanvas.d.ts +14 -0
  162. package/dist/testing/recordingCanvas.js +28 -0
  163. package/dist/testing/recordingContext.d.ts +10 -0
  164. package/dist/testing/recordingContext.js +19 -0
  165. package/dist/ui/ChangeController/index.d.ts +40 -0
  166. package/dist/ui/ChangeController/index.js +62 -0
  167. package/dist/ui/base/index.d.ts +69 -0
  168. package/dist/ui/base/index.js +94 -0
  169. package/dist/ui/elements/PaintCanvas/index.d.ts +249 -0
  170. package/dist/ui/elements/PaintCanvas/index.js +584 -0
  171. package/dist/ui/elements/PaintCanvas/style.js +3 -0
  172. package/dist/ui/elements/PcBrushConfig/index.d.ts +130 -0
  173. package/dist/ui/elements/PcBrushConfig/index.js +463 -0
  174. package/dist/ui/elements/PcBrushConfig/style.js +3 -0
  175. package/dist/ui/elements/PcBrushMenu/index.d.ts +121 -0
  176. package/dist/ui/elements/PcBrushMenu/index.js +362 -0
  177. package/dist/ui/elements/PcBrushMenu/style.js +3 -0
  178. package/dist/ui/elements/PcBrushTest/index.d.ts +71 -0
  179. package/dist/ui/elements/PcBrushTest/index.js +136 -0
  180. package/dist/ui/elements/PcBrushTest/style.js +3 -0
  181. package/dist/ui/elements/PcButton/index.d.ts +57 -0
  182. package/dist/ui/elements/PcButton/index.js +124 -0
  183. package/dist/ui/elements/PcButtonGroup/index.d.ts +44 -0
  184. package/dist/ui/elements/PcButtonGroup/index.js +93 -0
  185. package/dist/ui/elements/PcCanvas/index.d.ts +356 -0
  186. package/dist/ui/elements/PcCanvas/index.js +1004 -0
  187. package/dist/ui/elements/PcCanvas/style.js +3 -0
  188. package/dist/ui/elements/PcCanvasMap/index.d.ts +96 -0
  189. package/dist/ui/elements/PcCanvasMap/index.js +187 -0
  190. package/dist/ui/elements/PcCanvasMap/style.js +3 -0
  191. package/dist/ui/elements/PcContextMenu/index.d.ts +72 -0
  192. package/dist/ui/elements/PcContextMenu/index.js +148 -0
  193. package/dist/ui/elements/PcDialog/index.d.ts +63 -0
  194. package/dist/ui/elements/PcDialog/index.js +114 -0
  195. package/dist/ui/elements/PcIcon/index.d.ts +36 -0
  196. package/dist/ui/elements/PcIcon/index.js +43 -0
  197. package/dist/ui/elements/PcIconToggle/index.d.ts +46 -0
  198. package/dist/ui/elements/PcIconToggle/index.js +87 -0
  199. package/dist/ui/elements/PcInfoTip/index.d.ts +40 -0
  200. package/dist/ui/elements/PcInfoTip/index.js +95 -0
  201. package/dist/ui/elements/PcInputSettings/index.d.ts +69 -0
  202. package/dist/ui/elements/PcInputSettings/index.js +150 -0
  203. package/dist/ui/elements/PcLayerItem/index.d.ts +221 -0
  204. package/dist/ui/elements/PcLayerItem/index.js +561 -0
  205. package/dist/ui/elements/PcLayerItem/style.js +3 -0
  206. package/dist/ui/elements/PcLayersMenu/index.d.ts +108 -0
  207. package/dist/ui/elements/PcLayersMenu/index.js +208 -0
  208. package/dist/ui/elements/PcLayersMenu/style.js +3 -0
  209. package/dist/ui/elements/PcMatch/index.d.ts +31 -0
  210. package/dist/ui/elements/PcMatch/index.js +58 -0
  211. package/dist/ui/elements/PcPanel/index.d.ts +43 -0
  212. package/dist/ui/elements/PcPanel/index.js +51 -0
  213. package/dist/ui/elements/PcPopover/index.d.ts +48 -0
  214. package/dist/ui/elements/PcPopover/index.js +86 -0
  215. package/dist/ui/elements/PcSlider/index.d.ts +57 -0
  216. package/dist/ui/elements/PcSlider/index.js +88 -0
  217. package/dist/ui/elements/PcStats/index.d.ts +54 -0
  218. package/dist/ui/elements/PcStats/index.js +141 -0
  219. package/dist/ui/elements/PcThemePicker/index.d.ts +56 -0
  220. package/dist/ui/elements/PcThemePicker/index.js +134 -0
  221. package/dist/ui/elements/PcToast/index.d.ts +58 -0
  222. package/dist/ui/elements/PcToast/index.js +110 -0
  223. package/dist/ui/elements/PcToggleCheckbox/index.d.ts +37 -0
  224. package/dist/ui/elements/PcToggleCheckbox/index.js +105 -0
  225. package/dist/ui/elements/PcToolSettings/index.d.ts +128 -0
  226. package/dist/ui/elements/PcToolSettings/index.js +543 -0
  227. package/dist/ui/elements/PcToolSettings/style.js +3 -0
  228. package/dist/ui/elements/PcToolbar/index.d.ts +71 -0
  229. package/dist/ui/elements/PcToolbar/index.js +190 -0
  230. package/dist/ui/elements/PcToolbar/style.js +3 -0
  231. package/dist/ui/icons/images/brush.js +3 -0
  232. package/dist/ui/icons/images/circle-mask.js +3 -0
  233. package/dist/ui/icons/images/clipboard.js +3 -0
  234. package/dist/ui/icons/images/cursor.js +3 -0
  235. package/dist/ui/icons/images/eraser.js +3 -0
  236. package/dist/ui/icons/images/eyedropper.js +3 -0
  237. package/dist/ui/icons/images/flip-horizontal.js +3 -0
  238. package/dist/ui/icons/images/flip-vertical.js +3 -0
  239. package/dist/ui/icons/images/focus-pen.js +3 -0
  240. package/dist/ui/icons/images/freehand-mask.js +3 -0
  241. package/dist/ui/icons/images/hidden.js +3 -0
  242. package/dist/ui/icons/images/layers.js +3 -0
  243. package/dist/ui/icons/images/linked.js +3 -0
  244. package/dist/ui/icons/images/locked.js +3 -0
  245. package/dist/ui/icons/images/moon.js +3 -0
  246. package/dist/ui/icons/images/pan.js +3 -0
  247. package/dist/ui/icons/images/polygon-mask.js +3 -0
  248. package/dist/ui/icons/images/pressure.js +3 -0
  249. package/dist/ui/icons/images/randomise.js +3 -0
  250. package/dist/ui/icons/images/rectangle-mask.js +3 -0
  251. package/dist/ui/icons/images/redo.js +3 -0
  252. package/dist/ui/icons/images/rotate-90-left.js +3 -0
  253. package/dist/ui/icons/images/rotate-90-right.js +3 -0
  254. package/dist/ui/icons/images/smoothing-bezier-cubic.js +3 -0
  255. package/dist/ui/icons/images/smoothing-bezier-quad.js +3 -0
  256. package/dist/ui/icons/images/smoothing-linear.js +3 -0
  257. package/dist/ui/icons/images/star.js +3 -0
  258. package/dist/ui/icons/images/sun.js +3 -0
  259. package/dist/ui/icons/images/tilt.js +3 -0
  260. package/dist/ui/icons/images/undo.js +3 -0
  261. package/dist/ui/icons/images/unlinked.js +3 -0
  262. package/dist/ui/icons/images/unlocked.js +3 -0
  263. package/dist/ui/icons/images/visible.js +3 -0
  264. package/dist/ui/icons/images/zoom-in.js +3 -0
  265. package/dist/ui/icons/images/zoom-out.js +3 -0
  266. package/dist/ui/icons/images/zoom.js +3 -0
  267. package/dist/ui/icons/index.d.ts +42 -0
  268. package/dist/ui/icons/index.js +130 -0
  269. package/dist/ui/index.d.ts +21 -0
  270. package/dist/ui/index.js +22 -0
  271. package/dist/ui/layout/index.d.ts +88 -0
  272. package/dist/ui/layout/index.js +96 -0
  273. package/dist/ui/styles/index.d.ts +13 -0
  274. package/dist/ui/styles/index.js +195 -0
  275. package/dist/ui/tokens/index.d.ts +29 -0
  276. package/dist/ui/tokens/index.js +114 -0
  277. package/locales/en-GB.json +186 -0
  278. package/locales/en-US.json +186 -0
  279. package/locales/fr.json +186 -0
  280. package/locales/ja.json +186 -0
  281. package/locales/ko.json +186 -0
  282. package/locales/zh-Hans.json +186 -0
  283. package/locales/zh-Hant.json +186 -0
  284. package/package.json +97 -3
@@ -0,0 +1,324 @@
1
+ import { randomSeed, seededRandom } from "../../utils/random/index.js";
2
+ import { createOffscreenCanvas } from "../../classes/Layer/index.js";
3
+ import StrokeSampler from "../StrokeSampler/index.js";
4
+ import StrokePath from "../StrokePath/index.js";
5
+ import { pointInput, snapStamp, stampParams } from "../params/index.js";
6
+ // src/lib/brushes/StrokeEngine/index.ts
7
+ /** Extra pixels added around each stamp's bounds so anti-aliased edges are included */
8
+ var STAMP_MARGIN = 2;
9
+ /**
10
+ * Grow a rectangle to include another (the first may be empty).
11
+ *
12
+ * @example
13
+ * unionRect({ x: 0, y: 0, width: 10, height: 10 }, { x: 20, y: 5, width: 5, height: 5 });
14
+ * // { x: 0, y: 0, width: 25, height: 10 }
15
+ */
16
+ var unionRect = (a, b) => {
17
+ if (!a) return b;
18
+ const x = Math.min(a.x, b.x);
19
+ const y = Math.min(a.y, b.y);
20
+ return {
21
+ x,
22
+ y,
23
+ width: Math.max(a.x + a.width, b.x + b.width) - x,
24
+ height: Math.max(a.y + a.height, b.y + b.height) - y
25
+ };
26
+ };
27
+ /**
28
+ * Snap a rectangle outwards to whole pixels and clip it to the canvas. Returns undefined if nothing is left.
29
+ */
30
+ var clipRect = (rect, width, height) => {
31
+ const x = Math.max(0, Math.floor(rect.x));
32
+ const y = Math.max(0, Math.floor(rect.y));
33
+ const right = Math.min(width, Math.ceil(rect.x + rect.width));
34
+ const bottom = Math.min(height, Math.ceil(rect.y + rect.height));
35
+ return right > x && bottom > y ? {
36
+ x,
37
+ y,
38
+ width: right - x,
39
+ height: bottom - y
40
+ } : void 0;
41
+ };
42
+ /** How the stroke buffer is merged into the layer, or null if the stroke cannot change it */
43
+ var compositeOperation = (mode, alphaLock) => {
44
+ if (mode === "erase") return alphaLock ? null : "destination-out";
45
+ return alphaLock ? "source-atop" : "source-over";
46
+ };
47
+ /** Event dispatched just before a finished stroke is written into its layer */
48
+ var BEFORE_COMMIT_EVENT = "beforecommit";
49
+ /** Event dispatched when a stroke starts */
50
+ var STROKE_BEGIN_EVENT = "strokebegin";
51
+ /** Event dispatched when a stroke ends: written into its layer, or cancelled */
52
+ var STROKE_END_EVENT = "strokeend";
53
+ /**
54
+ * Draws brush and eraser strokes.
55
+ *
56
+ * Stamps are drawn at full strength into a stroke buffer, so overlapping stamps within one stroke do not build up opacity.
57
+ * The buffer is merged into the layer with the stroke's opacity (the preset's `alpha`):
58
+ * - Brush: painted over the layer (or only onto existing pixels when the layer's alpha lock is on).
59
+ * - Eraser: removes the buffer's shape from the layer (does nothing when alpha lock is on).
60
+ * - With a mask, the buffer is first cut to the mask, so the stroke only applies inside it.
61
+ *
62
+ * While drawing, `preview` provides the layer with the stroke merged in, to draw instead of the layer. The stroke is written into the layer when it ends.
63
+ *
64
+ * Dispatches a `change` event whenever the preview changes, and when a stroke is committed or cancelled. Dispatches a
65
+ * `beforecommit` event (with `StrokeCommitDetail`) just before a stroke that changes its layer is written into it, so
66
+ * the area can be recorded for undo. Dispatches `strokebegin` when a stroke starts and `strokeend` when it's committed or
67
+ * cancelled.
68
+ *
69
+ * @example
70
+ * engine.begin(options, { x: 10, y: 10, pressure: 0.5 }, event.timeStamp);
71
+ * engine.move({ x: 20, y: 12 }, event.timeStamp);
72
+ * engine.end({ x: 25, y: 15 }, event.timeStamp);
73
+ */
74
+ var StrokeEngine = class extends EventTarget {
75
+ /** Canvas width in pixels */
76
+ width;
77
+ /** Canvas height in pixels */
78
+ height;
79
+ createCanvas;
80
+ bufferCanvas;
81
+ workingCanvas;
82
+ maskedCanvas;
83
+ active;
84
+ /** Area of the preview changed since `takeChangedArea` was last called */
85
+ changedArea;
86
+ /** Whether strokes record their points and stamps for the debug overlay */
87
+ debugEnabled = false;
88
+ /** Points recorded and stamps placed by the current or last stroke (only while `debugEnabled`) */
89
+ debugTrace = {
90
+ points: [],
91
+ stamps: []
92
+ };
93
+ constructor(width, height, createCanvas = createOffscreenCanvas) {
94
+ super();
95
+ this.width = width;
96
+ this.height = height;
97
+ this.createCanvas = createCanvas;
98
+ }
99
+ /**
100
+ * The area of the canvas whose preview changed since this was last called (stamps placed, or a stroke cancelled or
101
+ * written into its layer), to redraw only that area; undefined if nothing changed.
102
+ */
103
+ takeChangedArea() {
104
+ const area = this.changedArea;
105
+ this.changedArea = void 0;
106
+ return area;
107
+ }
108
+ /** Whether a stroke is in progress */
109
+ get drawing() {
110
+ return this.active !== void 0;
111
+ }
112
+ /** The layer with the stroke in progress merged in, to draw in its place; undefined when not drawing */
113
+ get preview() {
114
+ return this.active && this.workingCanvas ? {
115
+ layer: this.active.options.layer,
116
+ image: this.workingCanvas
117
+ } : void 0;
118
+ }
119
+ /** The stroke buffer (created on first use) */
120
+ get buffer() {
121
+ this.bufferCanvas ??= this.createCanvas(this.width, this.height);
122
+ return this.bufferCanvas;
123
+ }
124
+ /** The preview canvas (created on first use) */
125
+ get working() {
126
+ this.workingCanvas ??= this.createCanvas(this.width, this.height);
127
+ return this.workingCanvas;
128
+ }
129
+ /**
130
+ * Turn recording of stroke points and stamps (for the debug overlay) on or off.
131
+ */
132
+ setDebug(enabled) {
133
+ this.debugEnabled = enabled;
134
+ this.debugTrace.points = [];
135
+ this.debugTrace.stamps = [];
136
+ this.dispatchEvent(new Event("change"));
137
+ }
138
+ /**
139
+ * Record a sampled point for the debug overlay.
140
+ */
141
+ trace(point) {
142
+ if (point && this.debugEnabled) this.debugTrace.points.push(point);
143
+ return point;
144
+ }
145
+ /**
146
+ * Start a stroke at the pointer-down point. Cancels any stroke already in progress.
147
+ */
148
+ begin(options, point, time) {
149
+ this.cancel();
150
+ const seed = options.seed ?? randomSeed();
151
+ this.active = {
152
+ options,
153
+ seed,
154
+ random: options.random ?? seededRandom(seed),
155
+ points: [{
156
+ ...point,
157
+ time
158
+ }],
159
+ sampler: new StrokeSampler(options.preset.sampleRate),
160
+ path: new StrokePath(options.preset.smoothingType, options.preset.spacing)
161
+ };
162
+ this.dispatchEvent(new Event(STROKE_BEGIN_EVENT));
163
+ const ctx = this.working.getContext("2d");
164
+ ctx.globalCompositeOperation = "copy";
165
+ ctx.drawImage(options.layer.canvas, 0, 0);
166
+ ctx.globalCompositeOperation = "source-over";
167
+ this.debugTrace.points = [];
168
+ this.debugTrace.stamps = [];
169
+ this.place(this.active.path.add(this.trace(this.active.sampler.start(point, time))));
170
+ }
171
+ /**
172
+ * Continue the stroke as the pointer moves. Points are recorded at the preset's sample rate.
173
+ */
174
+ move(point, time) {
175
+ const active = this.active;
176
+ if (!active) return;
177
+ active.points.push({
178
+ ...point,
179
+ time
180
+ });
181
+ const recorded = this.trace(active.sampler.move(point, time));
182
+ if (recorded) this.place(active.path.add(recorded));
183
+ }
184
+ /**
185
+ * Finish the stroke at the pointer-up point and write it into the layer.
186
+ */
187
+ end(point, time) {
188
+ const active = this.active;
189
+ if (!active) return;
190
+ active.points.push({
191
+ ...point,
192
+ time
193
+ });
194
+ const recorded = this.trace(active.sampler.end(point, time));
195
+ const stamps = recorded ? active.path.add(recorded) : [];
196
+ this.place([...stamps, ...active.path.finish()]);
197
+ this.commit(active);
198
+ }
199
+ /**
200
+ * Abandon the stroke in progress without changing the layer.
201
+ */
202
+ cancel() {
203
+ const active = this.active;
204
+ if (!active) return;
205
+ this.clearBuffer(active.dirty);
206
+ if (active.dirty) this.changedArea = unionRect(this.changedArea, active.dirty);
207
+ this.active = void 0;
208
+ this.dispatchEvent(new Event(STROKE_END_EVENT));
209
+ this.dispatchEvent(new Event("change"));
210
+ }
211
+ /**
212
+ * Stamp the shape at each point into the buffer, then refresh the preview where it changed.
213
+ */
214
+ place(points) {
215
+ const active = this.active;
216
+ if (points.length === 0) return;
217
+ if (this.debugEnabled) this.debugTrace.stamps.push(...points);
218
+ const { preset, size, tip, colour, mode, isPen } = active.options;
219
+ const { random } = active;
220
+ const ctx = this.buffer.getContext("2d");
221
+ const stampPreset = {
222
+ ...preset,
223
+ alpha: 1
224
+ };
225
+ let changed;
226
+ for (const point of points) {
227
+ const varied = stampParams(stampPreset, size, pointInput(point, isPen), random);
228
+ const { x, y, params } = preset.snapToPixelGrid ? snapStamp(point.x, point.y, varied) : {
229
+ x: point.x,
230
+ y: point.y,
231
+ params: varied
232
+ };
233
+ tip.stamp(ctx, x, y, params, mode === "erase" ? "#000000" : colour);
234
+ const reach = Math.hypot(params.width, params.height) / 2 + STAMP_MARGIN;
235
+ changed = unionRect(changed, {
236
+ x: x + params.offsetX - reach,
237
+ y: y + params.offsetY - reach,
238
+ width: reach * 2,
239
+ height: reach * 2
240
+ });
241
+ }
242
+ const area = changed && clipRect(changed, this.width, this.height);
243
+ if (!area) return;
244
+ active.dirty = unionRect(active.dirty, area);
245
+ this.changedArea = unionRect(this.changedArea, area);
246
+ this.mergeInto(this.working, active, area, true);
247
+ this.dispatchEvent(new Event("change"));
248
+ }
249
+ /**
250
+ * Merge the buffer into a target canvas within an area. For the preview, the area is first reset to the layer's pixels.
251
+ */
252
+ mergeInto(target, active, area, resetFromLayer) {
253
+ const { layer, preset, mode } = active.options;
254
+ const ctx = target.getContext("2d");
255
+ const { x, y, width, height } = area;
256
+ ctx.save();
257
+ if (resetFromLayer) {
258
+ ctx.clearRect(x, y, width, height);
259
+ ctx.drawImage(layer.canvas, x, y, width, height, x, y, width, height);
260
+ }
261
+ const operation = compositeOperation(mode, layer.alphaLock);
262
+ if (operation) {
263
+ ctx.globalAlpha = Math.max(0, Math.min(1, preset.alpha ?? 1));
264
+ ctx.globalCompositeOperation = operation;
265
+ ctx.drawImage(this.strokeImage(active, area), x, y, width, height, x, y, width, height);
266
+ }
267
+ ctx.restore();
268
+ }
269
+ /**
270
+ * The stroke buffer, cut to the mask within an area when a mask is active (partially masked areas let partial paint through).
271
+ */
272
+ strokeImage(active, area) {
273
+ const mask = active.options.mask;
274
+ if (!mask) return this.buffer;
275
+ this.maskedCanvas ??= this.createCanvas(this.width, this.height);
276
+ const ctx = this.maskedCanvas.getContext("2d");
277
+ const { x, y, width, height } = area;
278
+ ctx.save();
279
+ ctx.globalCompositeOperation = "copy";
280
+ ctx.drawImage(this.buffer, x, y, width, height, x, y, width, height);
281
+ ctx.globalCompositeOperation = "destination-in";
282
+ ctx.drawImage(mask, x, y, width, height, x, y, width, height);
283
+ ctx.restore();
284
+ return this.maskedCanvas;
285
+ }
286
+ /**
287
+ * Write the finished stroke into its layer and reset for the next stroke.
288
+ */
289
+ commit(active) {
290
+ const { layer, mode, preset, size, colour, isPen } = active.options;
291
+ if (active.dirty) {
292
+ if (compositeOperation(mode, layer.alphaLock)) {
293
+ const stroke = {
294
+ mode,
295
+ preset,
296
+ size,
297
+ colour,
298
+ isPen,
299
+ seed: active.seed,
300
+ points: active.points
301
+ };
302
+ this.dispatchEvent(new CustomEvent(BEFORE_COMMIT_EVENT, { detail: {
303
+ layer,
304
+ area: active.dirty,
305
+ stroke
306
+ } }));
307
+ }
308
+ this.mergeInto(active.options.layer.canvas, active, active.dirty, false);
309
+ this.clearBuffer(active.dirty);
310
+ this.changedArea = unionRect(this.changedArea, active.dirty);
311
+ }
312
+ this.active = void 0;
313
+ this.dispatchEvent(new Event(STROKE_END_EVENT));
314
+ this.dispatchEvent(new Event("change"));
315
+ }
316
+ /**
317
+ * Clear an area of the stroke buffer.
318
+ */
319
+ clearBuffer(area) {
320
+ if (!area) return;
321
+ this.buffer.getContext("2d").clearRect(area.x, area.y, area.width, area.height);
322
+ }
323
+ };
324
+ export { BEFORE_COMMIT_EVENT, STROKE_BEGIN_EVENT, STROKE_END_EVENT, clipRect, StrokeEngine as default, unionRect };
@@ -0,0 +1,53 @@
1
+ import { SmoothingType, type BrushStrokePoint } from "../types";
2
+ /** Largest allowed spacing between stamps, in pixels */
3
+ export declare const MAX_SPACING = 200;
4
+ /** Default spacing between stamps, in pixels */
5
+ export declare const DEFAULT_SPACING = 5;
6
+ /** Length in pixels of the straight pieces curves are split into */
7
+ export declare const CURVE_STEP = 1;
8
+ /**
9
+ * Distance between stamps for a preset's spacing: 0–200 px, where 0 means a stamp at every pixel.
10
+ *
11
+ * @example
12
+ * stampStep(0); // 1
13
+ * stampStep(500); // 200
14
+ */
15
+ export declare const stampStep: (spacing: number | undefined) => number;
16
+ /**
17
+ * Builds a stroke's line from its recorded points and places stamps along it, `spacing` pixels apart. Works incrementally while drawing:
18
+ * each new point returns the stamps that can now be placed.
19
+ *
20
+ * Smoothing:
21
+ * - Linear (and None): straight lines between points.
22
+ * - BezierQuad: quadratic curves through the midpoints between points (no lag).
23
+ * - BezierCubic: cubic curves whose handles follow the direction of movement before and after each point (lags one point until the next arrives).
24
+ *
25
+ * @example
26
+ * const path = new StrokePath(SmoothingType.Linear, 5);
27
+ * path.add({ x: 0, y: 0 }); // [{ x: 0, y: 0 }]
28
+ * path.add({ x: 10, y: 0 }); // [{ x: 5, y: 0 }, { x: 10, y: 0 }]
29
+ * path.finish(); // []
30
+ */
31
+ export default class StrokePath {
32
+ /** Pixels between stamps */
33
+ readonly step: number;
34
+ private readonly smoothing;
35
+ private readonly points;
36
+ /** End of the line built so far */
37
+ private tip?;
38
+ /** Distance along the line until the next stamp */
39
+ private untilNext;
40
+ constructor(smoothing?: SmoothingType, spacing?: number);
41
+ /**
42
+ * Add a recorded point. Returns the stamps placed along the line this point completes (the first point always gets a stamp).
43
+ */
44
+ add(point: BrushStrokePoint): BrushStrokePoint[];
45
+ /**
46
+ * Finish the stroke: returns stamps for the last part of the line that was waiting for more points.
47
+ */
48
+ finish(): BrushStrokePoint[];
49
+ /**
50
+ * Extend the line through the given points and return stamps placed every `step` pixels along it.
51
+ */
52
+ private walk;
53
+ }
@@ -0,0 +1,161 @@
1
+ import { SmoothingType } from "../types/index.js";
2
+ // src/lib/brushes/StrokePath/index.ts
3
+ /** Largest allowed spacing between stamps, in pixels */
4
+ var MAX_SPACING = 200;
5
+ /** Default spacing between stamps, in pixels */
6
+ var DEFAULT_SPACING = 5;
7
+ /** Length in pixels of the straight pieces curves are split into */
8
+ var CURVE_STEP = 1;
9
+ /**
10
+ * Distance between stamps for a preset's spacing: 0–200 px, where 0 means a stamp at every pixel.
11
+ *
12
+ * @example
13
+ * stampStep(0); // 1
14
+ * stampStep(500); // 200
15
+ */
16
+ var stampStep = (spacing) => Math.max(1, Math.min(200, spacing ?? 5));
17
+ /**
18
+ * Interpolate between two stroke points: position, pressure and tilt.
19
+ */
20
+ var mix = (a, b, t) => {
21
+ const value = (from, to) => from === void 0 || to === void 0 ? from ?? to : from + (to - from) * t;
22
+ const point = {
23
+ x: a.x + (b.x - a.x) * t,
24
+ y: a.y + (b.y - a.y) * t
25
+ };
26
+ const pressure = value(a.pressure, b.pressure);
27
+ const tiltX = value(a.tiltX, b.tiltX);
28
+ const tiltY = value(a.tiltY, b.tiltY);
29
+ if (pressure !== void 0) point.pressure = pressure;
30
+ if (tiltX !== void 0) point.tiltX = tiltX;
31
+ if (tiltY !== void 0) point.tiltY = tiltY;
32
+ return point;
33
+ };
34
+ /** Distance between two points */
35
+ var distance = (a, b) => Math.hypot(b.x - a.x, b.y - a.y);
36
+ /**
37
+ * Split a curve into short straight pieces about `CURVE_STEP` pixels long.
38
+ *
39
+ * @param at - position on the curve for t from 0 to 1
40
+ * @param approxLength - rough curve length, used to choose how many pieces
41
+ */
42
+ var flatten = (at, approxLength) => {
43
+ const pieces = Math.max(1, Math.ceil(approxLength / 1));
44
+ const points = [];
45
+ for (let i = 1; i <= pieces; i++) points.push(at(i / pieces));
46
+ return points;
47
+ };
48
+ /**
49
+ * Quadratic Bézier from `a` to `b` with control point `c`. Pressure and tilt blend from `a` to `b`.
50
+ */
51
+ var quadratic = (a, c, b) => flatten((t) => {
52
+ const point = mix(a, b, t);
53
+ const u = 1 - t;
54
+ point.x = u * u * a.x + 2 * u * t * c.x + t * t * b.x;
55
+ point.y = u * u * a.y + 2 * u * t * c.y + t * t * b.y;
56
+ return point;
57
+ }, distance(a, c) + distance(c, b));
58
+ /**
59
+ * Cubic Bézier from `a` to `b` with handles `c1` and `c2`. Pressure and tilt blend from `a` to `b`.
60
+ */
61
+ var cubic = (a, c1, c2, b) => flatten((t) => {
62
+ const point = mix(a, b, t);
63
+ const u = 1 - t;
64
+ point.x = u * u * u * a.x + 3 * u * u * t * c1.x + 3 * u * t * t * c2.x + t * t * t * b.x;
65
+ point.y = u * u * u * a.y + 3 * u * u * t * c1.y + 3 * u * t * t * c2.y + t * t * t * b.y;
66
+ return point;
67
+ }, distance(a, c1) + distance(c1, c2) + distance(c2, b));
68
+ /**
69
+ * The curve between `p1` and `p2` whose handles follow the direction of movement from `p0` to `p2` and from `p1` to `p3` (Catmull–Rom).
70
+ */
71
+ var catmullRom = (p0, p1, p2, p3) => cubic(p1, {
72
+ x: p1.x + (p2.x - p0.x) / 6,
73
+ y: p1.y + (p2.y - p0.y) / 6
74
+ }, {
75
+ x: p2.x - (p3.x - p1.x) / 6,
76
+ y: p2.y - (p3.y - p1.y) / 6
77
+ }, p2);
78
+ /**
79
+ * Builds a stroke's line from its recorded points and places stamps along it, `spacing` pixels apart. Works incrementally while drawing:
80
+ * each new point returns the stamps that can now be placed.
81
+ *
82
+ * Smoothing:
83
+ * - Linear (and None): straight lines between points.
84
+ * - BezierQuad: quadratic curves through the midpoints between points (no lag).
85
+ * - BezierCubic: cubic curves whose handles follow the direction of movement before and after each point (lags one point until the next arrives).
86
+ *
87
+ * @example
88
+ * const path = new StrokePath(SmoothingType.Linear, 5);
89
+ * path.add({ x: 0, y: 0 }); // [{ x: 0, y: 0 }]
90
+ * path.add({ x: 10, y: 0 }); // [{ x: 5, y: 0 }, { x: 10, y: 0 }]
91
+ * path.finish(); // []
92
+ */
93
+ var StrokePath = class {
94
+ /** Pixels between stamps */
95
+ step;
96
+ smoothing;
97
+ points = [];
98
+ /** End of the line built so far */
99
+ tip;
100
+ /** Distance along the line until the next stamp */
101
+ untilNext = 0;
102
+ constructor(smoothing = SmoothingType.Linear, spacing) {
103
+ this.smoothing = smoothing;
104
+ this.step = stampStep(spacing);
105
+ }
106
+ /**
107
+ * Add a recorded point. Returns the stamps placed along the line this point completes (the first point always gets a stamp).
108
+ */
109
+ add(point) {
110
+ const points = this.points;
111
+ points.push(point);
112
+ const n = points.length;
113
+ if (n === 1) {
114
+ this.tip = point;
115
+ this.untilNext = this.step;
116
+ return [point];
117
+ }
118
+ const prev = points[n - 2];
119
+ switch (this.smoothing) {
120
+ case SmoothingType.BezierQuad: return n === 2 ? this.walk([mix(prev, point, .5)]) : this.walk(quadratic(this.tip, prev, mix(prev, point, .5)));
121
+ case SmoothingType.BezierCubic:
122
+ if (n === 2) return [];
123
+ return this.walk(catmullRom(points[n - 4] ?? points[n - 3], points[n - 3], prev, point));
124
+ default: return this.walk([point]);
125
+ }
126
+ }
127
+ /**
128
+ * Finish the stroke: returns stamps for the last part of the line that was waiting for more points.
129
+ */
130
+ finish() {
131
+ const points = this.points;
132
+ const n = points.length;
133
+ const last = points[n - 1];
134
+ if (!last || n < 2) return [];
135
+ switch (this.smoothing) {
136
+ case SmoothingType.BezierQuad: return this.walk([last]);
137
+ case SmoothingType.BezierCubic: return this.walk(catmullRom(points[n - 3] ?? points[n - 2], points[n - 2], last, last));
138
+ default: return [];
139
+ }
140
+ }
141
+ /**
142
+ * Extend the line through the given points and return stamps placed every `step` pixels along it.
143
+ */
144
+ walk(points) {
145
+ const stamps = [];
146
+ for (const next of points) {
147
+ const from = this.tip;
148
+ const length = distance(from, next);
149
+ let travelled = 0;
150
+ while (length - travelled >= this.untilNext) {
151
+ travelled += this.untilNext;
152
+ stamps.push(mix(from, next, travelled / length));
153
+ this.untilNext = this.step;
154
+ }
155
+ this.untilNext -= length - travelled;
156
+ this.tip = next;
157
+ }
158
+ return stamps;
159
+ }
160
+ };
161
+ export { CURVE_STEP, DEFAULT_SPACING, MAX_SPACING, StrokePath as default, stampStep };
@@ -0,0 +1,55 @@
1
+ import type { BrushStrokePoint } from "../types";
2
+ /** Shortest allowed sample rate in milliseconds */
3
+ export declare const MIN_SAMPLE_RATE = 5;
4
+ /** Longest allowed sample rate in milliseconds */
5
+ export declare const MAX_SAMPLE_RATE = 400;
6
+ /** Default sample rate in milliseconds */
7
+ export declare const DEFAULT_SAMPLE_RATE = 5;
8
+ /**
9
+ * Clamp a preset's sample rate to 5–400 ms.
10
+ *
11
+ * @example
12
+ * clampSampleRate(1000); // 400
13
+ */
14
+ export declare const clampSampleRate: (rate: number | undefined) => number;
15
+ /**
16
+ * Records a stroke's points over time: the first point (pointer down), then a point at most every `sampleRate` milliseconds while the pointer moves, and the last point (pointer up).
17
+ * No points are recorded while the pointer is still, even if it is held down.
18
+ *
19
+ * @example
20
+ * const sampler = new StrokeSampler(50);
21
+ * sampler.start({ x: 0, y: 0 }, 0);
22
+ * sampler.move({ x: 5, y: 0 }, 20); // undefined (too soon)
23
+ * sampler.move({ x: 9, y: 0 }, 60); // recorded
24
+ * sampler.end({ x: 12, y: 0 }, 70); // recorded
25
+ */
26
+ export default class StrokeSampler {
27
+ /** Milliseconds between recorded points */
28
+ readonly sampleRate: number;
29
+ /** Points recorded so far */
30
+ readonly points: BrushStrokePoint[];
31
+ private lastTime;
32
+ constructor(sampleRate?: number);
33
+ /** The most recently recorded point */
34
+ get last(): BrushStrokePoint | undefined;
35
+ /**
36
+ * Begin a stroke at the pointer-down point. Always recorded.
37
+ */
38
+ start(point: BrushStrokePoint, time: number): BrushStrokePoint;
39
+ /**
40
+ * Offer a point while the pointer moves. Returns it if recorded: enough time has passed and the pointer has moved.
41
+ */
42
+ move(point: BrushStrokePoint, time: number): BrushStrokePoint | undefined;
43
+ /**
44
+ * Finish the stroke at the pointer-up point. Returns it if recorded (it differs from the last recorded position).
45
+ */
46
+ end(point: BrushStrokePoint, time: number): BrushStrokePoint | undefined;
47
+ /**
48
+ * Check whether a point is at a different position from the last recorded point.
49
+ */
50
+ private hasMoved;
51
+ /**
52
+ * Record a point.
53
+ */
54
+ private record;
55
+ }
@@ -0,0 +1,75 @@
1
+ // src/lib/brushes/StrokeSampler/index.ts
2
+ /** Shortest allowed sample rate in milliseconds */
3
+ var MIN_SAMPLE_RATE = 5;
4
+ /** Longest allowed sample rate in milliseconds */
5
+ var MAX_SAMPLE_RATE = 400;
6
+ /** Default sample rate in milliseconds */
7
+ var DEFAULT_SAMPLE_RATE = 5;
8
+ /**
9
+ * Clamp a preset's sample rate to 5–400 ms.
10
+ *
11
+ * @example
12
+ * clampSampleRate(1000); // 400
13
+ */
14
+ var clampSampleRate = (rate) => Math.max(5, Math.min(400, rate ?? 5));
15
+ /**
16
+ * Records a stroke's points over time: the first point (pointer down), then a point at most every `sampleRate` milliseconds while the pointer moves, and the last point (pointer up).
17
+ * No points are recorded while the pointer is still, even if it is held down.
18
+ *
19
+ * @example
20
+ * const sampler = new StrokeSampler(50);
21
+ * sampler.start({ x: 0, y: 0 }, 0);
22
+ * sampler.move({ x: 5, y: 0 }, 20); // undefined (too soon)
23
+ * sampler.move({ x: 9, y: 0 }, 60); // recorded
24
+ * sampler.end({ x: 12, y: 0 }, 70); // recorded
25
+ */
26
+ var StrokeSampler = class {
27
+ /** Milliseconds between recorded points */
28
+ sampleRate;
29
+ /** Points recorded so far */
30
+ points = [];
31
+ lastTime = 0;
32
+ constructor(sampleRate) {
33
+ this.sampleRate = clampSampleRate(sampleRate);
34
+ }
35
+ /** The most recently recorded point */
36
+ get last() {
37
+ return this.points.at(-1);
38
+ }
39
+ /**
40
+ * Begin a stroke at the pointer-down point. Always recorded.
41
+ */
42
+ start(point, time) {
43
+ this.points.length = 0;
44
+ return this.record(point, time);
45
+ }
46
+ /**
47
+ * Offer a point while the pointer moves. Returns it if recorded: enough time has passed and the pointer has moved.
48
+ */
49
+ move(point, time) {
50
+ if (time - this.lastTime < this.sampleRate || !this.hasMoved(point)) return void 0;
51
+ return this.record(point, time);
52
+ }
53
+ /**
54
+ * Finish the stroke at the pointer-up point. Returns it if recorded (it differs from the last recorded position).
55
+ */
56
+ end(point, time) {
57
+ return this.hasMoved(point) ? this.record(point, time) : void 0;
58
+ }
59
+ /**
60
+ * Check whether a point is at a different position from the last recorded point.
61
+ */
62
+ hasMoved(point) {
63
+ const last = this.last;
64
+ return !last || last.x !== point.x || last.y !== point.y;
65
+ }
66
+ /**
67
+ * Record a point.
68
+ */
69
+ record(point, time) {
70
+ this.points.push(point);
71
+ this.lastTime = time;
72
+ return point;
73
+ }
74
+ };
75
+ export { DEFAULT_SAMPLE_RATE, MAX_SAMPLE_RATE, MIN_SAMPLE_RATE, clampSampleRate, StrokeSampler as default };