@motion-core/motion-gpu 0.5.0 → 0.7.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 (71) hide show
  1. package/README.md +35 -2
  2. package/dist/core/compute-bindgroup-cache.d.ts +13 -0
  3. package/dist/core/compute-bindgroup-cache.d.ts.map +1 -0
  4. package/dist/core/compute-bindgroup-cache.js +45 -0
  5. package/dist/core/compute-bindgroup-cache.js.map +1 -0
  6. package/dist/core/compute-shader.d.ts +48 -0
  7. package/dist/core/compute-shader.d.ts.map +1 -1
  8. package/dist/core/compute-shader.js +34 -1
  9. package/dist/core/compute-shader.js.map +1 -1
  10. package/dist/core/error-diagnostics.d.ts +8 -1
  11. package/dist/core/error-diagnostics.d.ts.map +1 -1
  12. package/dist/core/error-diagnostics.js +7 -3
  13. package/dist/core/error-diagnostics.js.map +1 -1
  14. package/dist/core/error-report.d.ts.map +1 -1
  15. package/dist/core/error-report.js +19 -1
  16. package/dist/core/error-report.js.map +1 -1
  17. package/dist/core/material.d.ts.map +1 -1
  18. package/dist/core/material.js +2 -1
  19. package/dist/core/material.js.map +1 -1
  20. package/dist/core/pointer.d.ts +96 -0
  21. package/dist/core/pointer.d.ts.map +1 -0
  22. package/dist/core/pointer.js +71 -0
  23. package/dist/core/pointer.js.map +1 -0
  24. package/dist/core/renderer.d.ts.map +1 -1
  25. package/dist/core/renderer.js +150 -85
  26. package/dist/core/renderer.js.map +1 -1
  27. package/dist/core/runtime-loop.d.ts.map +1 -1
  28. package/dist/core/runtime-loop.js +26 -14
  29. package/dist/core/runtime-loop.js.map +1 -1
  30. package/dist/core/shader.d.ts +7 -2
  31. package/dist/core/shader.d.ts.map +1 -1
  32. package/dist/core/shader.js +1 -0
  33. package/dist/core/shader.js.map +1 -1
  34. package/dist/core/textures.d.ts +4 -0
  35. package/dist/core/textures.d.ts.map +1 -1
  36. package/dist/core/textures.js +2 -1
  37. package/dist/core/textures.js.map +1 -1
  38. package/dist/core/types.d.ts +1 -1
  39. package/dist/core/types.d.ts.map +1 -1
  40. package/dist/react/advanced.js +2 -1
  41. package/dist/react/index.d.ts +2 -0
  42. package/dist/react/index.d.ts.map +1 -1
  43. package/dist/react/index.js +2 -1
  44. package/dist/react/use-pointer.d.ts +94 -0
  45. package/dist/react/use-pointer.d.ts.map +1 -0
  46. package/dist/react/use-pointer.js +285 -0
  47. package/dist/react/use-pointer.js.map +1 -0
  48. package/dist/svelte/advanced.js +2 -1
  49. package/dist/svelte/index.d.ts +2 -0
  50. package/dist/svelte/index.d.ts.map +1 -1
  51. package/dist/svelte/index.js +2 -1
  52. package/dist/svelte/use-pointer.d.ts +94 -0
  53. package/dist/svelte/use-pointer.d.ts.map +1 -0
  54. package/dist/svelte/use-pointer.js +292 -0
  55. package/dist/svelte/use-pointer.js.map +1 -0
  56. package/package.json +1 -1
  57. package/src/lib/core/compute-bindgroup-cache.ts +73 -0
  58. package/src/lib/core/compute-shader.ts +86 -0
  59. package/src/lib/core/error-diagnostics.ts +29 -4
  60. package/src/lib/core/error-report.ts +26 -1
  61. package/src/lib/core/material.ts +2 -1
  62. package/src/lib/core/pointer.ts +177 -0
  63. package/src/lib/core/renderer.ts +198 -92
  64. package/src/lib/core/runtime-loop.ts +37 -16
  65. package/src/lib/core/shader.ts +13 -2
  66. package/src/lib/core/textures.ts +6 -1
  67. package/src/lib/core/types.ts +1 -1
  68. package/src/lib/react/index.ts +10 -0
  69. package/src/lib/react/use-pointer.ts +515 -0
  70. package/src/lib/svelte/index.ts +10 -0
  71. package/src/lib/svelte/use-pointer.ts +507 -0
@@ -0,0 +1,285 @@
1
+ import { createCurrentWritable } from "../core/current-value.js";
2
+ import { createInitialPointerState, getPointerCoordinates, getPointerNowSeconds, normalizePointerKind, resolvePointerFrameRequestMode } from "../core/pointer.js";
3
+ import { useMotionGPU } from "./motiongpu-context.js";
4
+ import { useCallback, useEffect, useRef } from "react";
5
+ //#region src/lib/react/use-pointer.ts
6
+ /**
7
+ * Resolves a valid click duration threshold in milliseconds.
8
+ */
9
+ function resolveClickMaxDurationMs(value) {
10
+ if (typeof value !== "number" || Number.isNaN(value) || value <= 0) return 350;
11
+ return value;
12
+ }
13
+ /**
14
+ * Resolves a valid click travel threshold in pixels.
15
+ */
16
+ function resolveClickMaxMovePx(value) {
17
+ if (typeof value !== "number" || Number.isNaN(value) || value < 0) return 8;
18
+ return value;
19
+ }
20
+ /**
21
+ * Normalizes click button configuration with a primary-button fallback.
22
+ */
23
+ function normalizeClickButtons(buttons) {
24
+ const source = buttons && buttons.length > 0 ? buttons : [0];
25
+ return new Set(source);
26
+ }
27
+ /**
28
+ * Tracks normalized pointer coordinates and click/tap snapshots for the active `FragCanvas`.
29
+ */
30
+ function usePointer(options = {}) {
31
+ const motiongpu = useMotionGPU();
32
+ const stateRef = useRef(createCurrentWritable(createInitialPointerState()));
33
+ const clickRef = useRef(createCurrentWritable(null));
34
+ const optionsRef = useRef(options);
35
+ const activePointerIdRef = useRef(null);
36
+ const downSnapshotRef = useRef(null);
37
+ const clickCounterRef = useRef(0);
38
+ const previousPxRef = useRef(null);
39
+ const previousUvRef = useRef(null);
40
+ const previousTimeSecondsRef = useRef(0);
41
+ optionsRef.current = options;
42
+ const requestFrame = useCallback(() => {
43
+ const mode = resolvePointerFrameRequestMode(optionsRef.current.requestFrame ?? "auto", motiongpu.renderMode.current);
44
+ if (mode === "invalidate") {
45
+ motiongpu.invalidate();
46
+ return;
47
+ }
48
+ if (mode === "advance") motiongpu.advance();
49
+ }, [motiongpu]);
50
+ /**
51
+ * Commits a full pointer state snapshot with computed delta and velocity vectors.
52
+ */
53
+ const updatePointerState = useCallback((input) => {
54
+ const nowSeconds = getPointerNowSeconds();
55
+ const previousTimeSeconds = previousTimeSecondsRef.current;
56
+ const dt = previousTimeSeconds > 0 ? Math.max(nowSeconds - previousTimeSeconds, 1e-6) : 0;
57
+ const previousPx = previousPxRef.current;
58
+ const previousUv = previousUvRef.current;
59
+ const deltaPx = input.resetDelta || !previousPx ? [0, 0] : [input.point.px[0] - previousPx[0], input.point.px[1] - previousPx[1]];
60
+ const deltaUv = input.resetDelta || !previousUv ? [0, 0] : [input.point.uv[0] - previousUv[0], input.point.uv[1] - previousUv[1]];
61
+ const velocityPx = dt > 0 ? [deltaPx[0] / dt, deltaPx[1] / dt] : [0, 0];
62
+ const velocityUv = dt > 0 ? [deltaUv[0] / dt, deltaUv[1] / dt] : [0, 0];
63
+ const nextState = {
64
+ px: input.point.px,
65
+ uv: input.point.uv,
66
+ ndc: input.point.ndc,
67
+ inside: input.inside,
68
+ pressed: input.pressed,
69
+ dragging: input.dragging,
70
+ pointerType: input.pointerType,
71
+ pointerId: input.pointerId,
72
+ button: input.button,
73
+ buttons: input.buttons,
74
+ time: nowSeconds,
75
+ downPx: input.downPx,
76
+ downUv: input.downUv,
77
+ deltaPx,
78
+ deltaUv,
79
+ velocityPx,
80
+ velocityUv
81
+ };
82
+ stateRef.current.set(nextState);
83
+ previousPxRef.current = input.point.px;
84
+ previousUvRef.current = input.point.uv;
85
+ previousTimeSecondsRef.current = nowSeconds;
86
+ requestFrame();
87
+ return nextState;
88
+ }, [requestFrame]);
89
+ useEffect(() => {
90
+ if (!(optionsRef.current.enabled ?? true)) return;
91
+ const canvas = motiongpu.canvas;
92
+ if (!canvas) return;
93
+ const isTrackedPointer = (event) => activePointerIdRef.current === null || event.pointerId === activePointerIdRef.current;
94
+ const handlePointerDown = (event) => {
95
+ const point = getPointerCoordinates(event.clientX, event.clientY, canvas.getBoundingClientRect());
96
+ const pointerType = normalizePointerKind(event.pointerType);
97
+ activePointerIdRef.current = event.pointerId;
98
+ downSnapshotRef.current = {
99
+ pointerId: event.pointerId,
100
+ pointerType,
101
+ button: event.button,
102
+ timeMs: getPointerNowSeconds() * 1e3,
103
+ px: point.px,
104
+ uv: point.uv,
105
+ inside: point.inside
106
+ };
107
+ if (optionsRef.current.capturePointer ?? true) try {
108
+ canvas.setPointerCapture(event.pointerId);
109
+ } catch {}
110
+ const nextState = updatePointerState({
111
+ point,
112
+ inside: point.inside,
113
+ pressed: true,
114
+ dragging: false,
115
+ pointerType,
116
+ pointerId: event.pointerId,
117
+ button: event.button,
118
+ buttons: event.buttons,
119
+ downPx: point.px,
120
+ downUv: point.uv,
121
+ resetDelta: true
122
+ });
123
+ optionsRef.current.onDown?.(nextState, event);
124
+ };
125
+ const handleMove = (event) => {
126
+ if (!isTrackedPointer(event)) return;
127
+ const point = getPointerCoordinates(event.clientX, event.clientY, canvas.getBoundingClientRect());
128
+ const pressed = activePointerIdRef.current !== null && event.pointerId === activePointerIdRef.current;
129
+ const downPx = pressed ? downSnapshotRef.current?.px ?? point.px : null;
130
+ const downUv = pressed ? downSnapshotRef.current?.uv ?? point.uv : null;
131
+ let dragging = false;
132
+ if (pressed && downPx) {
133
+ const dx = point.px[0] - downPx[0];
134
+ const dy = point.px[1] - downPx[1];
135
+ dragging = Math.hypot(dx, dy) > 0;
136
+ }
137
+ const nextState = updatePointerState({
138
+ point,
139
+ inside: point.inside,
140
+ pressed,
141
+ dragging,
142
+ pointerType: normalizePointerKind(event.pointerType),
143
+ pointerId: event.pointerId,
144
+ button: pressed ? downSnapshotRef.current?.button ?? event.button : null,
145
+ buttons: event.buttons,
146
+ downPx,
147
+ downUv
148
+ });
149
+ optionsRef.current.onMove?.(nextState, event);
150
+ };
151
+ const handleWindowMove = (event) => {
152
+ if (!(optionsRef.current.trackWhilePressedOutsideCanvas ?? true) || activePointerIdRef.current === null || event.pointerId !== activePointerIdRef.current) return;
153
+ const point = getPointerCoordinates(event.clientX, event.clientY, canvas.getBoundingClientRect());
154
+ if (point.inside) return;
155
+ const downPx = downSnapshotRef.current?.px ?? point.px;
156
+ const downUv = downSnapshotRef.current?.uv ?? point.uv;
157
+ const dx = point.px[0] - downPx[0];
158
+ const dy = point.px[1] - downPx[1];
159
+ const nextState = updatePointerState({
160
+ point,
161
+ inside: false,
162
+ pressed: true,
163
+ dragging: Math.hypot(dx, dy) > 0,
164
+ pointerType: downSnapshotRef.current?.pointerType ?? normalizePointerKind(event.pointerType),
165
+ pointerId: event.pointerId,
166
+ button: downSnapshotRef.current?.button ?? event.button,
167
+ buttons: event.buttons,
168
+ downPx,
169
+ downUv
170
+ });
171
+ optionsRef.current.onMove?.(nextState, event);
172
+ };
173
+ const releasePointer = (event, emitClick) => {
174
+ if (activePointerIdRef.current === null || event.pointerId !== activePointerIdRef.current) return;
175
+ const point = getPointerCoordinates(event.clientX, event.clientY, canvas.getBoundingClientRect());
176
+ const previous = downSnapshotRef.current;
177
+ const pointerType = previous?.pointerType ?? normalizePointerKind(event.pointerType);
178
+ const nextState = updatePointerState({
179
+ point,
180
+ inside: point.inside,
181
+ pressed: false,
182
+ dragging: false,
183
+ pointerType,
184
+ pointerId: null,
185
+ button: null,
186
+ buttons: event.buttons,
187
+ downPx: null,
188
+ downUv: null
189
+ });
190
+ optionsRef.current.onUp?.(nextState, event);
191
+ if ((optionsRef.current.capturePointer ?? true) && canvas.hasPointerCapture(event.pointerId)) try {
192
+ canvas.releasePointerCapture(event.pointerId);
193
+ } catch {}
194
+ if (emitClick && (optionsRef.current.clickEnabled ?? true) && previous) {
195
+ if (normalizeClickButtons(optionsRef.current.clickButtons).has(previous.button)) {
196
+ const clickMaxDurationMs = resolveClickMaxDurationMs(optionsRef.current.clickMaxDurationMs);
197
+ const clickMaxMovePx = resolveClickMaxMovePx(optionsRef.current.clickMaxMovePx);
198
+ const durationMs = getPointerNowSeconds() * 1e3 - previous.timeMs;
199
+ const dx = point.px[0] - previous.px[0];
200
+ const dy = point.px[1] - previous.px[1];
201
+ const moveDistance = Math.hypot(dx, dy);
202
+ if (previous.inside && point.inside && durationMs <= clickMaxDurationMs && moveDistance <= clickMaxMovePx) {
203
+ clickCounterRef.current += 1;
204
+ const click = {
205
+ id: clickCounterRef.current,
206
+ time: getPointerNowSeconds(),
207
+ pointerType,
208
+ pointerId: event.pointerId,
209
+ button: previous.button,
210
+ modifiers: {
211
+ alt: event.altKey,
212
+ ctrl: event.ctrlKey,
213
+ shift: event.shiftKey,
214
+ meta: event.metaKey
215
+ },
216
+ px: point.px,
217
+ uv: point.uv,
218
+ ndc: point.ndc
219
+ };
220
+ clickRef.current.set(click);
221
+ optionsRef.current.onClick?.(click, nextState, event);
222
+ requestFrame();
223
+ }
224
+ }
225
+ }
226
+ activePointerIdRef.current = null;
227
+ downSnapshotRef.current = null;
228
+ };
229
+ const handlePointerUp = (event) => {
230
+ releasePointer(event, true);
231
+ };
232
+ const handlePointerCancel = (event) => {
233
+ releasePointer(event, false);
234
+ };
235
+ const handlePointerLeave = () => {
236
+ if (activePointerIdRef.current !== null) return;
237
+ const current = stateRef.current.current;
238
+ stateRef.current.set({
239
+ ...current,
240
+ inside: false,
241
+ time: getPointerNowSeconds(),
242
+ deltaPx: [0, 0],
243
+ deltaUv: [0, 0],
244
+ velocityPx: [0, 0],
245
+ velocityUv: [0, 0]
246
+ });
247
+ requestFrame();
248
+ };
249
+ canvas.addEventListener("pointerdown", handlePointerDown);
250
+ canvas.addEventListener("pointermove", handleMove);
251
+ canvas.addEventListener("pointerup", handlePointerUp);
252
+ canvas.addEventListener("pointercancel", handlePointerCancel);
253
+ canvas.addEventListener("pointerleave", handlePointerLeave);
254
+ if (optionsRef.current.trackWhilePressedOutsideCanvas ?? true) {
255
+ window.addEventListener("pointermove", handleWindowMove);
256
+ window.addEventListener("pointerup", handlePointerUp);
257
+ window.addEventListener("pointercancel", handlePointerCancel);
258
+ }
259
+ return () => {
260
+ canvas.removeEventListener("pointerdown", handlePointerDown);
261
+ canvas.removeEventListener("pointermove", handleMove);
262
+ canvas.removeEventListener("pointerup", handlePointerUp);
263
+ canvas.removeEventListener("pointercancel", handlePointerCancel);
264
+ canvas.removeEventListener("pointerleave", handlePointerLeave);
265
+ window.removeEventListener("pointermove", handleWindowMove);
266
+ window.removeEventListener("pointerup", handlePointerUp);
267
+ window.removeEventListener("pointercancel", handlePointerCancel);
268
+ };
269
+ }, [
270
+ motiongpu,
271
+ requestFrame,
272
+ updatePointerState
273
+ ]);
274
+ return {
275
+ state: stateRef.current,
276
+ lastClick: clickRef.current,
277
+ resetClick: useCallback(() => {
278
+ clickRef.current.set(null);
279
+ }, [])
280
+ };
281
+ }
282
+ //#endregion
283
+ export { usePointer };
284
+
285
+ //# sourceMappingURL=use-pointer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-pointer.js","names":[],"sources":["../../src/lib/react/use-pointer.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport {\n\tcreateCurrentWritable as currentWritable,\n\ttype CurrentReadable\n} from '../core/current-value.js';\nimport {\n\tcreateInitialPointerState,\n\tgetPointerCoordinates,\n\tgetPointerNowSeconds,\n\tnormalizePointerKind,\n\tresolvePointerFrameRequestMode,\n\ttype PointerClick,\n\ttype PointerFrameRequestMode,\n\ttype PointerState,\n\ttype PointerVec2\n} from '../core/pointer.js';\nimport { useMotionGPU } from './motiongpu-context.js';\n\nexport type {\n\tPointerClick,\n\tPointerFrameRequestMode,\n\tPointerKind,\n\tPointerPoint,\n\tPointerState\n} from '../core/pointer.js';\n\n/**\n * Configuration for pointer input handling in `usePointer`.\n */\nexport interface UsePointerOptions {\n\t/**\n\t * Enables pointer listeners.\n\t *\n\t * @default true\n\t */\n\tenabled?: boolean;\n\t/**\n\t * Frame wake-up strategy for pointer-driven state changes.\n\t *\n\t * @default 'auto'\n\t */\n\trequestFrame?: PointerFrameRequestMode;\n\t/**\n\t * Requests pointer capture on pointer down.\n\t *\n\t * @default true\n\t */\n\tcapturePointer?: boolean;\n\t/**\n\t * Tracks pointer move/up outside canvas while pointer is pressed.\n\t *\n\t * @default true\n\t */\n\ttrackWhilePressedOutsideCanvas?: boolean;\n\t/**\n\t * Enables click/tap synthesis on pointer up.\n\t *\n\t * @default true\n\t */\n\tclickEnabled?: boolean;\n\t/**\n\t * Maximum press duration to consider pointer up a click (milliseconds).\n\t *\n\t * @default 350\n\t */\n\tclickMaxDurationMs?: number;\n\t/**\n\t * Maximum pointer travel from down to up to consider pointer up a click (pixels).\n\t *\n\t * @default 8\n\t */\n\tclickMaxMovePx?: number;\n\t/**\n\t * Allowed pointer buttons for click synthesis.\n\t *\n\t * @default [0]\n\t */\n\tclickButtons?: number[];\n\t/**\n\t * Called after pointer move state update.\n\t */\n\tonMove?: (state: PointerState, event: PointerEvent) => void;\n\t/**\n\t * Called after pointer down state update.\n\t */\n\tonDown?: (state: PointerState, event: PointerEvent) => void;\n\t/**\n\t * Called after pointer up/cancel state update.\n\t */\n\tonUp?: (state: PointerState, event: PointerEvent) => void;\n\t/**\n\t * Called when click/tap is synthesized.\n\t */\n\tonClick?: (click: PointerClick, state: PointerState, event: PointerEvent) => void;\n}\n\n/**\n * Reactive state returned by `usePointer`.\n */\nexport interface UsePointerResult {\n\t/**\n\t * Current pointer state.\n\t */\n\tstate: CurrentReadable<PointerState>;\n\t/**\n\t * Last synthesized click/tap event.\n\t */\n\tlastClick: CurrentReadable<PointerClick | null>;\n\t/**\n\t * Clears last click snapshot.\n\t */\n\tresetClick: () => void;\n}\n\ninterface PointerDownSnapshot {\n\tbutton: number;\n\tinside: boolean;\n\tpointerId: number;\n\tpointerType: 'mouse' | 'pen' | 'touch';\n\tpx: PointerVec2;\n\ttimeMs: number;\n\tuv: PointerVec2;\n}\n\n/**\n * Resolves a valid click duration threshold in milliseconds.\n */\nfunction resolveClickMaxDurationMs(value: number | undefined): number {\n\tif (typeof value !== 'number' || Number.isNaN(value) || value <= 0) {\n\t\treturn 350;\n\t}\n\n\treturn value;\n}\n\n/**\n * Resolves a valid click travel threshold in pixels.\n */\nfunction resolveClickMaxMovePx(value: number | undefined): number {\n\tif (typeof value !== 'number' || Number.isNaN(value) || value < 0) {\n\t\treturn 8;\n\t}\n\n\treturn value;\n}\n\n/**\n * Normalizes click button configuration with a primary-button fallback.\n */\nfunction normalizeClickButtons(buttons: number[] | undefined): Set<number> {\n\tconst source = buttons && buttons.length > 0 ? buttons : [0];\n\treturn new Set(source);\n}\n\n/**\n * Tracks normalized pointer coordinates and click/tap snapshots for the active `FragCanvas`.\n */\nexport function usePointer(options: UsePointerOptions = {}): UsePointerResult {\n\tconst motiongpu = useMotionGPU();\n\tconst stateRef = useRef(currentWritable<PointerState>(createInitialPointerState()));\n\tconst clickRef = useRef(currentWritable<PointerClick | null>(null));\n\tconst optionsRef = useRef(options);\n\tconst activePointerIdRef = useRef<number | null>(null);\n\tconst downSnapshotRef = useRef<PointerDownSnapshot | null>(null);\n\tconst clickCounterRef = useRef(0);\n\tconst previousPxRef = useRef<PointerVec2 | null>(null);\n\tconst previousUvRef = useRef<PointerVec2 | null>(null);\n\tconst previousTimeSecondsRef = useRef(0);\n\n\toptionsRef.current = options;\n\n\tconst requestFrame = useCallback((): void => {\n\t\tconst mode = resolvePointerFrameRequestMode(\n\t\t\toptionsRef.current.requestFrame ?? 'auto',\n\t\t\tmotiongpu.renderMode.current\n\t\t);\n\t\tif (mode === 'invalidate') {\n\t\t\tmotiongpu.invalidate();\n\t\t\treturn;\n\t\t}\n\t\tif (mode === 'advance') {\n\t\t\tmotiongpu.advance();\n\t\t}\n\t}, [motiongpu]);\n\n\t/**\n\t * Commits a full pointer state snapshot with computed delta and velocity vectors.\n\t */\n\tconst updatePointerState = useCallback(\n\t\t(input: {\n\t\t\tbutton: number | null;\n\t\t\tbuttons: number;\n\t\t\tdownPx: PointerVec2 | null;\n\t\t\tdownUv: PointerVec2 | null;\n\t\t\tdragging: boolean;\n\t\t\tinside: boolean;\n\t\t\tpointerId: number | null;\n\t\t\tpointerType: 'mouse' | 'pen' | 'touch' | null;\n\t\t\tpressed: boolean;\n\t\t\tpoint: {\n\t\t\t\tndc: PointerVec2;\n\t\t\t\tpx: PointerVec2;\n\t\t\t\tuv: PointerVec2;\n\t\t\t};\n\t\t\tresetDelta?: boolean;\n\t\t}): PointerState => {\n\t\t\tconst nowSeconds = getPointerNowSeconds();\n\t\t\tconst previousTimeSeconds = previousTimeSecondsRef.current;\n\t\t\tconst dt = previousTimeSeconds > 0 ? Math.max(nowSeconds - previousTimeSeconds, 1e-6) : 0;\n\t\t\tconst previousPx = previousPxRef.current;\n\t\t\tconst previousUv = previousUvRef.current;\n\t\t\tconst deltaPx: PointerVec2 =\n\t\t\t\tinput.resetDelta || !previousPx\n\t\t\t\t\t? [0, 0]\n\t\t\t\t\t: [input.point.px[0] - previousPx[0], input.point.px[1] - previousPx[1]];\n\t\t\tconst deltaUv: PointerVec2 =\n\t\t\t\tinput.resetDelta || !previousUv\n\t\t\t\t\t? [0, 0]\n\t\t\t\t\t: [input.point.uv[0] - previousUv[0], input.point.uv[1] - previousUv[1]];\n\t\t\tconst velocityPx: PointerVec2 = dt > 0 ? [deltaPx[0] / dt, deltaPx[1] / dt] : [0, 0];\n\t\t\tconst velocityUv: PointerVec2 = dt > 0 ? [deltaUv[0] / dt, deltaUv[1] / dt] : [0, 0];\n\t\t\tconst nextState: PointerState = {\n\t\t\t\tpx: input.point.px,\n\t\t\t\tuv: input.point.uv,\n\t\t\t\tndc: input.point.ndc,\n\t\t\t\tinside: input.inside,\n\t\t\t\tpressed: input.pressed,\n\t\t\t\tdragging: input.dragging,\n\t\t\t\tpointerType: input.pointerType,\n\t\t\t\tpointerId: input.pointerId,\n\t\t\t\tbutton: input.button,\n\t\t\t\tbuttons: input.buttons,\n\t\t\t\ttime: nowSeconds,\n\t\t\t\tdownPx: input.downPx,\n\t\t\t\tdownUv: input.downUv,\n\t\t\t\tdeltaPx,\n\t\t\t\tdeltaUv,\n\t\t\t\tvelocityPx,\n\t\t\t\tvelocityUv\n\t\t\t};\n\t\t\tstateRef.current.set(nextState);\n\t\t\tpreviousPxRef.current = input.point.px;\n\t\t\tpreviousUvRef.current = input.point.uv;\n\t\t\tpreviousTimeSecondsRef.current = nowSeconds;\n\t\t\trequestFrame();\n\t\t\treturn nextState;\n\t\t},\n\t\t[requestFrame]\n\t);\n\n\tuseEffect(() => {\n\t\tconst enabled = optionsRef.current.enabled ?? true;\n\t\tif (!enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst canvas = motiongpu.canvas;\n\t\tif (!canvas) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isTrackedPointer = (event: PointerEvent): boolean =>\n\t\t\tactivePointerIdRef.current === null || event.pointerId === activePointerIdRef.current;\n\n\t\tconst handlePointerDown = (event: PointerEvent): void => {\n\t\t\tconst point = getPointerCoordinates(\n\t\t\t\tevent.clientX,\n\t\t\t\tevent.clientY,\n\t\t\t\tcanvas.getBoundingClientRect()\n\t\t\t);\n\t\t\tconst pointerType = normalizePointerKind(event.pointerType);\n\t\t\tactivePointerIdRef.current = event.pointerId;\n\t\t\tdownSnapshotRef.current = {\n\t\t\t\tpointerId: event.pointerId,\n\t\t\t\tpointerType,\n\t\t\t\tbutton: event.button,\n\t\t\t\ttimeMs: getPointerNowSeconds() * 1000,\n\t\t\t\tpx: point.px,\n\t\t\t\tuv: point.uv,\n\t\t\t\tinside: point.inside\n\t\t\t};\n\t\t\tif (optionsRef.current.capturePointer ?? true) {\n\t\t\t\ttry {\n\t\t\t\t\tcanvas.setPointerCapture(event.pointerId);\n\t\t\t\t} catch {\n\t\t\t\t\t// Browser rejected capture (e.g. unsupported pointer state).\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst nextState = updatePointerState({\n\t\t\t\tpoint,\n\t\t\t\tinside: point.inside,\n\t\t\t\tpressed: true,\n\t\t\t\tdragging: false,\n\t\t\t\tpointerType,\n\t\t\t\tpointerId: event.pointerId,\n\t\t\t\tbutton: event.button,\n\t\t\t\tbuttons: event.buttons,\n\t\t\t\tdownPx: point.px,\n\t\t\t\tdownUv: point.uv,\n\t\t\t\tresetDelta: true\n\t\t\t});\n\t\t\toptionsRef.current.onDown?.(nextState, event);\n\t\t};\n\n\t\tconst handleMove = (event: PointerEvent): void => {\n\t\t\tif (!isTrackedPointer(event)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst point = getPointerCoordinates(\n\t\t\t\tevent.clientX,\n\t\t\t\tevent.clientY,\n\t\t\t\tcanvas.getBoundingClientRect()\n\t\t\t);\n\t\t\tconst pressed =\n\t\t\t\tactivePointerIdRef.current !== null && event.pointerId === activePointerIdRef.current;\n\t\t\tconst downPx = pressed ? (downSnapshotRef.current?.px ?? point.px) : null;\n\t\t\tconst downUv = pressed ? (downSnapshotRef.current?.uv ?? point.uv) : null;\n\t\t\tlet dragging = false;\n\t\t\tif (pressed && downPx) {\n\t\t\t\tconst dx = point.px[0] - downPx[0];\n\t\t\t\tconst dy = point.px[1] - downPx[1];\n\t\t\t\tdragging = Math.hypot(dx, dy) > 0;\n\t\t\t}\n\t\t\tconst nextState = updatePointerState({\n\t\t\t\tpoint,\n\t\t\t\tinside: point.inside,\n\t\t\t\tpressed,\n\t\t\t\tdragging,\n\t\t\t\tpointerType: normalizePointerKind(event.pointerType),\n\t\t\t\tpointerId: event.pointerId,\n\t\t\t\tbutton: pressed ? (downSnapshotRef.current?.button ?? event.button) : null,\n\t\t\t\tbuttons: event.buttons,\n\t\t\t\tdownPx,\n\t\t\t\tdownUv\n\t\t\t});\n\t\t\toptionsRef.current.onMove?.(nextState, event);\n\t\t};\n\n\t\tconst handleWindowMove = (event: PointerEvent): void => {\n\t\t\tif (\n\t\t\t\t!(optionsRef.current.trackWhilePressedOutsideCanvas ?? true) ||\n\t\t\t\tactivePointerIdRef.current === null ||\n\t\t\t\tevent.pointerId !== activePointerIdRef.current\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst point = getPointerCoordinates(\n\t\t\t\tevent.clientX,\n\t\t\t\tevent.clientY,\n\t\t\t\tcanvas.getBoundingClientRect()\n\t\t\t);\n\t\t\tif (point.inside) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst downPx = downSnapshotRef.current?.px ?? point.px;\n\t\t\tconst downUv = downSnapshotRef.current?.uv ?? point.uv;\n\t\t\tconst dx = point.px[0] - downPx[0];\n\t\t\tconst dy = point.px[1] - downPx[1];\n\t\t\tconst nextState = updatePointerState({\n\t\t\t\tpoint,\n\t\t\t\tinside: false,\n\t\t\t\tpressed: true,\n\t\t\t\tdragging: Math.hypot(dx, dy) > 0,\n\t\t\t\tpointerType:\n\t\t\t\t\tdownSnapshotRef.current?.pointerType ?? normalizePointerKind(event.pointerType),\n\t\t\t\tpointerId: event.pointerId,\n\t\t\t\tbutton: downSnapshotRef.current?.button ?? event.button,\n\t\t\t\tbuttons: event.buttons,\n\t\t\t\tdownPx,\n\t\t\t\tdownUv\n\t\t\t});\n\t\t\toptionsRef.current.onMove?.(nextState, event);\n\t\t};\n\n\t\tconst releasePointer = (event: PointerEvent, emitClick: boolean): void => {\n\t\t\tif (activePointerIdRef.current === null || event.pointerId !== activePointerIdRef.current) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst point = getPointerCoordinates(\n\t\t\t\tevent.clientX,\n\t\t\t\tevent.clientY,\n\t\t\t\tcanvas.getBoundingClientRect()\n\t\t\t);\n\t\t\tconst previous = downSnapshotRef.current;\n\t\t\tconst pointerType = previous?.pointerType ?? normalizePointerKind(event.pointerType);\n\t\t\tconst nextState = updatePointerState({\n\t\t\t\tpoint,\n\t\t\t\tinside: point.inside,\n\t\t\t\tpressed: false,\n\t\t\t\tdragging: false,\n\t\t\t\tpointerType,\n\t\t\t\tpointerId: null,\n\t\t\t\tbutton: null,\n\t\t\t\tbuttons: event.buttons,\n\t\t\t\tdownPx: null,\n\t\t\t\tdownUv: null\n\t\t\t});\n\t\t\toptionsRef.current.onUp?.(nextState, event);\n\n\t\t\tif (\n\t\t\t\t(optionsRef.current.capturePointer ?? true) &&\n\t\t\t\tcanvas.hasPointerCapture(event.pointerId)\n\t\t\t) {\n\t\t\t\ttry {\n\t\t\t\t\tcanvas.releasePointerCapture(event.pointerId);\n\t\t\t\t} catch {\n\t\t\t\t\t// Browser rejected release for this pointer id.\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (emitClick && (optionsRef.current.clickEnabled ?? true) && previous) {\n\t\t\t\tconst allowedButtons = normalizeClickButtons(optionsRef.current.clickButtons);\n\t\t\t\tif (allowedButtons.has(previous.button)) {\n\t\t\t\t\tconst clickMaxDurationMs = resolveClickMaxDurationMs(\n\t\t\t\t\t\toptionsRef.current.clickMaxDurationMs\n\t\t\t\t\t);\n\t\t\t\t\tconst clickMaxMovePx = resolveClickMaxMovePx(optionsRef.current.clickMaxMovePx);\n\t\t\t\t\tconst durationMs = getPointerNowSeconds() * 1000 - previous.timeMs;\n\t\t\t\t\tconst dx = point.px[0] - previous.px[0];\n\t\t\t\t\tconst dy = point.px[1] - previous.px[1];\n\t\t\t\t\tconst moveDistance = Math.hypot(dx, dy);\n\t\t\t\t\tif (\n\t\t\t\t\t\tprevious.inside &&\n\t\t\t\t\t\tpoint.inside &&\n\t\t\t\t\t\tdurationMs <= clickMaxDurationMs &&\n\t\t\t\t\t\tmoveDistance <= clickMaxMovePx\n\t\t\t\t\t) {\n\t\t\t\t\t\tclickCounterRef.current += 1;\n\t\t\t\t\t\tconst click: PointerClick = {\n\t\t\t\t\t\t\tid: clickCounterRef.current,\n\t\t\t\t\t\t\ttime: getPointerNowSeconds(),\n\t\t\t\t\t\t\tpointerType,\n\t\t\t\t\t\t\tpointerId: event.pointerId,\n\t\t\t\t\t\t\tbutton: previous.button,\n\t\t\t\t\t\t\tmodifiers: {\n\t\t\t\t\t\t\t\talt: event.altKey,\n\t\t\t\t\t\t\t\tctrl: event.ctrlKey,\n\t\t\t\t\t\t\t\tshift: event.shiftKey,\n\t\t\t\t\t\t\t\tmeta: event.metaKey\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tpx: point.px,\n\t\t\t\t\t\t\tuv: point.uv,\n\t\t\t\t\t\t\tndc: point.ndc\n\t\t\t\t\t\t};\n\t\t\t\t\t\tclickRef.current.set(click);\n\t\t\t\t\t\toptionsRef.current.onClick?.(click, nextState, event);\n\t\t\t\t\t\trequestFrame();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tactivePointerIdRef.current = null;\n\t\t\tdownSnapshotRef.current = null;\n\t\t};\n\n\t\tconst handlePointerUp = (event: PointerEvent): void => {\n\t\t\treleasePointer(event, true);\n\t\t};\n\n\t\tconst handlePointerCancel = (event: PointerEvent): void => {\n\t\t\treleasePointer(event, false);\n\t\t};\n\n\t\tconst handlePointerLeave = (): void => {\n\t\t\tif (activePointerIdRef.current !== null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst current = stateRef.current.current;\n\t\t\tstateRef.current.set({\n\t\t\t\t...current,\n\t\t\t\tinside: false,\n\t\t\t\ttime: getPointerNowSeconds(),\n\t\t\t\tdeltaPx: [0, 0],\n\t\t\t\tdeltaUv: [0, 0],\n\t\t\t\tvelocityPx: [0, 0],\n\t\t\t\tvelocityUv: [0, 0]\n\t\t\t});\n\t\t\trequestFrame();\n\t\t};\n\n\t\tcanvas.addEventListener('pointerdown', handlePointerDown);\n\t\tcanvas.addEventListener('pointermove', handleMove);\n\t\tcanvas.addEventListener('pointerup', handlePointerUp);\n\t\tcanvas.addEventListener('pointercancel', handlePointerCancel);\n\t\tcanvas.addEventListener('pointerleave', handlePointerLeave);\n\t\tif (optionsRef.current.trackWhilePressedOutsideCanvas ?? true) {\n\t\t\twindow.addEventListener('pointermove', handleWindowMove);\n\t\t\twindow.addEventListener('pointerup', handlePointerUp);\n\t\t\twindow.addEventListener('pointercancel', handlePointerCancel);\n\t\t}\n\n\t\treturn () => {\n\t\t\tcanvas.removeEventListener('pointerdown', handlePointerDown);\n\t\t\tcanvas.removeEventListener('pointermove', handleMove);\n\t\t\tcanvas.removeEventListener('pointerup', handlePointerUp);\n\t\t\tcanvas.removeEventListener('pointercancel', handlePointerCancel);\n\t\t\tcanvas.removeEventListener('pointerleave', handlePointerLeave);\n\t\t\twindow.removeEventListener('pointermove', handleWindowMove);\n\t\t\twindow.removeEventListener('pointerup', handlePointerUp);\n\t\t\twindow.removeEventListener('pointercancel', handlePointerCancel);\n\t\t};\n\t}, [motiongpu, requestFrame, updatePointerState]);\n\n\treturn {\n\t\tstate: stateRef.current,\n\t\tlastClick: clickRef.current,\n\t\tresetClick: useCallback(() => {\n\t\t\tclickRef.current.set(null);\n\t\t}, [])\n\t};\n}\n"],"mappings":"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"}
@@ -7,7 +7,8 @@ import { PingPongComputePass } from "../passes/PingPongComputePass.js";
7
7
  import { applySchedulerPreset, captureSchedulerDebugSnapshot } from "../core/scheduler-helpers.js";
8
8
  import { useMotionGPU } from "./motiongpu-context.js";
9
9
  import { useFrame } from "./frame-context.js";
10
+ import { usePointer } from "./use-pointer.js";
10
11
  import { useTexture } from "./use-texture.js";
11
12
  import { FragCanvas } from "./index.js";
12
13
  import { setMotionGPUUserContext, useMotionGPUUserContext } from "./use-motiongpu-user-context.js";
13
- export { BlitPass, ComputePass, CopyPass, FragCanvas, PingPongComputePass, ShaderPass, applySchedulerPreset, captureSchedulerDebugSnapshot, defineMaterial, setMotionGPUUserContext, useFrame, useMotionGPU, useMotionGPUUserContext, useTexture };
14
+ export { BlitPass, ComputePass, CopyPass, FragCanvas, PingPongComputePass, ShaderPass, applySchedulerPreset, captureSchedulerDebugSnapshot, defineMaterial, setMotionGPUUserContext, useFrame, useMotionGPU, useMotionGPUUserContext, usePointer, useTexture };
@@ -6,12 +6,14 @@ export { defineMaterial } from '../core/material.js';
6
6
  export { BlitPass, CopyPass, ShaderPass, ComputePass, PingPongComputePass } from '../passes/index.js';
7
7
  export { useMotionGPU } from './motiongpu-context.js';
8
8
  export { useFrame } from './frame-context.js';
9
+ export { usePointer } from './use-pointer.js';
9
10
  export { useTexture } from './use-texture.js';
10
11
  export type { FrameInvalidationToken, FrameState, OutputColorSpace, AnyPass, ComputePassLike, RenderPass, RenderPassContext, RenderPassFlags, RenderPassInputSlot, RenderPassOutputSlot, RenderMode, RenderTarget, RenderTargetDefinition, RenderTargetDefinitionMap, TextureData, TextureDefinition, TextureDefinitionMap, TextureUpdateMode, TextureMap, TextureSource, TextureValue, TypedUniform, UniformMat4Value, UniformMap, UniformType, UniformValue } from '../core/types.js';
11
12
  export type { LoadedTexture, TextureDecodeOptions, TextureLoadOptions } from '../core/texture-loader.js';
12
13
  export type { FragMaterial, FragMaterialInput, MaterialIncludes, MaterialDefineValue, MaterialDefines, TypedMaterialDefineValue } from '../core/material.js';
13
14
  export type { MotionGPUContext } from './motiongpu-context.js';
14
15
  export type { UseFrameOptions, UseFrameResult } from './frame-context.js';
16
+ export type { PointerClick, PointerFrameRequestMode, PointerKind, PointerPoint, PointerState, UsePointerOptions, UsePointerResult } from './use-pointer.js';
15
17
  export type { TextureUrlInput, UseTextureResult } from './use-texture.js';
16
18
  export type { StorageBufferAccess, StorageBufferDefinition, StorageBufferDefinitionMap, StorageBufferType, ComputePassContext } from '../core/types.js';
17
19
  export type { ComputePassOptions, ComputeDispatchContext } from '../passes/ComputePass.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/svelte/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACN,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EACX,sBAAsB,EACtB,UAAU,EACV,gBAAgB,EAChB,OAAO,EACP,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,UAAU,EACV,YAAY,EACZ,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,YAAY,EACZ,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACX,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACX,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,wBAAwB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,YAAY,EACX,mBAAmB,EACnB,uBAAuB,EACvB,0BAA0B,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAC3F,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/svelte/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACN,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EACX,sBAAsB,EACtB,UAAU,EACV,gBAAgB,EAChB,OAAO,EACP,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,UAAU,EACV,YAAY,EACZ,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,YAAY,EACZ,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACX,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACX,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,wBAAwB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EACX,YAAY,EACZ,uBAAuB,EACvB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,YAAY,EACX,mBAAmB,EACnB,uBAAuB,EACvB,0BAA0B,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAC3F,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC"}
@@ -7,6 +7,7 @@ import { PingPongComputePass } from "../passes/PingPongComputePass.js";
7
7
  import "../passes/index.js";
8
8
  import { useMotionGPU } from "./motiongpu-context.js";
9
9
  import { useFrame } from "./frame-context.js";
10
+ import { usePointer } from "./use-pointer.js";
10
11
  import { useTexture } from "./use-texture.js";
11
12
  import FragCanvas from "./FragCanvas.svelte";
12
- export { BlitPass, ComputePass, CopyPass, FragCanvas, PingPongComputePass, ShaderPass, defineMaterial, useFrame, useMotionGPU, useTexture };
13
+ export { BlitPass, ComputePass, CopyPass, FragCanvas, PingPongComputePass, ShaderPass, defineMaterial, useFrame, useMotionGPU, usePointer, useTexture };
@@ -0,0 +1,94 @@
1
+ import { type CurrentReadable } from '../core/current-value.js';
2
+ import { type PointerClick, type PointerFrameRequestMode, type PointerState } from '../core/pointer.js';
3
+ export type { PointerClick, PointerFrameRequestMode, PointerKind, PointerPoint, PointerState } from '../core/pointer.js';
4
+ /**
5
+ * Configuration for pointer input handling in `usePointer`.
6
+ */
7
+ export interface UsePointerOptions {
8
+ /**
9
+ * Enables pointer listeners.
10
+ *
11
+ * @default true
12
+ */
13
+ enabled?: boolean;
14
+ /**
15
+ * Frame wake-up strategy for pointer-driven state changes.
16
+ *
17
+ * @default 'auto'
18
+ */
19
+ requestFrame?: PointerFrameRequestMode;
20
+ /**
21
+ * Requests pointer capture on pointer down.
22
+ *
23
+ * @default true
24
+ */
25
+ capturePointer?: boolean;
26
+ /**
27
+ * Tracks pointer move/up outside canvas while pointer is pressed.
28
+ *
29
+ * @default true
30
+ */
31
+ trackWhilePressedOutsideCanvas?: boolean;
32
+ /**
33
+ * Enables click/tap synthesis on pointer up.
34
+ *
35
+ * @default true
36
+ */
37
+ clickEnabled?: boolean;
38
+ /**
39
+ * Maximum press duration to consider pointer up a click (milliseconds).
40
+ *
41
+ * @default 350
42
+ */
43
+ clickMaxDurationMs?: number;
44
+ /**
45
+ * Maximum pointer travel from down to up to consider pointer up a click (pixels).
46
+ *
47
+ * @default 8
48
+ */
49
+ clickMaxMovePx?: number;
50
+ /**
51
+ * Allowed pointer buttons for click synthesis.
52
+ *
53
+ * @default [0]
54
+ */
55
+ clickButtons?: number[];
56
+ /**
57
+ * Called after pointer move state update.
58
+ */
59
+ onMove?: (state: PointerState, event: PointerEvent) => void;
60
+ /**
61
+ * Called after pointer down state update.
62
+ */
63
+ onDown?: (state: PointerState, event: PointerEvent) => void;
64
+ /**
65
+ * Called after pointer up/cancel state update.
66
+ */
67
+ onUp?: (state: PointerState, event: PointerEvent) => void;
68
+ /**
69
+ * Called when click/tap is synthesized.
70
+ */
71
+ onClick?: (click: PointerClick, state: PointerState, event: PointerEvent) => void;
72
+ }
73
+ /**
74
+ * Reactive state returned by `usePointer`.
75
+ */
76
+ export interface UsePointerResult {
77
+ /**
78
+ * Current pointer state.
79
+ */
80
+ state: CurrentReadable<PointerState>;
81
+ /**
82
+ * Last synthesized click/tap event.
83
+ */
84
+ lastClick: CurrentReadable<PointerClick | null>;
85
+ /**
86
+ * Clears last click snapshot.
87
+ */
88
+ resetClick: () => void;
89
+ }
90
+ /**
91
+ * Tracks normalized pointer coordinates and click/tap snapshots for the active `FragCanvas`.
92
+ */
93
+ export declare function usePointer(options?: UsePointerOptions): UsePointerResult;
94
+ //# sourceMappingURL=use-pointer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-pointer.d.ts","sourceRoot":"","sources":["../../src/lib/svelte/use-pointer.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,KAAK,eAAe,EACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAMN,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,YAAY,EAEjB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EACX,YAAY,EACZ,uBAAuB,EACvB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,YAAY,CAAC,EAAE,uBAAuB,CAAC;IACvC;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5D;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5D;;OAEG;IACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1D;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAClF;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC;;OAEG;IACH,KAAK,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IACrC;;OAEG;IACH,SAAS,EAAE,eAAe,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAChD;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;CACvB;AA0CD;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CA6V5E"}