phase 0.0.11 → 0.1.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.
package/README.md CHANGED
@@ -176,9 +176,9 @@ The main primitive. Composes a ticker, visibility observer, and reduced-motion l
176
176
  import { createLoop } from 'phase';
177
177
 
178
178
  const loop = createLoop({
179
- element: el,
179
+ target: el,
180
180
  onTick: (frame) => {
181
- // frame.time — performance.now()
181
+ // frame.time — browser rAF timestamp
182
182
  // frame.delta — ms since last tick (clamped to 40ms)
183
183
  // frame.elapsed — ms since start (paused time excluded)
184
184
  // frame.frame — frame count
@@ -229,7 +229,7 @@ Controls the loop's response when quality degrades. Same three-value pattern as
229
229
 
230
230
  ```ts
231
231
  createLoop({
232
- element: el,
232
+ target: el,
233
233
  onTick: draw,
234
234
  degraded: 'throttle', // default
235
235
  degradedFps: 20, // only accepted when degraded is 'throttle'
@@ -240,7 +240,7 @@ createLoop({
240
240
 
241
241
  | Option | Type | Default | Description |
242
242
  | --------------- | ----------------------------------- | ------------ | ----------------------------------------- |
243
- | `element` | `Element` | required | Element to observe for visibility |
243
+ | `target` | `Element` | required | Element to observe for visibility |
244
244
  | `onTick` | `(frame: FrameState) => void` | required | Called each frame while running |
245
245
  | `fps` | `number` | — | Cap frames per second |
246
246
  | `reducedMotion` | `'pause' \| 'complete' \| 'ignore'` | `'pause'` | Behavior when user prefers reduced motion |
@@ -264,7 +264,7 @@ const ticker = createTicker({
264
264
  ticker.start();
265
265
  ```
266
266
 
267
- All tickers share a single `requestAnimationFrame` loop. Every subscriber reads the same `performance.now()` value each frame, so independent animations stay in visual sync.
267
+ All tickers share a single `requestAnimationFrame` loop. Every subscriber receives the same browser-supplied timestamp each frame, so independent animations stay in visual sync.
268
268
 
269
269
  #### Ticker phases
270
270
 
@@ -283,7 +283,7 @@ Answers one question: is this element visible right now? Combines `document.visi
283
283
  import { createSight } from 'phase';
284
284
 
285
285
  const sight = createSight({
286
- element: el,
286
+ target: el,
287
287
  onPhaseChange: (phase, reason) => {
288
288
  // phase: 'visible' | 'hidden' | 'unknown'
289
289
  // reason: 'initial' | 'viewport' | 'document' | 'bfcache' | 'all-hidden'
@@ -303,7 +303,7 @@ Use `createLifecycle` when you own your render loop (a three.js/WebGL renderer,
303
303
  import { createLifecycle } from 'phase';
304
304
 
305
305
  const lifecycle = createLifecycle({
306
- element: canvas,
306
+ target: canvas,
307
307
  onPhaseChange: (phase, reason) => {
308
308
  // phase: 'idle' | 'active' | 'paused' | 'stopped'
309
309
  // reason: 'started' | 'resumed' | 'sight' | 'reduced-motion' | 'manual' | 'disposed' | 'initial'
@@ -343,7 +343,7 @@ Reports what fraction of an element is currently visible in the viewport (0–1)
343
343
  import { createScrollProgress } from 'phase';
344
344
 
345
345
  const progress = createScrollProgress({
346
- element: el,
346
+ target: el,
347
347
  onProgress: (ratio) => {
348
348
  el.style.opacity = String(ratio);
349
349
  },
@@ -361,7 +361,7 @@ The `steps` option controls threshold granularity. Default `20` generates 21 eve
361
361
 
362
362
  | Option | Type | Default | Description |
363
363
  | ------------ | ----------------------------- | -------- | ---------------------------------- |
364
- | `element` | `Element` | required | Element to observe |
364
+ | `target` | `Element` | required | Element to observe |
365
365
  | `onProgress` | `(ratio: number) => void` | required | Called at each threshold crossing |
366
366
  | `steps` | `number` | `20` | Number of evenly-spaced thresholds |
367
367
  | `root` | `Element \| Document \| null` | — | IO root element |
@@ -377,7 +377,7 @@ Tracks a scroll container's offset and progress. Reads `scrollLeft`/`scrollTop`
377
377
  import { createScroll } from 'phase';
378
378
 
379
379
  const scroll = createScroll({
380
- element: viewport,
380
+ target: viewport,
381
381
  onScroll: (s) => {
382
382
  // thumb CSS needs `transform-origin: left` so scaleX anchors to the track start
383
383
  thumb.style.transform = `translateX(${s.progressX * (1 - s.visibleX) * 100}%) scaleX(${s.visibleX})`;
@@ -401,7 +401,7 @@ scroll.stop();
401
401
 
402
402
  | Option | Type | Default | Description |
403
403
  | --------------------- | ------------------------------ | --------- | -------------------------------------------------- |
404
- | `element` | `Element` | required | Scroll container to track |
404
+ | `target` | `Element` | required | Scroll container to track |
405
405
  | `onScroll` | `(state: ScrollState) => void` | required | Called once per rAF frame with position + progress |
406
406
  | `onPhaseChange` | `(phase, reason) => void` | — | Called on phase transitions |
407
407
  | `visibility` | `'pause' \| 'ignore'` | `'pause'` | Pause tracking when off-screen, or ignore |
@@ -481,7 +481,7 @@ Reports whether the browser is rendering an element or skipping it under `conten
481
481
  import { createRenderState } from 'phase';
482
482
 
483
483
  const renderState = createRenderState({
484
- element: el,
484
+ target: el,
485
485
  onPhaseChange: (phase) => {
486
486
  if (phase === 'skipped') clock.pause();
487
487
  else clock.resume();
@@ -518,7 +518,7 @@ A lifecycle-aware `MutationObserver`: records are coalesced into one callback pe
518
518
  import { createMutation } from 'phase';
519
519
 
520
520
  const mutation = createMutation({
521
- element: list,
521
+ target: list,
522
522
  mutation: { childList: true },
523
523
  onMutations: (records) => syncItems(records),
524
524
  });
@@ -536,7 +536,7 @@ Tracks pointer position relative to an element, batching high-frequency events i
536
536
  import { createPointer } from 'phase';
537
537
 
538
538
  const pointer = createPointer({
539
- element: surface,
539
+ target: surface,
540
540
  onPointer: (state) => {
541
541
  cursor.style.transform = `translate(${state.x}px, ${state.y}px)`;
542
542
  },
@@ -741,12 +741,12 @@ Animates a number from A to B over a duration. Calls `setState` per frame (appro
741
741
  ```tsx
742
742
  import { useTween } from 'phase/react';
743
743
 
744
- const opacity = useTween({ target: isVisible ? 1 : 0, duration: 300 });
744
+ const opacity = useTween({ to: isVisible ? 1 : 0, duration: 300 });
745
745
  ```
746
746
 
747
747
  Use `useTween` for single values where the render is cheap (counters, progress bars, opacity). Use `useLoop` when animating many elements or doing canvas work, since per-frame `setState` doesn't scale.
748
748
 
749
- Reduced motion default: `'complete'` (jumps to target instantly). The value still reaches its destination; it skips the animation.
749
+ Reduced motion default: `'complete'` (jumps to the destination instantly). The value still reaches its destination; it skips the animation.
750
750
 
751
751
  ### usePresence
752
752
 
@@ -1195,7 +1195,7 @@ The rAF loop never triggers a React re-render. All per-frame state lives in refs
1195
1195
 
1196
1196
  ### Frame-locked shared clock
1197
1197
 
1198
- All tickers share one `requestAnimationFrame` loop with a single `performance.now()` read per frame, keeping multiple animations on the same page in visual sync.
1198
+ All tickers share one `requestAnimationFrame` loop and receive the same browser-supplied timestamp each frame, keeping multiple animations on the same page in visual sync.
1199
1199
 
1200
1200
  ### Delta clamping
1201
1201
 
@@ -1209,13 +1209,13 @@ Every error includes a machine-readable `code` and an actionable message.
1209
1209
  import { PhaseError, isPhaseError } from 'phase';
1210
1210
  ```
1211
1211
 
1212
- | Code | Trigger |
1213
- | ------------------ | ---------------------------------------------------- |
1214
- | `server_context` | Calling a browser-only primitive during SSR |
1215
- | `no_element` | Passing a null or undefined `element` to a primitive |
1216
- | `invalid_duration` | `useTween` duration is zero, negative, or NaN |
1217
- | `ticker_stopped` | Calling `start`/`resume` on a stopped ticker |
1218
- | `missing_context` | `<Swap.State>` used outside `<Swap>` |
1212
+ | Code | Trigger |
1213
+ | ------------------ | --------------------------------------------------- |
1214
+ | `server_context` | Calling a browser-only primitive during SSR |
1215
+ | `no_target` | Passing a null or undefined `target` to a primitive |
1216
+ | `invalid_duration` | `useTween` duration is zero, negative, or NaN |
1217
+ | `ticker_stopped` | Calling `start`/`resume` on a stopped ticker |
1218
+ | `missing_context` | `<Swap.State>` used outside `<Swap>` |
1219
1219
 
1220
1220
  ## Relationship to View Transitions
1221
1221
 
@@ -1232,35 +1232,35 @@ Minimal footprint is a core promise (see [Why phase](#why-phase)). Every export
1232
1232
  | Export | Size (min+brotli) |
1233
1233
  | ------------------------- | ----------------: |
1234
1234
  | **Core** | |
1235
- | `createTicker` | 834 B |
1236
- | `createSight` | 967 B |
1235
+ | `createTicker` | 847 B |
1236
+ | `createSight` | 970 B |
1237
1237
  | `createLifecycle` | 1.48 kB |
1238
- | `createLoop` | 2.59 kB |
1239
- | `createScrollProgress` | 866 B |
1240
- | `createRenderState` | 495 B |
1238
+ | `createLoop` | 2.6 kB |
1239
+ | `createScrollProgress` | 865 B |
1240
+ | `createRenderState` | 490 B |
1241
1241
  | `createDevicePixelRatio` | 544 B |
1242
- | `createMutation` | 1.18 kB |
1243
- | `createPointer` | 1.27 kB |
1244
- | `createScroll` | 1.45 kB |
1245
- | `createThrottle` | 657 B |
1246
- | `createDebounce` | 559 B |
1242
+ | `createMutation` | 1.17 kB |
1243
+ | `createPointer` | 1.26 kB |
1244
+ | `createScroll` | 1.46 kB |
1245
+ | `createThrottle` | 659 B |
1246
+ | `createDebounce` | 557 B |
1247
1247
  | `whenIdle` | 409 B |
1248
1248
  | `prefersReducedMotion` | 101 B |
1249
1249
  | **Ease** | |
1250
1250
  | `ease (all)` | 210 B |
1251
1251
  | **React** | |
1252
- | `useLoop` | 2.82 kB |
1252
+ | `useLoop` | 2.85 kB |
1253
1253
  | `useLifecycle` | 1.68 kB |
1254
1254
  | `useSight` | 1.18 kB |
1255
- | `useCanvas` | 3.44 kB |
1256
- | `useMutation` | 1.36 kB |
1257
- | `usePointer` | 1.47 kB |
1255
+ | `useCanvas` | 3.47 kB |
1256
+ | `useMutation` | 1.37 kB |
1257
+ | `usePointer` | 1.48 kB |
1258
1258
  | `useScroll` | 1.72 kB |
1259
1259
  | `useThrottledCallback` | 797 B |
1260
- | `useDebouncedCallback` | 688 B |
1260
+ | `useDebouncedCallback` | 687 B |
1261
1261
  | `useTween` | 655 B |
1262
1262
  | `usePresence` | 591 B |
1263
- | `useScrollProgress` | 997 B |
1263
+ | `useScrollProgress` | 999 B |
1264
1264
  | `useSize` | 378 B |
1265
1265
  | `useContainerQuery` | 384 B |
1266
1266
  | `useMediaQuery` | 246 B |
@@ -1269,13 +1269,13 @@ Minimal footprint is a core promise (see [Why phase](#why-phase)). Every export
1269
1269
  | `useSyncedRef` | 22 B |
1270
1270
  | `useStableCallback` | 39 B |
1271
1271
  | `Presence` | 741 B |
1272
- | `WhenVisible` | 1.44 kB |
1272
+ | `WhenVisible` | 1.43 kB |
1273
1273
  | `WhenIdle` | 593 B |
1274
1274
  | `Defer` | 86 B |
1275
1275
  | `useIdle` | 435 B |
1276
- | `useWhenIdle` | 445 B |
1277
- | `useRenderState` | 527 B |
1278
- | `Swap` | 1.13 kB |
1276
+ | `useWhenIdle` | 446 B |
1277
+ | `useRenderState` | 521 B |
1278
+ | `Swap` | 1.12 kB |
1279
1279
 
1280
1280
  <!-- SIZE-TABLE:END -->
1281
1281
 
@@ -49,10 +49,10 @@ function serverContextError(fn) {
49
49
  fix: "Move into a useEffect or client-only module."
50
50
  });
51
51
  }
52
- function noElementError(fn) {
53
- throw new PhaseError(`${fn}() requires a DOM element.`, {
54
- code: "no_element",
55
- reason: "The element was null or undefined.",
52
+ function noTargetError(fn) {
53
+ throw new PhaseError(`${fn}() requires a target.`, {
54
+ code: "no_target",
55
+ reason: "The target was null or undefined.",
56
56
  fix: "Pass a mounted Element, or use the React hook which manages the ref."
57
57
  });
58
58
  }
@@ -83,28 +83,31 @@ function missingContextError(child, parent) {
83
83
  const MAX_DELTA_MS = 40;
84
84
  /** Default first-frame delta when no previous tick exists. */
85
85
  const DEFAULT_FIRST_DELTA_MS = 16.67;
86
+ let sharedRafId = null;
87
+ let sharedFrame = 0;
86
88
  let sharedTime = 0;
87
- let sharedRafId = 0;
88
89
  const sharedSubscribers = /* @__PURE__ */ new Set();
89
- function sharedTick() {
90
- sharedTime = performance.now();
91
- for (const callback of sharedSubscribers) callback();
92
- if (sharedSubscribers.size > 0) sharedRafId = requestAnimationFrame(sharedTick);
90
+ function dispatchSharedSubscription(subscription) {
91
+ if (subscription.joinedFrame < sharedFrame) subscription.callback(sharedTime);
93
92
  }
94
- function joinSharedClock(callback) {
93
+ function sharedTick(time) {
94
+ sharedTime = time;
95
+ sharedFrame++;
96
+ sharedRafId = requestAnimationFrame(sharedTick);
97
+ sharedSubscribers.forEach(dispatchSharedSubscription);
98
+ }
99
+ function joinSharedClock(subscription) {
95
100
  const wasEmpty = sharedSubscribers.size === 0;
96
- sharedSubscribers.add(callback);
97
- if (wasEmpty) {
98
- sharedTime = performance.now();
99
- sharedRafId = requestAnimationFrame(sharedTick);
101
+ subscription.joinedFrame = sharedFrame;
102
+ sharedSubscribers.add(subscription);
103
+ if (wasEmpty) sharedRafId = requestAnimationFrame(sharedTick);
104
+ }
105
+ function leaveSharedClock(subscription) {
106
+ sharedSubscribers.delete(subscription);
107
+ if (sharedSubscribers.size === 0 && sharedRafId !== null) {
108
+ cancelAnimationFrame(sharedRafId);
109
+ sharedRafId = null;
100
110
  }
101
- return () => {
102
- sharedSubscribers.delete(callback);
103
- if (sharedSubscribers.size === 0 && sharedRafId) {
104
- cancelAnimationFrame(sharedRafId);
105
- sharedRafId = 0;
106
- }
107
- };
108
111
  }
109
112
  function resetFrameState(state) {
110
113
  state.time = 0;
@@ -125,7 +128,6 @@ function createTicker(options) {
125
128
  const minFrameTime = fps ? 1e3 / fps : 0;
126
129
  let _phase = "idle";
127
130
  let _reason = "initial";
128
- let leaveSharedClock = null;
129
131
  let lastTickTime = 0;
130
132
  let pauseStartTime = 0;
131
133
  let totalPausedTime = 0;
@@ -136,8 +138,7 @@ function createTicker(options) {
136
138
  elapsed: 0,
137
139
  frame: 0
138
140
  };
139
- function tick() {
140
- const now = sharedTime;
141
+ function tick(now) {
141
142
  if (minFrameTime > 0 && now - lastTickTime < minFrameTime) return;
142
143
  const rawDelta = lastTickTime === 0 ? DEFAULT_FIRST_DELTA_MS : now - lastTickTime;
143
144
  lastTickTime = now;
@@ -147,6 +148,10 @@ function createTicker(options) {
147
148
  frame.frame++;
148
149
  onTick(frame);
149
150
  }
151
+ const subscription = {
152
+ callback: tick,
153
+ joinedFrame: 0
154
+ };
150
155
  function start() {
151
156
  if (_phase === "running") return;
152
157
  if (_phase === "stopped") tickerStoppedError();
@@ -160,15 +165,14 @@ function createTicker(options) {
160
165
  lastTickTime = 0;
161
166
  totalPausedTime = 0;
162
167
  resetFrameState(frame);
163
- leaveSharedClock = joinSharedClock(tick);
168
+ joinSharedClock(subscription);
164
169
  }
165
170
  function pause() {
166
171
  if (_phase !== "running") return;
167
172
  _phase = "paused";
168
173
  _reason = "manual";
169
174
  pauseStartTime = performance.now();
170
- leaveSharedClock?.();
171
- leaveSharedClock = null;
175
+ leaveSharedClock(subscription);
172
176
  }
173
177
  function resume() {
174
178
  if (_phase === "stopped") tickerStoppedError();
@@ -177,15 +181,14 @@ function createTicker(options) {
177
181
  lastTickTime = 0;
178
182
  _phase = "running";
179
183
  _reason = "resumed";
180
- leaveSharedClock = joinSharedClock(tick);
184
+ joinSharedClock(subscription);
181
185
  }
182
186
  function stop() {
183
187
  if (_phase === "stopped") return;
184
188
  _phase = "stopped";
185
189
  _reason = _reason === "initial" ? "disposed" : "manual";
186
190
  unlinkAbort?.();
187
- leaveSharedClock?.();
188
- leaveSharedClock = null;
191
+ leaveSharedClock(subscription);
189
192
  }
190
193
  let unlinkAbort;
191
194
  unlinkAbort = linkAbortSignal(signal, stop);
@@ -277,7 +280,7 @@ const createPoolEntry$1 = (options) => {
277
280
  *
278
281
  * @example
279
282
  * const sight = createSight({
280
- * element: el,
283
+ * target: el,
281
284
  * onPhaseChange: (phase) => phase === 'visible' ? loop.start() : loop.pause(),
282
285
  * });
283
286
  * // cleanup:
@@ -288,8 +291,8 @@ const createPoolEntry$1 = (options) => {
288
291
  */
289
292
  function createSight(options) {
290
293
  if (typeof document === "undefined") serverContextError("createSight");
291
- const { element, intersectionOptions, onPhaseChange, signal } = options;
292
- if (!element) noElementError("createSight");
294
+ const { target, intersectionOptions, onPhaseChange, signal } = options;
295
+ if (!target) noTargetError("createSight");
293
296
  let _phase = "unknown";
294
297
  let _reason = "initial";
295
298
  let stopped = false;
@@ -320,7 +323,7 @@ function createSight(options) {
320
323
  document.addEventListener("visibilitychange", onVisibilityChange);
321
324
  window.addEventListener("pageshow", onPageShow);
322
325
  const unobserveIO = observeIntersection({
323
- element,
326
+ element: target,
324
327
  onIntersect: onIntersection,
325
328
  ...intersectionOptions
326
329
  });
@@ -413,7 +416,7 @@ const REDUCED_MOTION_QUERY$1 = "(prefers-reduced-motion: reduce)";
413
416
  *
414
417
  * @example
415
418
  * const lifecycle = createLifecycle({
416
- * element: canvas,
419
+ * target: canvas,
417
420
  * onPhaseChange: (phase) => {
418
421
  * if (phase === 'active') renderer.start();
419
422
  * else renderer.stop();
@@ -424,8 +427,8 @@ const REDUCED_MOTION_QUERY$1 = "(prefers-reduced-motion: reduce)";
424
427
  */
425
428
  function createLifecycle(options) {
426
429
  if (typeof document === "undefined") serverContextError("createLifecycle");
427
- const { element, reducedMotion = "pause", intersectionOptions, start: startMode = "auto", onPhaseChange, signal } = options;
428
- if (!element) noElementError("createLifecycle");
430
+ const { target, reducedMotion = "pause", intersectionOptions, start: startMode = "auto", onPhaseChange, signal } = options;
431
+ if (!target) noTargetError("createLifecycle");
429
432
  let _phase = "idle";
430
433
  let _reason = "initial";
431
434
  let sightVisible = false;
@@ -465,7 +468,7 @@ function createLifecycle(options) {
465
468
  reconcile();
466
469
  }
467
470
  const sight = createSight({
468
- element,
471
+ target,
469
472
  intersectionOptions,
470
473
  onPhaseChange: onSightChange
471
474
  });
@@ -542,7 +545,7 @@ const RECOVERY_RETRY_MS = 2e3;
542
545
  *
543
546
  * @example
544
547
  * const loop = createLoop({
545
- * element: el,
548
+ * target: el,
546
549
  * onTick: (frame) => draw(ctx, frame),
547
550
  * });
548
551
  * // cleanup:
@@ -550,8 +553,8 @@ const RECOVERY_RETRY_MS = 2e3;
550
553
  */
551
554
  function createLoop(options) {
552
555
  if (typeof requestAnimationFrame === "undefined") serverContextError("createLoop");
553
- const { element, onTick, fps: baseFps, reducedMotion = "pause", degraded = "throttle", degradedFps: configuredDegradedFps, intersectionOptions, start: startMode = "auto", onPhaseChange, signal } = options;
554
- if (!element) noElementError("createLoop");
556
+ const { target, onTick, fps: baseFps, reducedMotion = "pause", degraded = "throttle", degradedFps: configuredDegradedFps, intersectionOptions, start: startMode = "auto", onPhaseChange, signal } = options;
557
+ if (!target) noTargetError("createLoop");
555
558
  const degradedFps = degraded === "throttle" ? configuredDegradedFps : void 0;
556
559
  let _phase = "idle";
557
560
  let _reason = "initial";
@@ -672,7 +675,7 @@ function createLoop(options) {
672
675
  reconcileQuality();
673
676
  }
674
677
  const lifecycle = createLifecycle({
675
- element,
678
+ target,
676
679
  reducedMotion: reducedMotion === "pause" ? "pause" : "ignore",
677
680
  intersectionOptions,
678
681
  start: "manual",
@@ -742,7 +745,7 @@ function buildThresholds(steps) {
742
745
  *
743
746
  * @example
744
747
  * const progress = createScrollProgress({
745
- * element: el,
748
+ * target: el,
746
749
  * onProgress: (ratio) => {
747
750
  * el.style.opacity = String(ratio);
748
751
  * },
@@ -752,8 +755,8 @@ function buildThresholds(steps) {
752
755
  */
753
756
  function createScrollProgress(options) {
754
757
  if (typeof IntersectionObserver === "undefined") serverContextError("createScrollProgress");
755
- const { element, onProgress, steps = DEFAULT_STEPS, root, rootMargin, signal } = options;
756
- if (!element) noElementError("createScrollProgress");
758
+ const { target: element, onProgress, steps = DEFAULT_STEPS, root, rootMargin, signal } = options;
759
+ if (!element) noTargetError("createScrollProgress");
757
760
  let _ratio = 0;
758
761
  let stopped = false;
759
762
  const unobserve = observeIntersection({
@@ -799,7 +802,7 @@ function createScrollProgress(options) {
799
802
  *
800
803
  * @example
801
804
  * const render = createRenderState({
802
- * element: el,
805
+ * target: el,
803
806
  * onPhaseChange: (phase) => phase === 'skipped' ? clock.pause() : clock.resume(),
804
807
  * });
805
808
  * // cleanup:
@@ -814,8 +817,8 @@ function createScrollProgress(options) {
814
817
  */
815
818
  function createRenderState(options) {
816
819
  if (typeof document === "undefined") serverContextError("createRenderState");
817
- const { element, onPhaseChange, signal } = options;
818
- if (!element) noElementError("createRenderState");
820
+ const { target: element, onPhaseChange, signal } = options;
821
+ if (!element) noTargetError("createRenderState");
819
822
  let _phase = "rendered";
820
823
  let stopped = false;
821
824
  function onStateChange(event) {
@@ -944,8 +947,8 @@ function prefersReducedMotion() {
944
947
  /** Lifecycle-aware MutationObserver with rAF-coalesced callbacks. */
945
948
  function createMutation(options) {
946
949
  if (typeof document === "undefined") serverContextError("createMutation");
947
- const { element, mutation: mutationInit, onMutations, onPhaseChange, visibility = "pause", intersectionOptions, signal } = options;
948
- if (!element) noElementError("createMutation");
950
+ const { target: element, mutation: mutationInit, onMutations, onPhaseChange, visibility = "pause", intersectionOptions, signal } = options;
951
+ if (!element) noTargetError("createMutation");
949
952
  warnReflowStorm(mutationInit);
950
953
  let _phase = "paused";
951
954
  let _reason = "initial";
@@ -1062,8 +1065,8 @@ function warnReflowStorm(opts) {
1062
1065
  /** Lifecycle-aware pointer tracker with rAF-batched `getBoundingClientRect`. */
1063
1066
  function createPointer(options) {
1064
1067
  if (typeof document === "undefined") serverContextError("createPointer");
1065
- const { element, onPointer, onPhaseChange, visibility = "pause", intersectionOptions, signal } = options;
1066
- if (!element) noElementError("createPointer");
1068
+ const { target: element, onPointer, onPhaseChange, visibility = "pause", intersectionOptions, signal } = options;
1069
+ if (!element) noTargetError("createPointer");
1067
1070
  let _phase = "idle";
1068
1071
  let _reason = "initial";
1069
1072
  let stopped = false;
@@ -1251,8 +1254,8 @@ function getObserver() {
1251
1254
  */
1252
1255
  function createScroll(options) {
1253
1256
  if (typeof document === "undefined") serverContextError("createScroll");
1254
- const { element, onScroll, onPhaseChange, visibility = "pause", intersectionOptions, signal } = options;
1255
- if (!element) noElementError("createScroll");
1257
+ const { target, onScroll, onPhaseChange, visibility = "pause", intersectionOptions, signal } = options;
1258
+ if (!target) noTargetError("createScroll");
1256
1259
  let _phase = "paused";
1257
1260
  let _reason = "initial";
1258
1261
  let stopped = false;
@@ -1278,8 +1281,8 @@ function createScroll(options) {
1278
1281
  }
1279
1282
  function computePosition() {
1280
1283
  const { maxX, maxY } = _state;
1281
- const x = element.scrollLeft;
1282
- const y = element.scrollTop;
1284
+ const x = target.scrollLeft;
1285
+ const y = target.scrollTop;
1283
1286
  _state.x = x < 0 ? 0 : x > maxX ? maxX : x;
1284
1287
  _state.y = y < 0 ? 0 : y > maxY ? maxY : y;
1285
1288
  _state.progressX = maxX > 0 ? _state.x / maxX : 0;
@@ -1287,10 +1290,10 @@ function createScroll(options) {
1287
1290
  }
1288
1291
  function measure() {
1289
1292
  if (stopped || !listenersAttached) return;
1290
- const scrollWidth = element.scrollWidth;
1291
- const clientWidth = element.clientWidth;
1292
- const scrollHeight = element.scrollHeight;
1293
- const clientHeight = element.clientHeight;
1293
+ const scrollWidth = target.scrollWidth;
1294
+ const clientWidth = target.clientWidth;
1295
+ const scrollHeight = target.scrollHeight;
1296
+ const clientHeight = target.clientHeight;
1294
1297
  const maxX = scrollWidth - clientWidth;
1295
1298
  const maxY = scrollHeight - clientHeight;
1296
1299
  _state.maxX = maxX > 0 ? maxX : 0;
@@ -1330,14 +1333,14 @@ function createScroll(options) {
1330
1333
  function attachListeners() {
1331
1334
  if (listenersAttached) return;
1332
1335
  listenersAttached = true;
1333
- element.addEventListener("scroll", onScrollEvent, { passive: true });
1334
- unobserveRO = observeResize(element, onROResize);
1336
+ target.addEventListener("scroll", onScrollEvent, { passive: true });
1337
+ unobserveRO = observeResize(target, onROResize);
1335
1338
  measure();
1336
1339
  }
1337
1340
  function detachListeners() {
1338
1341
  if (!listenersAttached) return;
1339
1342
  listenersAttached = false;
1340
- element.removeEventListener("scroll", onScrollEvent);
1343
+ target.removeEventListener("scroll", onScrollEvent);
1341
1344
  unobserveRO?.();
1342
1345
  unobserveRO = void 0;
1343
1346
  cancelFlush();
@@ -1369,7 +1372,7 @@ function createScroll(options) {
1369
1372
  document.addEventListener("visibilitychange", onVisChange);
1370
1373
  window.addEventListener("pageshow", onPageShow);
1371
1374
  const unobserveIO = observeIntersection({
1372
- element,
1375
+ element: target,
1373
1376
  onIntersect: (entry) => {
1374
1377
  elementInView = entry.isIntersecting;
1375
1378
  recompute();
@@ -1615,4 +1618,4 @@ function createDebounce(options) {
1615
1618
  //#endregion
1616
1619
  export { missingContextError as C, isPhaseError as S, linkAbortSignal as T, subscribeMediaQuery as _, createPointer as a, PhaseError as b, prefersReducedMotion as c, subscribeDpr as d, createRenderState as f, readMediaQuery as g, createLifecycle as h, observeResize as i, whenIdle as l, createLoop as m, createThrottle as n, createMutation as o, createScrollProgress as p, createScroll as r, REDUCED_MOTION_QUERY as s, createDebounce as t, readDpr as u, createSight as v, serverContextError as w, invalidDurationError as x, createTicker as y };
1617
1620
 
1618
- //# sourceMappingURL=debounce-BD9K4TW4.js.map
1621
+ //# sourceMappingURL=debounce-BX3NrBak.js.map