@prtcl/plonk 1.0.4 → 1.0.6

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
@@ -1,5 +1,39 @@
1
- # plonk
1
+ # @prtcl/plonk
2
2
 
3
- Tiny library that provides timers, envelopes, and random generators.
3
+ Tiny library providing timers, envelopes, and random generators for creative coding, animation loops, and synthesis engines. Inspired by time-based functions from Max/MSP and SuperCollider.
4
4
 
5
- Visit [GitHub](https://github.com/prtcl/plonk) for docs and info.
5
+ ## Installation
6
+
7
+ ```
8
+ npm i @prtcl/plonk
9
+ ```
10
+
11
+ ## What's included
12
+
13
+ - **Timers** — `Metro`, `Frames` — high-resolution recursive loops with runtime metrics
14
+ - **Generators** — `Drunk`, `Rand`, `Env`, `Sine`, `Scale` — random walks, envelopes, oscillators, and range mapping
15
+ - **Utilities** — `now`, `ms`, `clamp`, `expo` — timing and math helpers
16
+
17
+ Generators follow an iterator-inspired `value()` / `next()` pattern — they're stateful objects you pull from on your own schedule (a timer callback, a Web Audio worklet, a game loop, etc).
18
+
19
+ ## Quick example
20
+
21
+ ```typescript
22
+ import { Metro, Drunk, Rand } from '@prtcl/plonk';
23
+
24
+ const d = new Drunk({ min: -1, max: 1 });
25
+ const r = new Rand({ min: 50, max: 150 });
26
+
27
+ const metro = new Metro(() => {
28
+ console.log(d.next());
29
+ metro.setTime(r.next());
30
+ }, { time: 100 });
31
+
32
+ metro.run();
33
+ ```
34
+
35
+ ## Documentation
36
+
37
+ See the full [API Reference](https://github.com/prtcl/plonk/blob/main/docs/API.md).
38
+
39
+ Also available: [`@prtcl/plonk-hooks`](https://www.npmjs.com/package/@prtcl/plonk-hooks) for React integration.
package/dist/index.cjs CHANGED
@@ -37,7 +37,6 @@ __export(index_exports, {
37
37
  TimeFormat: () => TimeFormat,
38
38
  clamp: () => clamp,
39
39
  expo: () => expo,
40
- flip: () => flip,
41
40
  ms: () => ms,
42
41
  now: () => now
43
42
  });
@@ -182,34 +181,29 @@ var Drunk = class {
182
181
  };
183
182
 
184
183
  // src/utils/now.ts
185
- var internal;
186
- if (typeof performance !== "undefined" && "now" in performance) {
187
- internal = () => {
188
- return performance.now();
189
- };
190
- } else if (typeof process === "object" && process.toString() === "[object process]") {
191
- const timestamp = () => {
192
- const hr = process.hrtime();
193
- return hr[0] * 1e9 + hr[1];
194
- };
195
- const initial = timestamp();
196
- internal = () => {
197
- return (timestamp() - initial) / 1e6;
198
- };
199
- } else {
200
- const initial = Date.now();
201
- internal = () => {
202
- return Date.now() - initial;
203
- };
204
- }
184
+ var innerNow = (() => {
185
+ if (typeof performance !== "undefined" && "now" in performance) {
186
+ return () => performance.now();
187
+ }
188
+ if (typeof process === "object" && process.toString() === "[object process]") {
189
+ const ts = () => {
190
+ const hr = process.hrtime();
191
+ return hr[0] * 1e9 + hr[1];
192
+ };
193
+ const initialNow2 = ts();
194
+ return () => (ts() - initialNow2) / 1e6;
195
+ }
196
+ const initialNow = Date.now();
197
+ return () => Date.now() - initialNow;
198
+ })();
205
199
  function now() {
206
- return internal();
200
+ return innerNow();
207
201
  }
208
202
 
209
203
  // src/math/Scale.ts
210
- var parseOptions3 = (opts) => {
211
- const { from, to } = {
212
- ...opts,
204
+ var computeRatio = (from, to) => (to.max - to.min) / (from.max - from.min);
205
+ var parseInitialState = (opts) => {
206
+ const initialRange = {
213
207
  from: {
214
208
  min: 0,
215
209
  max: 1,
@@ -222,22 +216,25 @@ var parseOptions3 = (opts) => {
222
216
  }
223
217
  };
224
218
  return {
225
- from,
226
- to
219
+ ...initialRange,
220
+ ratio: computeRatio(initialRange.from, initialRange.to),
221
+ value: initialRange.to.min
227
222
  };
228
223
  };
229
224
  var updateStateFromOptions = (opts, prevState) => {
230
225
  const { from, to } = opts;
226
+ const updatedFrom = {
227
+ ...prevState.from,
228
+ ...from
229
+ };
231
230
  const updatedTo = {
232
231
  ...prevState.to,
233
232
  ...to
234
233
  };
235
234
  return {
236
235
  ...prevState,
237
- from: {
238
- ...prevState.from,
239
- ...from
240
- },
236
+ from: updatedFrom,
237
+ ratio: computeRatio(updatedFrom, updatedTo),
241
238
  to: updatedTo,
242
239
  value: clamp(prevState.value, updatedTo.min, updatedTo.max)
243
240
  };
@@ -245,8 +242,7 @@ var updateStateFromOptions = (opts, prevState) => {
245
242
  var Scale = class _Scale {
246
243
  constructor(opts) {
247
244
  __publicField(this, "state");
248
- const { from, to } = parseOptions3(opts);
249
- this.state = { from, to, value: to.min };
245
+ this.state = parseInitialState(opts);
250
246
  }
251
247
  static scale(n, opts) {
252
248
  return new _Scale(opts).scale(n);
@@ -255,22 +251,21 @@ var Scale = class _Scale {
255
251
  this.state = updateStateFromOptions(opts, this.state);
256
252
  }
257
253
  reset(opts) {
258
- const { from, to } = parseOptions3(opts);
259
- this.state = { from, to, value: to.min };
254
+ this.state = parseInitialState(opts);
260
255
  }
261
256
  value() {
262
257
  return this.state.value;
263
258
  }
264
259
  scale(n) {
265
- const { from, to } = this.state;
266
- const updates = to.min + (clamp(n, from.min, from.max) - from.min) * (to.max - to.min) / (from.max - from.min);
260
+ const { from, to, ratio } = this.state;
261
+ const updates = to.min + (clamp(n, from.min, from.max) - from.min) * ratio;
267
262
  this.state.value = updates;
268
263
  return updates;
269
264
  }
270
265
  };
271
266
 
272
267
  // src/math/Env.ts
273
- var parseOptions4 = (opts) => {
268
+ var parseOptions3 = (opts) => {
274
269
  return {
275
270
  duration: 0,
276
271
  from: 0,
@@ -309,7 +304,7 @@ var Env = class {
309
304
  constructor(opts) {
310
305
  __publicField(this, "state");
311
306
  __publicField(this, "_interpolator");
312
- const { from, to, duration } = parseOptions4(opts);
307
+ const { from, to, duration } = parseOptions3(opts);
313
308
  this.state = getInitialState({ from, to, duration });
314
309
  this._interpolator = new Scale({
315
310
  from: {
@@ -552,7 +547,7 @@ var processTimerState = (state) => {
552
547
  totalElapsed: totalElapsed + tickInterval
553
548
  };
554
549
  };
555
- var parseOptions5 = (opts) => {
550
+ var parseOptions4 = (opts) => {
556
551
  return {
557
552
  time: SIXTY_FPS,
558
553
  ...opts
@@ -603,7 +598,7 @@ var Metro = class {
603
598
  };
604
599
  tick();
605
600
  });
606
- const { time } = parseOptions5(opts);
601
+ const { time } = parseOptions4(opts);
607
602
  this.state = getInitialState3(time);
608
603
  this._listeners = [callback];
609
604
  }
@@ -617,7 +612,7 @@ var Metro = class {
617
612
 
618
613
  // src/timers/Frames.ts
619
614
  var DEFAULT_FPS = 60;
620
- var parseOptions6 = (opts) => {
615
+ var parseOptions5 = (opts) => {
621
616
  const { fps } = {
622
617
  fps: DEFAULT_FPS,
623
618
  ...opts
@@ -628,7 +623,7 @@ var parseOptions6 = (opts) => {
628
623
  };
629
624
  var Frames = class extends Metro {
630
625
  constructor(callback, opts) {
631
- super(() => callback(this), parseOptions6(opts));
626
+ super(() => callback(this), parseOptions5(opts));
632
627
  __publicField(this, "setFPS", (fps = DEFAULT_FPS) => {
633
628
  this.setTime(ms(fps, "fps" /* FPS */));
634
629
  });
@@ -653,11 +648,6 @@ var Frames = class extends Metro {
653
648
  function expo(n) {
654
649
  return Math.pow(clamp(n, 0, 1), Math.E);
655
650
  }
656
-
657
- // src/utils/flip.ts
658
- function flip(n) {
659
- return n * -1;
660
- }
661
651
  // Annotate the CommonJS export names for ESM import in node:
662
652
  0 && (module.exports = {
663
653
  Drunk,
@@ -675,7 +665,6 @@ function flip(n) {
675
665
  TimeFormat,
676
666
  clamp,
677
667
  expo,
678
- flip,
679
668
  ms,
680
669
  now
681
670
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/utils/clamp.ts","../src/math/Rand.ts","../src/math/Drunk.ts","../src/utils/now.ts","../src/math/Scale.ts","../src/math/Env.ts","../src/math/Sine.ts","../src/constants.ts","../src/utils/ms.ts","../src/timers/Metro.ts","../src/timers/Frames.ts","../src/utils/expo.ts","../src/utils/flip.ts"],"sourcesContent":["export { Drunk, type DrunkOptions, type DrunkState } from './math/Drunk';\nexport { Env, type EnvOptions, type EnvState } from './math/Env';\nexport { Rand, type RandOptions, type RandState } from './math/Rand';\nexport {\n Scale,\n type ScaleOptions,\n type ScaleRange,\n type ScaleState,\n} from './math/Scale';\nexport {\n Sine,\n type SineOptions,\n type SineState,\n SINE_PERIOD,\n} from './math/Sine';\nexport { Frames, type FramesOptions } from './timers/Frames';\nexport { Metro, type MetroOptions, type TimerCallback } from './timers/Metro';\nexport { clamp } from './utils/clamp';\nexport { expo } from './utils/expo';\nexport { flip } from './utils/flip';\nexport { ms, type FPS, TimeFormat } from './utils/ms';\nexport { now } from './utils/now';\nexport * from './constants';\n","export function clamp(n: number): number;\nexport function clamp(n: number, max: number): number;\nexport function clamp(n: number, min: number, max: number): number;\n\n/**\n * Constrains an input value to a min...max range.\n * @param n - The value to constrain.\n * @param min - Lower bound (defaults to 0).\n * @param max - Upper bound (defaults to 1).\n * @returns The clamped value.\n */\nexport function clamp(n: number, min?: number, max?: number) {\n let a = 0;\n let b = 1;\n\n if (typeof min === 'number') {\n if (typeof max === 'number') {\n a = min;\n b = max;\n } else {\n a = 0;\n b = min;\n }\n }\n\n return Math.min(Math.max(n, a), b);\n}\n","import { clamp } from '../utils/clamp';\n\n/** Options for configuring a Rand generator. */\nexport type RandOptions = {\n /** Lower bound of the range. Defaults to 0. */\n min?: number;\n /** Upper bound of the range. Defaults to 1. */\n max?: number;\n};\n\n/** Snapshot of a Rand generator's internal state. */\nexport type RandState = {\n min: number;\n max: number;\n value: number;\n};\n\nexport const parseOptions = (opts?: RandOptions): Required<RandOptions> => {\n return {\n min: 0,\n max: 1,\n ...opts,\n };\n};\n\n/**\n * Random number generator that produces values within a bounded range.\n * @param opts - {@link RandOptions} for configuring the range.\n */\nexport class Rand {\n state: RandState;\n\n static rand(opts?: RandOptions) {\n return new Rand(opts).value();\n }\n\n constructor(opts?: RandOptions) {\n const { min, max } = parseOptions(opts);\n\n this.state = { max, min, value: 0 };\n this.next();\n }\n\n setRange(partialOpts: RandOptions) {\n const { value = 0 } = this.state;\n const { min, max } = {\n ...this.state,\n ...partialOpts,\n };\n\n this.state = {\n ...this.state,\n max,\n min,\n value: clamp(value, min, max),\n };\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const { min, max } = this.state;\n const updates = Math.random() * (max - min) + min;\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { clamp } from '../utils/clamp';\nimport { Rand } from './Rand';\n\nexport const DEFAULT_DRUNK_STEP = 0.1;\n\n/** Options for configuring a Drunk random walk. */\nexport type DrunkOptions = {\n /** Upper bound of the range. Defaults to 1. */\n max?: number;\n /** Lower bound of the range. Defaults to 0. */\n min?: number;\n /** Initial value. If omitted, a random value within the range is used. */\n startsAt?: number;\n /** Maximum step size as a fraction of the range (0-1). Defaults to 0.1. */\n step?: number;\n};\n\n/** Snapshot of a Drunk walk's internal state. */\nexport type DrunkState = {\n initialValue: number;\n max: number;\n min: number;\n step: number;\n value: number;\n};\n\nexport const parseStepSize = (step?: number): number =>\n typeof step !== 'undefined' ? clamp(step, 0, 1) : DEFAULT_DRUNK_STEP;\n\nexport const parseOptions = (opts?: DrunkOptions): Required<DrunkOptions> => {\n const { step, ...restOpts } = opts || {};\n const parsedStepSize = parseStepSize(step);\n\n return {\n max: 1,\n min: 0,\n startsAt: 0,\n step: parsedStepSize,\n ...restOpts,\n };\n};\n\n/**\n * Stochastic random walk generator that produces values within a bounded range.\n * @param opts - {@link DrunkOptions} for configuring the walk.\n */\nexport class Drunk {\n state: DrunkState;\n protected _initialValue: Rand;\n protected _step: Rand;\n\n constructor(opts?: DrunkOptions) {\n const { min, max, step, startsAt } = parseOptions(opts);\n\n this._initialValue = new Rand({ min, max });\n this._step = new Rand({ min: -1, max: 1 });\n\n const initialValue =\n typeof opts?.startsAt !== 'undefined'\n ? startsAt\n : this._initialValue.value();\n\n this.state = {\n initialValue,\n max,\n min,\n step,\n value: initialValue,\n };\n }\n\n setRange(partialOpts?: Pick<DrunkOptions, 'min' | 'max'>) {\n const { max, min } = {\n min: this.state.min,\n max: this.state.max,\n ...partialOpts,\n };\n\n this._initialValue.setRange({ min, max });\n this.state = {\n ...this.state,\n ...(min !== this.state.min || max !== this.state.max\n ? {\n initialValue: clamp(this._initialValue.value(), min, max),\n max,\n min,\n value: clamp(this.state.value, min, max),\n }\n : {\n max,\n min,\n }),\n };\n }\n\n setStepSize(partialOpts?: Pick<DrunkOptions, 'step'>) {\n const step = parseStepSize(partialOpts?.step);\n\n this.state = {\n ...this.state,\n step,\n };\n }\n\n reset(opts?: DrunkOptions) {\n const { min, max, startsAt, step } = parseOptions(opts);\n\n this.setRange({ min, max });\n this.setStepSize({ step });\n\n const initialValue =\n typeof opts?.startsAt !== 'undefined'\n ? startsAt\n : this._initialValue.next();\n\n this.state = {\n ...this.state,\n initialValue,\n value: initialValue,\n };\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const { min, max, step, value } = this.state;\n const updates = clamp(value + max * this._step.next() * step, min, max);\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","let internal: () => number;\n\nif (typeof performance !== 'undefined' && 'now' in performance) {\n internal = () => {\n return performance.now();\n };\n} else if (\n typeof process === 'object' &&\n process.toString() === '[object process]'\n) {\n const timestamp = () => {\n const hr = process.hrtime();\n return hr[0] * 1e9 + hr[1];\n };\n const initial = timestamp();\n\n internal = () => {\n return (timestamp() - initial) / 1e6;\n };\n} else {\n const initial = Date.now();\n\n internal = () => {\n return Date.now() - initial;\n };\n}\n\n/**\n * Cross-environment high-resolution timestamp (performance.now polyfill).\n * @returns Elapsed milliseconds since initialization.\n */\nexport function now() {\n return internal();\n}\n","import { clamp } from '../utils/clamp';\n\n/** A numeric range with min and max bounds. */\nexport type ScaleRange = {\n min?: number;\n max: number;\n};\n\n/** Options for configuring a Scale mapper. */\nexport type ScaleOptions = {\n /** Input range. Defaults to { min: 0, max: 1 }. */\n from?: ScaleRange;\n /** Output range. Defaults to { min: 0, max: 1 }. */\n to?: ScaleRange;\n};\n\n/** Snapshot of a Scale mapper's internal state. */\nexport type ScaleState = {\n from: Required<ScaleRange>;\n to: Required<ScaleRange>;\n value: number;\n};\n\nexport const parseOptions = (\n opts?: ScaleOptions,\n): { from: Required<ScaleRange>; to: Required<ScaleRange> } => {\n const { from, to } = {\n ...opts,\n from: {\n min: 0,\n max: 1,\n ...opts?.from,\n },\n to: {\n min: 0,\n max: 1,\n ...opts?.to,\n },\n };\n\n return {\n from,\n to,\n };\n};\n\nexport const updateStateFromOptions = (\n opts: ScaleOptions,\n prevState: ScaleState,\n): ScaleState => {\n const { from, to } = opts;\n\n const updatedTo = {\n ...prevState.to,\n ...to,\n };\n\n return {\n ...prevState,\n from: {\n ...prevState.from,\n ...from,\n },\n to: updatedTo,\n value: clamp(prevState.value, updatedTo.min, updatedTo.max),\n };\n};\n\n/**\n * Linear map of values from one range to another, supports negative values and inversion.\n * @param opts - {@link ScaleOptions} for configuring input and output ranges.\n */\nexport class Scale {\n state: ScaleState;\n\n static scale(n: number, opts?: ScaleOptions) {\n return new Scale(opts).scale(n);\n }\n\n constructor(opts?: ScaleOptions) {\n const { from, to } = parseOptions(opts);\n this.state = { from, to, value: to.min };\n }\n\n setRanges(opts: ScaleOptions) {\n this.state = updateStateFromOptions(opts, this.state);\n }\n\n reset(opts: ScaleOptions) {\n const { from, to } = parseOptions(opts);\n this.state = { from, to, value: to.min };\n }\n\n value() {\n return this.state.value;\n }\n\n scale(n: number) {\n const { from, to } = this.state;\n const updates =\n to.min +\n ((clamp(n, from.min, from.max) - from.min) * (to.max - to.min)) /\n (from.max - from.min);\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { now } from '../utils/now';\nimport { Scale } from './Scale';\n\n/** Snapshot of an Env's internal state. */\nexport type EnvState = {\n duration: number;\n from: number;\n prev: number;\n to: number;\n totalElapsed: number;\n value: number;\n};\n\n/** Options for configuring an Env envelope. */\nexport type EnvOptions = {\n /** Duration of the envelope in milliseconds. */\n duration: number;\n /** Starting value. Defaults to 0. */\n from?: number;\n /** Ending value. Defaults to 1. */\n to?: number;\n};\n\nexport const parseOptions = (opts?: EnvOptions): Required<EnvOptions> => {\n return {\n duration: 0,\n from: 0,\n to: 1,\n ...opts,\n };\n};\n\nconst getInitialState = ({\n from,\n to,\n duration,\n}: Required<EnvOptions>): EnvState => {\n return {\n duration,\n from,\n prev: now(),\n to,\n totalElapsed: 0,\n value: from,\n };\n};\n\nexport const updateStateFromOptions = (\n opts: EnvOptions | undefined,\n prevState: EnvState,\n): EnvState => {\n const { from, to, duration } = {\n ...prevState,\n ...opts,\n };\n\n return {\n ...prevState,\n duration,\n from,\n to,\n totalElapsed: 0,\n };\n};\n\n/**\n * Linear envelope which interpolates between two values over a duration. Useful for audio envelopes, transitions, and animations.\n * @param opts - {@link EnvOptions} for configuring the envelope.\n */\nexport class Env {\n state: EnvState;\n protected _interpolator: Scale;\n\n constructor(opts: EnvOptions) {\n const { from, to, duration } = parseOptions(opts);\n\n this.state = getInitialState({ from, to, duration });\n this._interpolator = new Scale({\n from: {\n min: 0,\n max: duration,\n },\n to: {\n min: from,\n max: to,\n },\n });\n }\n\n setDuration(duration: number) {\n const { to, totalElapsed } = this.state;\n\n this.state = {\n ...this.state,\n ...(duration <= totalElapsed\n ? {\n duration,\n value: to,\n }\n : { duration }),\n };\n }\n\n reset(opts?: EnvOptions) {\n const updates = updateStateFromOptions(opts, this.state);\n\n this.state = {\n ...updates,\n prev: now(),\n value: updates.from,\n };\n this._interpolator.setRanges({\n from: {\n min: 0,\n max: updates.duration,\n },\n to: {\n min: updates.from,\n max: updates.to,\n },\n });\n }\n\n done() {\n return this.state.duration <= this.state.totalElapsed;\n }\n\n value() {\n const { to, value } = this.state;\n\n if (this.done()) {\n return to;\n }\n\n return value;\n }\n\n next() {\n if (this.done()) {\n return this.value();\n }\n\n const { prev, totalElapsed: prevTotalElapsed } = this.state;\n\n const curr = now();\n const tickInterval = curr - prev;\n const totalElapsed = prevTotalElapsed + tickInterval;\n const updates = this._interpolator.scale(totalElapsed);\n\n this.state.prev = curr;\n this.state.totalElapsed = totalElapsed;\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { clamp } from '../utils/clamp';\nimport { now } from '../utils/now';\nimport { Scale } from './Scale';\n\nexport const SINE_PERIOD = Math.PI * 2 - 0.0001;\n\n/** Options for configuring a Sine oscillator. */\nexport type SineOptions = {\n /** Duration of one full cycle in milliseconds. */\n duration: number;\n};\n\n/** Snapshot of a Sine oscillator's internal state. */\nexport type SineState = {\n cycle: number;\n duration: number;\n prev: number;\n totalElapsed: number;\n value: number;\n};\n\nconst getInitialState = (duration: number): SineState => ({\n cycle: 0,\n duration,\n prev: now(),\n totalElapsed: 0,\n value: 0,\n});\n\n/**\n * Time-based sine wave oscillator that outputs values between -1 and 1.\n * @param opts - {@link SineOptions} for configuring the oscillator.\n */\nexport class Sine {\n state: SineState;\n protected _interpolator: Scale;\n\n constructor(opts: SineOptions) {\n const { duration } = opts;\n\n this._interpolator = new Scale({\n from: {\n min: 0,\n max: duration,\n },\n to: {\n min: 0,\n max: SINE_PERIOD,\n },\n });\n this.state = getInitialState(duration);\n }\n\n setDuration(duration: number) {\n this.state = {\n ...this.state,\n duration,\n };\n }\n\n reset(opts?: SineOptions) {\n const { duration } = {\n ...this.state,\n ...opts,\n };\n\n this.state = getInitialState(duration);\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const {\n cycle,\n duration,\n prev,\n totalElapsed: prevTotalElapsed,\n } = this.state;\n const curr = now();\n const tickInterval = curr - prev;\n const totalElapsed = prevTotalElapsed + tickInterval;\n\n const updates = clamp(\n Math.sin(this._interpolator.scale(totalElapsed)),\n -1,\n 1,\n );\n\n if (cycle >= duration) {\n this.state.cycle = 0;\n } else {\n this.state.cycle = cycle + tickInterval;\n }\n\n this.state.prev = curr;\n this.state.totalElapsed = totalElapsed;\n this.state.value = updates;\n\n return updates;\n }\n}\n","export const SIXTY_FPS = 1000 / 60;\nexport const MS_IN_SECOND = 1000;\nexport const MS_IN_MINUTE = 60 * MS_IN_SECOND;\nexport const MS_IN_HOUR = MS_IN_MINUTE * 60;\n","import { MS_IN_SECOND, MS_IN_MINUTE, MS_IN_HOUR } from '../constants';\n\nexport type FPS = 15 | 30 | 60;\n\nexport enum TimeFormat {\n FPS = 'fps',\n HOURS = 'h',\n HZ = 'hz',\n MILLISECONDS = 'ms',\n MINUTES = 'm',\n SECONDS = 's',\n}\n\nexport type AvailableTimeFormats = `${TimeFormat}`;\n\nexport const FORMAT_IDENTIFIERS: AvailableTimeFormats[] = [\n TimeFormat.FPS,\n TimeFormat.HOURS,\n TimeFormat.HZ,\n TimeFormat.MILLISECONDS,\n TimeFormat.MINUTES,\n TimeFormat.SECONDS,\n]\n // Desc length sort so that `ms` matches prior to `m`\n .sort((a, b) => b.length - a.length);\n\ntype FormatGetter = (val: number) => number;\n\nconst FORMATTERS = new Map<AvailableTimeFormats, FormatGetter>([\n [TimeFormat.FPS, (val: number) => MS_IN_SECOND / val],\n [TimeFormat.HOURS, (val: number) => val * MS_IN_HOUR],\n [TimeFormat.HZ, (val: number) => (1 / val) * MS_IN_SECOND],\n [TimeFormat.MILLISECONDS, (val: number) => val],\n [TimeFormat.MINUTES, (val: number) => val * MS_IN_MINUTE],\n [TimeFormat.SECONDS, (val: number) => val * MS_IN_SECOND],\n]);\n\nconst sanitizeStringVal = (val: string) => val.toLocaleLowerCase().trim();\n\nconst parseStringValAndFormat = (val: string) => {\n for (let i = 0; i < FORMAT_IDENTIFIERS.length; i += 1) {\n const format = FORMAT_IDENTIFIERS[i];\n\n if (val.includes(format)) {\n const value = Number(val.replace(' ', '').replace(format, ''));\n\n return {\n format,\n value,\n };\n }\n }\n\n return {\n format: undefined,\n value: undefined,\n };\n};\n\nexport function ms(val: string | null | undefined): number | undefined;\nexport function ms(\n val: string | number | null | undefined,\n format?: AvailableTimeFormats | TimeFormat,\n): number | undefined;\n\n/**\n * Converts time format strings or numeric values to their corresponding value in milliseconds.\n * @param val - A string like `'60fps'`, `'2s'`, or a numeric value.\n * @param format - Explicit time format when `val` is a number.\n * @returns Milliseconds, or undefined if the input is invalid.\n */\nexport function ms(\n val: string | number | null | undefined,\n format?: AvailableTimeFormats | TimeFormat,\n): number | undefined {\n let parsedValue: number | null | undefined = null;\n let parsedFormat: AvailableTimeFormats = format || TimeFormat.MILLISECONDS;\n\n if (typeof val === 'string') {\n const parsed = parseStringValAndFormat(sanitizeStringVal(val));\n\n if (typeof parsed.value !== 'undefined') {\n parsedValue = parsed.value;\n }\n\n if (parsed.format) {\n parsedFormat = parsed.format;\n }\n } else {\n parsedValue = val;\n }\n\n if (\n typeof parsedValue === 'undefined' ||\n parsedValue === null ||\n Number.isNaN(parsedValue)\n ) {\n return undefined;\n }\n\n const formatter = FORMATTERS.get(parsedFormat);\n\n if (!formatter) {\n return undefined;\n }\n\n return formatter(parsedValue);\n}\n","import { SIXTY_FPS } from '../constants';\nimport { now } from '../utils/now';\n\n/** Snapshot of a running timer's internal state. */\nexport type TimerState = {\n initialTime: number;\n isRunning: boolean;\n iterations: number;\n prev: number;\n tickInterval: number;\n time: number;\n totalElapsed: number;\n};\n\nexport const getInitialState = (initialTime: number): TimerState => {\n return {\n initialTime,\n isRunning: false,\n iterations: -1,\n prev: 0,\n tickInterval: 0,\n time: initialTime,\n totalElapsed: 0,\n };\n};\n\nexport const processTimerState = (state: TimerState): TimerState | null => {\n const { time, prev, totalElapsed, iterations } = state;\n const curr = now();\n\n if (iterations === -1) {\n return {\n ...state,\n prev: curr,\n iterations: 0,\n };\n }\n\n const tickInterval = curr - prev;\n\n if (tickInterval <= time) {\n return null;\n }\n\n return {\n ...state,\n iterations: iterations + 1,\n prev: curr,\n tickInterval,\n totalElapsed: totalElapsed + tickInterval,\n };\n};\n\n/** Options for configuring a Metro timer. */\nexport type MetroOptions = {\n /** Interval between ticks in milliseconds. Defaults to ~16.67ms (60fps). */\n time?: number;\n};\n\nexport const parseOptions = (opts?: MetroOptions): Required<MetroOptions> => {\n return {\n time: SIXTY_FPS,\n ...opts,\n };\n};\n\n/** Callback invoked on each timer tick with the timer instance. */\nexport type TimerCallback<T extends Metro> = (timer: T) => void;\n\n/**\n * High-resolution recursive timer with variable interval, provides runtime metrics via callback for time-based calculations.\n * @param callback - {@link TimerCallback} called on each tick with the timer instance.\n * @param opts - {@link MetroOptions} for configuring the timer interval.\n */\nexport class Metro {\n state: TimerState;\n protected _listeners: TimerCallback<Metro>[];\n protected declare _timerId: ReturnType<typeof setTimeout> | number;\n\n constructor(callback: TimerCallback<Metro>, opts?: MetroOptions) {\n const { time } = parseOptions(opts);\n this.state = getInitialState(time);\n this._listeners = [callback];\n }\n\n protected asyncHandler(callback: () => void) {\n this._timerId = setTimeout(callback, SIXTY_FPS);\n }\n\n protected clearAsyncHandler() {\n clearTimeout(this._timerId);\n }\n\n stop = () => {\n const { totalElapsed } = this.state;\n this.reset();\n this.clearAsyncHandler();\n\n return totalElapsed;\n };\n\n reset = () => {\n const { initialTime } = this.state;\n this.state = getInitialState(initialTime);\n };\n\n setTime = (updatedTime = this.state.time) => {\n const time = Math.max(updatedTime, 0);\n\n this.state = {\n ...this.state,\n time,\n initialTime: time,\n };\n };\n\n run = () => {\n if (this.state.isRunning) {\n this.stop();\n }\n\n this.state = {\n ...this.state,\n isRunning: true,\n prev: now(),\n };\n\n const tick = () => {\n const updates = processTimerState(this.state);\n\n if (updates) {\n this.state = updates;\n this._listeners.forEach((listener) => {\n listener(this);\n });\n }\n\n if (this.state.isRunning) {\n this.asyncHandler(tick);\n }\n };\n\n tick();\n };\n}\n","import { ms, TimeFormat, type FPS } from '../utils/ms';\nimport { Metro, type TimerCallback, type MetroOptions } from './Metro';\n\n/** Options for configuring a Frames timer. */\nexport type FramesOptions = {\n /** Target frames per second (15, 30, or 60). Defaults to 60. */\n fps: FPS;\n};\n\nexport const DEFAULT_FPS: FPS = 60;\n\nexport const parseOptions = (opts?: FramesOptions): MetroOptions => {\n const { fps } = {\n fps: DEFAULT_FPS,\n ...opts,\n };\n\n return {\n time: ms(fps, TimeFormat.FPS),\n };\n};\n\n/**\n * Animation-loop timer that uses requestAnimationFrame when available.\n * @param callback - {@link TimerCallback} called on each frame tick.\n * @param opts - {@link FramesOptions} for configuring the target frame rate.\n */\nexport class Frames extends Metro {\n protected declare _timerId: ReturnType<typeof requestAnimationFrame>;\n\n constructor(callback: TimerCallback<Frames>, opts?: FramesOptions) {\n super(() => callback(this), parseOptions(opts));\n }\n\n protected asyncHandler(callback: () => void) {\n if (typeof window === 'undefined' || !('requestAnimationFrame' in window)) {\n super.asyncHandler(callback);\n } else {\n this._timerId = requestAnimationFrame(callback);\n }\n }\n\n protected clearAsyncHandler() {\n if (typeof window === 'undefined' || !('cancelAnimationFrame' in window)) {\n super.clearAsyncHandler();\n } else {\n cancelAnimationFrame(this._timerId);\n }\n }\n\n setFPS = (fps = DEFAULT_FPS) => {\n this.setTime(ms(fps, TimeFormat.FPS));\n };\n}\n","import { clamp } from './clamp';\n\n/**\n * Scales 0...1 by Euler's number to produce a natural feeling curve.\n * @param n - Input value (clamped to 0-1).\n * @returns The exponentially scaled value.\n */\nexport function expo(n: number): number {\n return Math.pow(clamp(n, 0, 1), Math.E);\n}\n","/**\n * Flips the sign of a number.\n * @param n - The input value.\n * @returns The negated value.\n */\nexport function flip(n: number): number {\n return n * -1;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACWO,SAAS,MAAM,GAAW,KAAc,KAAc;AAC3D,MAAI,IAAI;AACR,MAAI,IAAI;AAER,MAAI,OAAO,QAAQ,UAAU;AAC3B,QAAI,OAAO,QAAQ,UAAU;AAC3B,UAAI;AACJ,UAAI;AAAA,IACN,OAAO;AACL,UAAI;AACJ,UAAI;AAAA,IACN;AAAA,EACF;AAEA,SAAO,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC;AACnC;;;ACTO,IAAM,eAAe,CAAC,SAA8C;AACzE,SAAO;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,GAAG;AAAA,EACL;AACF;AAMO,IAAM,OAAN,MAAM,MAAK;AAAA,EAOhB,YAAY,MAAoB;AANhC;AAOE,UAAM,EAAE,KAAK,IAAI,IAAI,aAAa,IAAI;AAEtC,SAAK,QAAQ,EAAE,KAAK,KAAK,OAAO,EAAE;AAClC,SAAK,KAAK;AAAA,EACZ;AAAA,EATA,OAAO,KAAK,MAAoB;AAC9B,WAAO,IAAI,MAAK,IAAI,EAAE,MAAM;AAAA,EAC9B;AAAA,EASA,SAAS,aAA0B;AACjC,UAAM,EAAE,QAAQ,EAAE,IAAI,KAAK;AAC3B,UAAM,EAAE,KAAK,IAAI,IAAI;AAAA,MACnB,GAAG,KAAK;AAAA,MACR,GAAG;AAAA,IACL;AAEA,SAAK,QAAQ;AAAA,MACX,GAAG,KAAK;AAAA,MACR;AAAA,MACA;AAAA,MACA,OAAO,MAAM,OAAO,KAAK,GAAG;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,QAAQ;AACN,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,OAAO;AACL,UAAM,EAAE,KAAK,IAAI,IAAI,KAAK;AAC1B,UAAM,UAAU,KAAK,OAAO,KAAK,MAAM,OAAO;AAE9C,SAAK,MAAM,QAAQ;AAEnB,WAAO;AAAA,EACT;AACF;;;ACnEO,IAAM,qBAAqB;AAuB3B,IAAM,gBAAgB,CAAC,SAC5B,OAAO,SAAS,cAAc,MAAM,MAAM,GAAG,CAAC,IAAI;AAE7C,IAAMA,gBAAe,CAAC,SAAgD;AAC3E,QAAM,EAAE,MAAM,GAAG,SAAS,IAAI,QAAQ,CAAC;AACvC,QAAM,iBAAiB,cAAc,IAAI;AAEzC,SAAO;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,UAAU;AAAA,IACV,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AAMO,IAAM,QAAN,MAAY;AAAA,EAKjB,YAAY,MAAqB;AAJjC;AACA,wBAAU;AACV,wBAAU;AAGR,UAAM,EAAE,KAAK,KAAK,MAAM,SAAS,IAAIA,cAAa,IAAI;AAEtD,SAAK,gBAAgB,IAAI,KAAK,EAAE,KAAK,IAAI,CAAC;AAC1C,SAAK,QAAQ,IAAI,KAAK,EAAE,KAAK,IAAI,KAAK,EAAE,CAAC;AAEzC,UAAM,eACJ,OAAO,MAAM,aAAa,cACtB,WACA,KAAK,cAAc,MAAM;AAE/B,SAAK,QAAQ;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,SAAS,aAAiD;AACxD,UAAM,EAAE,KAAK,IAAI,IAAI;AAAA,MACnB,KAAK,KAAK,MAAM;AAAA,MAChB,KAAK,KAAK,MAAM;AAAA,MAChB,GAAG;AAAA,IACL;AAEA,SAAK,cAAc,SAAS,EAAE,KAAK,IAAI,CAAC;AACxC,SAAK,QAAQ;AAAA,MACX,GAAG,KAAK;AAAA,MACR,GAAI,QAAQ,KAAK,MAAM,OAAO,QAAQ,KAAK,MAAM,MAC7C;AAAA,QACE,cAAc,MAAM,KAAK,cAAc,MAAM,GAAG,KAAK,GAAG;AAAA,QACxD;AAAA,QACA;AAAA,QACA,OAAO,MAAM,KAAK,MAAM,OAAO,KAAK,GAAG;AAAA,MACzC,IACA;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,IACN;AAAA,EACF;AAAA,EAEA,YAAY,aAA0C;AACpD,UAAM,OAAO,cAAc,aAAa,IAAI;AAE5C,SAAK,QAAQ;AAAA,MACX,GAAG,KAAK;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,KAAK,KAAK,UAAU,KAAK,IAAIA,cAAa,IAAI;AAEtD,SAAK,SAAS,EAAE,KAAK,IAAI,CAAC;AAC1B,SAAK,YAAY,EAAE,KAAK,CAAC;AAEzB,UAAM,eACJ,OAAO,MAAM,aAAa,cACtB,WACA,KAAK,cAAc,KAAK;AAE9B,SAAK,QAAQ;AAAA,MACX,GAAG,KAAK;AAAA,MACR;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,QAAQ;AACN,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,OAAO;AACL,UAAM,EAAE,KAAK,KAAK,MAAM,MAAM,IAAI,KAAK;AACvC,UAAM,UAAU,MAAM,QAAQ,MAAM,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK,GAAG;AAEtE,SAAK,MAAM,QAAQ;AAEnB,WAAO;AAAA,EACT;AACF;;;ACtIA,IAAI;AAEJ,IAAI,OAAO,gBAAgB,eAAe,SAAS,aAAa;AAC9D,aAAW,MAAM;AACf,WAAO,YAAY,IAAI;AAAA,EACzB;AACF,WACE,OAAO,YAAY,YACnB,QAAQ,SAAS,MAAM,oBACvB;AACA,QAAM,YAAY,MAAM;AACtB,UAAM,KAAK,QAAQ,OAAO;AAC1B,WAAO,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC;AAAA,EAC3B;AACA,QAAM,UAAU,UAAU;AAE1B,aAAW,MAAM;AACf,YAAQ,UAAU,IAAI,WAAW;AAAA,EACnC;AACF,OAAO;AACL,QAAM,UAAU,KAAK,IAAI;AAEzB,aAAW,MAAM;AACf,WAAO,KAAK,IAAI,IAAI;AAAA,EACtB;AACF;AAMO,SAAS,MAAM;AACpB,SAAO,SAAS;AAClB;;;ACVO,IAAMC,gBAAe,CAC1B,SAC6D;AAC7D,QAAM,EAAE,MAAM,GAAG,IAAI;AAAA,IACnB,GAAG;AAAA,IACH,MAAM;AAAA,MACJ,KAAK;AAAA,MACL,KAAK;AAAA,MACL,GAAG,MAAM;AAAA,IACX;AAAA,IACA,IAAI;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AAAA,MACL,GAAG,MAAM;AAAA,IACX;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,yBAAyB,CACpC,MACA,cACe;AACf,QAAM,EAAE,MAAM,GAAG,IAAI;AAErB,QAAM,YAAY;AAAA,IAChB,GAAG,UAAU;AAAA,IACb,GAAG;AAAA,EACL;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,MACJ,GAAG,UAAU;AAAA,MACb,GAAG;AAAA,IACL;AAAA,IACA,IAAI;AAAA,IACJ,OAAO,MAAM,UAAU,OAAO,UAAU,KAAK,UAAU,GAAG;AAAA,EAC5D;AACF;AAMO,IAAM,QAAN,MAAM,OAAM;AAAA,EAOjB,YAAY,MAAqB;AANjC;AAOE,UAAM,EAAE,MAAM,GAAG,IAAIA,cAAa,IAAI;AACtC,SAAK,QAAQ,EAAE,MAAM,IAAI,OAAO,GAAG,IAAI;AAAA,EACzC;AAAA,EAPA,OAAO,MAAM,GAAW,MAAqB;AAC3C,WAAO,IAAI,OAAM,IAAI,EAAE,MAAM,CAAC;AAAA,EAChC;AAAA,EAOA,UAAU,MAAoB;AAC5B,SAAK,QAAQ,uBAAuB,MAAM,KAAK,KAAK;AAAA,EACtD;AAAA,EAEA,MAAM,MAAoB;AACxB,UAAM,EAAE,MAAM,GAAG,IAAIA,cAAa,IAAI;AACtC,SAAK,QAAQ,EAAE,MAAM,IAAI,OAAO,GAAG,IAAI;AAAA,EACzC;AAAA,EAEA,QAAQ;AACN,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,MAAM,GAAW;AACf,UAAM,EAAE,MAAM,GAAG,IAAI,KAAK;AAC1B,UAAM,UACJ,GAAG,OACD,MAAM,GAAG,KAAK,KAAK,KAAK,GAAG,IAAI,KAAK,QAAQ,GAAG,MAAM,GAAG,QACvD,KAAK,MAAM,KAAK;AAErB,SAAK,MAAM,QAAQ;AAEnB,WAAO;AAAA,EACT;AACF;;;ACrFO,IAAMC,gBAAe,CAAC,SAA4C;AACvE,SAAO;AAAA,IACL,UAAU;AAAA,IACV,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,GAAG;AAAA,EACL;AACF;AAEA,IAAM,kBAAkB,CAAC;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF,MAAsC;AACpC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,IAAI;AAAA,IACV;AAAA,IACA,cAAc;AAAA,IACd,OAAO;AAAA,EACT;AACF;AAEO,IAAMC,0BAAyB,CACpC,MACA,cACa;AACb,QAAM,EAAE,MAAM,IAAI,SAAS,IAAI;AAAA,IAC7B,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,EAChB;AACF;AAMO,IAAM,MAAN,MAAU;AAAA,EAIf,YAAY,MAAkB;AAH9B;AACA,wBAAU;AAGR,UAAM,EAAE,MAAM,IAAI,SAAS,IAAID,cAAa,IAAI;AAEhD,SAAK,QAAQ,gBAAgB,EAAE,MAAM,IAAI,SAAS,CAAC;AACnD,SAAK,gBAAgB,IAAI,MAAM;AAAA,MAC7B,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAAA,MACA,IAAI;AAAA,QACF,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,YAAY,UAAkB;AAC5B,UAAM,EAAE,IAAI,aAAa,IAAI,KAAK;AAElC,SAAK,QAAQ;AAAA,MACX,GAAG,KAAK;AAAA,MACR,GAAI,YAAY,eACZ;AAAA,QACE;AAAA,QACA,OAAO;AAAA,MACT,IACA,EAAE,SAAS;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,MAAmB;AACvB,UAAM,UAAUC,wBAAuB,MAAM,KAAK,KAAK;AAEvD,SAAK,QAAQ;AAAA,MACX,GAAG;AAAA,MACH,MAAM,IAAI;AAAA,MACV,OAAO,QAAQ;AAAA,IACjB;AACA,SAAK,cAAc,UAAU;AAAA,MAC3B,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,KAAK,QAAQ;AAAA,MACf;AAAA,MACA,IAAI;AAAA,QACF,KAAK,QAAQ;AAAA,QACb,KAAK,QAAQ;AAAA,MACf;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,OAAO;AACL,WAAO,KAAK,MAAM,YAAY,KAAK,MAAM;AAAA,EAC3C;AAAA,EAEA,QAAQ;AACN,UAAM,EAAE,IAAI,MAAM,IAAI,KAAK;AAE3B,QAAI,KAAK,KAAK,GAAG;AACf,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,OAAO;AACL,QAAI,KAAK,KAAK,GAAG;AACf,aAAO,KAAK,MAAM;AAAA,IACpB;AAEA,UAAM,EAAE,MAAM,cAAc,iBAAiB,IAAI,KAAK;AAEtD,UAAM,OAAO,IAAI;AACjB,UAAM,eAAe,OAAO;AAC5B,UAAM,eAAe,mBAAmB;AACxC,UAAM,UAAU,KAAK,cAAc,MAAM,YAAY;AAErD,SAAK,MAAM,OAAO;AAClB,SAAK,MAAM,eAAe;AAC1B,SAAK,MAAM,QAAQ;AAEnB,WAAO;AAAA,EACT;AACF;;;ACvJO,IAAM,cAAc,KAAK,KAAK,IAAI;AAiBzC,IAAMC,mBAAkB,CAAC,cAAiC;AAAA,EACxD,OAAO;AAAA,EACP;AAAA,EACA,MAAM,IAAI;AAAA,EACV,cAAc;AAAA,EACd,OAAO;AACT;AAMO,IAAM,OAAN,MAAW;AAAA,EAIhB,YAAY,MAAmB;AAH/B;AACA,wBAAU;AAGR,UAAM,EAAE,SAAS,IAAI;AAErB,SAAK,gBAAgB,IAAI,MAAM;AAAA,MAC7B,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAAA,MACA,IAAI;AAAA,QACF,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAAA,IACF,CAAC;AACD,SAAK,QAAQA,iBAAgB,QAAQ;AAAA,EACvC;AAAA,EAEA,YAAY,UAAkB;AAC5B,SAAK,QAAQ;AAAA,MACX,GAAG,KAAK;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,MAAoB;AACxB,UAAM,EAAE,SAAS,IAAI;AAAA,MACnB,GAAG,KAAK;AAAA,MACR,GAAG;AAAA,IACL;AAEA,SAAK,QAAQA,iBAAgB,QAAQ;AAAA,EACvC;AAAA,EAEA,QAAQ;AACN,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,OAAO;AACL,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc;AAAA,IAChB,IAAI,KAAK;AACT,UAAM,OAAO,IAAI;AACjB,UAAM,eAAe,OAAO;AAC5B,UAAM,eAAe,mBAAmB;AAExC,UAAM,UAAU;AAAA,MACd,KAAK,IAAI,KAAK,cAAc,MAAM,YAAY,CAAC;AAAA,MAC/C;AAAA,MACA;AAAA,IACF;AAEA,QAAI,SAAS,UAAU;AACrB,WAAK,MAAM,QAAQ;AAAA,IACrB,OAAO;AACL,WAAK,MAAM,QAAQ,QAAQ;AAAA,IAC7B;AAEA,SAAK,MAAM,OAAO;AAClB,SAAK,MAAM,eAAe;AAC1B,SAAK,MAAM,QAAQ;AAEnB,WAAO;AAAA,EACT;AACF;;;ACtGO,IAAM,YAAY,MAAO;AACzB,IAAM,eAAe;AACrB,IAAM,eAAe,KAAK;AAC1B,IAAM,aAAa,eAAe;;;ACClC,IAAK,aAAL,kBAAKC,gBAAL;AACL,EAAAA,YAAA,SAAM;AACN,EAAAA,YAAA,WAAQ;AACR,EAAAA,YAAA,QAAK;AACL,EAAAA,YAAA,kBAAe;AACf,EAAAA,YAAA,aAAU;AACV,EAAAA,YAAA,aAAU;AANA,SAAAA;AAAA,GAAA;AAWL,IAAM,qBAA6C;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAEG,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAIrC,IAAM,aAAa,oBAAI,IAAwC;AAAA,EAC7D,CAAC,iBAAgB,CAAC,QAAgB,eAAe,GAAG;AAAA,EACpD,CAAC,iBAAkB,CAAC,QAAgB,MAAM,UAAU;AAAA,EACpD,CAAC,eAAe,CAAC,QAAiB,IAAI,MAAO,YAAY;AAAA,EACzD,CAAC,yBAAyB,CAAC,QAAgB,GAAG;AAAA,EAC9C,CAAC,mBAAoB,CAAC,QAAgB,MAAM,YAAY;AAAA,EACxD,CAAC,mBAAoB,CAAC,QAAgB,MAAM,YAAY;AAC1D,CAAC;AAED,IAAM,oBAAoB,CAAC,QAAgB,IAAI,kBAAkB,EAAE,KAAK;AAExE,IAAM,0BAA0B,CAAC,QAAgB;AAC/C,WAAS,IAAI,GAAG,IAAI,mBAAmB,QAAQ,KAAK,GAAG;AACrD,UAAM,SAAS,mBAAmB,CAAC;AAEnC,QAAI,IAAI,SAAS,MAAM,GAAG;AACxB,YAAM,QAAQ,OAAO,IAAI,QAAQ,KAAK,EAAE,EAAE,QAAQ,QAAQ,EAAE,CAAC;AAE7D,aAAO;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,OAAO;AAAA,EACT;AACF;AAcO,SAAS,GACd,KACA,QACoB;AACpB,MAAI,cAAyC;AAC7C,MAAI,eAAqC,UAAU;AAEnD,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,SAAS,wBAAwB,kBAAkB,GAAG,CAAC;AAE7D,QAAI,OAAO,OAAO,UAAU,aAAa;AACvC,oBAAc,OAAO;AAAA,IACvB;AAEA,QAAI,OAAO,QAAQ;AACjB,qBAAe,OAAO;AAAA,IACxB;AAAA,EACF,OAAO;AACL,kBAAc;AAAA,EAChB;AAEA,MACE,OAAO,gBAAgB,eACvB,gBAAgB,QAChB,OAAO,MAAM,WAAW,GACxB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,WAAW,IAAI,YAAY;AAE7C,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,SAAO,UAAU,WAAW;AAC9B;;;AC7FO,IAAMC,mBAAkB,CAAC,gBAAoC;AAClE,SAAO;AAAA,IACL;AAAA,IACA,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,cAAc;AAAA,IACd,MAAM;AAAA,IACN,cAAc;AAAA,EAChB;AACF;AAEO,IAAM,oBAAoB,CAAC,UAAyC;AACzE,QAAM,EAAE,MAAM,MAAM,cAAc,WAAW,IAAI;AACjD,QAAM,OAAO,IAAI;AAEjB,MAAI,eAAe,IAAI;AACrB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM;AAAA,MACN,YAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,eAAe,OAAO;AAE5B,MAAI,gBAAgB,MAAM;AACxB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY,aAAa;AAAA,IACzB,MAAM;AAAA,IACN;AAAA,IACA,cAAc,eAAe;AAAA,EAC/B;AACF;AAQO,IAAMC,gBAAe,CAAC,SAAgD;AAC3E,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AAUO,IAAM,QAAN,MAAY;AAAA,EAKjB,YAAY,UAAgC,MAAqB;AAJjE;AACA,wBAAU;AAiBV,gCAAO,MAAM;AACX,YAAM,EAAE,aAAa,IAAI,KAAK;AAC9B,WAAK,MAAM;AACX,WAAK,kBAAkB;AAEvB,aAAO;AAAA,IACT;AAEA,iCAAQ,MAAM;AACZ,YAAM,EAAE,YAAY,IAAI,KAAK;AAC7B,WAAK,QAAQD,iBAAgB,WAAW;AAAA,IAC1C;AAEA,mCAAU,CAAC,cAAc,KAAK,MAAM,SAAS;AAC3C,YAAM,OAAO,KAAK,IAAI,aAAa,CAAC;AAEpC,WAAK,QAAQ;AAAA,QACX,GAAG,KAAK;AAAA,QACR;AAAA,QACA,aAAa;AAAA,MACf;AAAA,IACF;AAEA,+BAAM,MAAM;AACV,UAAI,KAAK,MAAM,WAAW;AACxB,aAAK,KAAK;AAAA,MACZ;AAEA,WAAK,QAAQ;AAAA,QACX,GAAG,KAAK;AAAA,QACR,WAAW;AAAA,QACX,MAAM,IAAI;AAAA,MACZ;AAEA,YAAM,OAAO,MAAM;AACjB,cAAM,UAAU,kBAAkB,KAAK,KAAK;AAE5C,YAAI,SAAS;AACX,eAAK,QAAQ;AACb,eAAK,WAAW,QAAQ,CAAC,aAAa;AACpC,qBAAS,IAAI;AAAA,UACf,CAAC;AAAA,QACH;AAEA,YAAI,KAAK,MAAM,WAAW;AACxB,eAAK,aAAa,IAAI;AAAA,QACxB;AAAA,MACF;AAEA,WAAK;AAAA,IACP;AA/DE,UAAM,EAAE,KAAK,IAAIC,cAAa,IAAI;AAClC,SAAK,QAAQD,iBAAgB,IAAI;AACjC,SAAK,aAAa,CAAC,QAAQ;AAAA,EAC7B;AAAA,EAEU,aAAa,UAAsB;AAC3C,SAAK,WAAW,WAAW,UAAU,SAAS;AAAA,EAChD;AAAA,EAEU,oBAAoB;AAC5B,iBAAa,KAAK,QAAQ;AAAA,EAC5B;AAqDF;;;ACvIO,IAAM,cAAmB;AAEzB,IAAME,gBAAe,CAAC,SAAuC;AAClE,QAAM,EAAE,IAAI,IAAI;AAAA,IACd,KAAK;AAAA,IACL,GAAG;AAAA,EACL;AAEA,SAAO;AAAA,IACL,MAAM,GAAG,oBAAmB;AAAA,EAC9B;AACF;AAOO,IAAM,SAAN,cAAqB,MAAM;AAAA,EAGhC,YAAY,UAAiC,MAAsB;AACjE,UAAM,MAAM,SAAS,IAAI,GAAGA,cAAa,IAAI,CAAC;AAmBhD,kCAAS,CAAC,MAAM,gBAAgB;AAC9B,WAAK,QAAQ,GAAG,oBAAmB,CAAC;AAAA,IACtC;AAAA,EApBA;AAAA,EAEU,aAAa,UAAsB;AAC3C,QAAI,OAAO,WAAW,eAAe,EAAE,2BAA2B,SAAS;AACzE,YAAM,aAAa,QAAQ;AAAA,IAC7B,OAAO;AACL,WAAK,WAAW,sBAAsB,QAAQ;AAAA,IAChD;AAAA,EACF;AAAA,EAEU,oBAAoB;AAC5B,QAAI,OAAO,WAAW,eAAe,EAAE,0BAA0B,SAAS;AACxE,YAAM,kBAAkB;AAAA,IAC1B,OAAO;AACL,2BAAqB,KAAK,QAAQ;AAAA,IACpC;AAAA,EACF;AAKF;;;AC9CO,SAAS,KAAK,GAAmB;AACtC,SAAO,KAAK,IAAI,MAAM,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC;AACxC;;;ACJO,SAAS,KAAK,GAAmB;AACtC,SAAO,IAAI;AACb;","names":["parseOptions","parseOptions","parseOptions","updateStateFromOptions","getInitialState","TimeFormat","getInitialState","parseOptions","parseOptions"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/utils/clamp.ts","../src/math/Rand.ts","../src/math/Drunk.ts","../src/utils/now.ts","../src/math/Scale.ts","../src/math/Env.ts","../src/math/Sine.ts","../src/constants.ts","../src/utils/ms.ts","../src/timers/Metro.ts","../src/timers/Frames.ts","../src/utils/expo.ts"],"sourcesContent":["export { Drunk, type DrunkOptions, type DrunkState } from './math/Drunk';\nexport { Env, type EnvOptions, type EnvState } from './math/Env';\nexport { Rand, type RandOptions, type RandState } from './math/Rand';\nexport {\n Scale,\n type ScaleOptions,\n type ScaleRange,\n type ScaleState,\n} from './math/Scale';\nexport {\n Sine,\n type SineOptions,\n type SineState,\n SINE_PERIOD,\n} from './math/Sine';\nexport { Frames, type FramesOptions } from './timers/Frames';\nexport { Metro, type MetroOptions, type TimerCallback } from './timers/Metro';\nexport { clamp } from './utils/clamp';\nexport { expo } from './utils/expo';\nexport { ms, type FPS, TimeFormat } from './utils/ms';\nexport { now } from './utils/now';\nexport * from './constants';\n","export function clamp(n: number): number;\nexport function clamp(n: number, max: number): number;\nexport function clamp(n: number, min: number, max: number): number;\n\n/**\n * Constrains an input value to a min...max range.\n * @param n - The value to constrain.\n * @param min - Lower bound (defaults to 0).\n * @param max - Upper bound (defaults to 1).\n * @returns The clamped value.\n */\nexport function clamp(n: number, min?: number, max?: number) {\n let a = 0;\n let b = 1;\n\n if (typeof min === 'number') {\n if (typeof max === 'number') {\n a = min;\n b = max;\n } else {\n a = 0;\n b = min;\n }\n }\n\n return Math.min(Math.max(n, a), b);\n}\n","import { clamp } from '../utils/clamp';\n\n/** Options for configuring a Rand generator. */\nexport type RandOptions = {\n /** Lower bound of the range. Defaults to 0. */\n min?: number;\n /** Upper bound of the range. Defaults to 1. */\n max?: number;\n};\n\n/** Snapshot of a Rand generator's internal state. */\nexport type RandState = {\n min: number;\n max: number;\n value: number;\n};\n\nexport const parseOptions = (opts?: RandOptions): Required<RandOptions> => {\n return {\n min: 0,\n max: 1,\n ...opts,\n };\n};\n\n/**\n * Random number generator that produces values within a bounded range.\n * @param opts - {@link RandOptions} for configuring the range.\n */\nexport class Rand {\n state: RandState;\n\n static rand(opts?: RandOptions) {\n return new Rand(opts).value();\n }\n\n constructor(opts?: RandOptions) {\n const { min, max } = parseOptions(opts);\n\n this.state = { max, min, value: 0 };\n this.next();\n }\n\n setRange(partialOpts: RandOptions) {\n const { value = 0 } = this.state;\n const { min, max } = {\n ...this.state,\n ...partialOpts,\n };\n\n this.state = {\n ...this.state,\n max,\n min,\n value: clamp(value, min, max),\n };\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const { min, max } = this.state;\n const updates = Math.random() * (max - min) + min;\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { clamp } from '../utils/clamp';\nimport { Rand } from './Rand';\n\nexport const DEFAULT_DRUNK_STEP = 0.1;\n\n/** Options for configuring a Drunk random walk. */\nexport type DrunkOptions = {\n /** Upper bound of the range. Defaults to 1. */\n max?: number;\n /** Lower bound of the range. Defaults to 0. */\n min?: number;\n /** Initial value. If omitted, a random value within the range is used. */\n startsAt?: number;\n /** Maximum step size as a fraction of the range (0-1). Defaults to 0.1. */\n step?: number;\n};\n\n/** Snapshot of a Drunk walk's internal state. */\nexport type DrunkState = {\n initialValue: number;\n max: number;\n min: number;\n step: number;\n value: number;\n};\n\nexport const parseStepSize = (step?: number): number =>\n typeof step !== 'undefined' ? clamp(step, 0, 1) : DEFAULT_DRUNK_STEP;\n\nexport const parseOptions = (opts?: DrunkOptions): Required<DrunkOptions> => {\n const { step, ...restOpts } = opts || {};\n const parsedStepSize = parseStepSize(step);\n\n return {\n max: 1,\n min: 0,\n startsAt: 0,\n step: parsedStepSize,\n ...restOpts,\n };\n};\n\n/**\n * Stochastic random walk generator that produces values within a bounded range.\n * @param opts - {@link DrunkOptions} for configuring the walk.\n */\nexport class Drunk {\n state: DrunkState;\n protected _initialValue: Rand;\n protected _step: Rand;\n\n constructor(opts?: DrunkOptions) {\n const { min, max, step, startsAt } = parseOptions(opts);\n\n this._initialValue = new Rand({ min, max });\n this._step = new Rand({ min: -1, max: 1 });\n\n const initialValue =\n typeof opts?.startsAt !== 'undefined'\n ? startsAt\n : this._initialValue.value();\n\n this.state = {\n initialValue,\n max,\n min,\n step,\n value: initialValue,\n };\n }\n\n setRange(partialOpts?: Pick<DrunkOptions, 'min' | 'max'>) {\n const { max, min } = {\n min: this.state.min,\n max: this.state.max,\n ...partialOpts,\n };\n\n this._initialValue.setRange({ min, max });\n this.state = {\n ...this.state,\n ...(min !== this.state.min || max !== this.state.max\n ? {\n initialValue: clamp(this._initialValue.value(), min, max),\n max,\n min,\n value: clamp(this.state.value, min, max),\n }\n : {\n max,\n min,\n }),\n };\n }\n\n setStepSize(partialOpts?: Pick<DrunkOptions, 'step'>) {\n const step = parseStepSize(partialOpts?.step);\n\n this.state = {\n ...this.state,\n step,\n };\n }\n\n reset(opts?: DrunkOptions) {\n const { min, max, startsAt, step } = parseOptions(opts);\n\n this.setRange({ min, max });\n this.setStepSize({ step });\n\n const initialValue =\n typeof opts?.startsAt !== 'undefined'\n ? startsAt\n : this._initialValue.next();\n\n this.state = {\n ...this.state,\n initialValue,\n value: initialValue,\n };\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const { min, max, step, value } = this.state;\n const updates = clamp(value + max * this._step.next() * step, min, max);\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","type InnerNow = () => number;\n\n/** Resolve the best available clock once at module load. */\nconst innerNow = ((): InnerNow => {\n // Browser or modern Node (>= 16)\n if (typeof performance !== 'undefined' && 'now' in performance) {\n return () => performance.now();\n }\n\n // Older Node — use process.hrtime, offset from first call\n if (\n typeof process === 'object' &&\n process.toString() === '[object process]'\n ) {\n const ts = () => {\n const hr = process.hrtime();\n return hr[0] * 1e9 + hr[1];\n };\n const initialNow = ts();\n return () => (ts() - initialNow) / 1e6;\n }\n\n // Fallback — Date.now with manual offset\n const initialNow = Date.now();\n return () => Date.now() - initialNow;\n})();\n\n/**\n * Cross-environment high-resolution timestamp (performance.now polyfill).\n * @returns Elapsed milliseconds since initialization.\n */\nexport function now(): number {\n return innerNow();\n}\n","import { clamp } from '../utils/clamp';\n\n/** A numeric range with min and max bounds. */\nexport type ScaleRange = {\n min?: number;\n max: number;\n};\n\n/** Options for configuring a Scale mapper. */\nexport type ScaleOptions = {\n /** Input range. Defaults to { min: 0, max: 1 }. */\n from?: ScaleRange;\n /** Output range. Defaults to { min: 0, max: 1 }. */\n to?: ScaleRange;\n};\n\n/** Snapshot of a Scale mapper's internal state. */\nexport type ScaleState = {\n /** Input range. */\n from: Required<ScaleRange>;\n /** Precomputed (to.max - to.min) / (from.max - from.min), updated when ranges change. */\n ratio: number;\n /** Output range. */\n to: Required<ScaleRange>;\n /** Last scaled value. */\n value: number;\n};\n\n/** Precompute the scale factor so the hot path avoids a division per call. */\nconst computeRatio = (from: Required<ScaleRange>, to: Required<ScaleRange>) =>\n (to.max - to.min) / (from.max - from.min);\n\n/** Build initial state from options, applying defaults and computing the ratio. */\nexport const parseInitialState = (opts?: ScaleOptions): ScaleState => {\n const initialRange: Pick<ScaleState, 'from' | 'to'> = {\n from: {\n min: 0,\n max: 1,\n ...opts?.from,\n },\n to: {\n min: 0,\n max: 1,\n ...opts?.to,\n },\n };\n\n return {\n ...initialRange,\n ratio: computeRatio(initialRange.from, initialRange.to),\n value: initialRange.to.min,\n };\n};\n\n/** Merge partial range updates into existing state, recomputing the ratio. */\nexport const updateStateFromOptions = (\n opts: ScaleOptions,\n prevState: ScaleState,\n): ScaleState => {\n const { from, to } = opts;\n const updatedFrom: Required<ScaleRange> = {\n ...prevState.from,\n ...from,\n };\n const updatedTo: Required<ScaleRange> = {\n ...prevState.to,\n ...to,\n };\n\n return {\n ...prevState,\n from: updatedFrom,\n ratio: computeRatio(updatedFrom, updatedTo),\n to: updatedTo,\n value: clamp(prevState.value, updatedTo.min, updatedTo.max),\n };\n};\n\n/**\n * Linear map of values from one range to another, supports negative values and inversion.\n * @param opts - {@link ScaleOptions} for configuring input and output ranges.\n */\nexport class Scale {\n state: ScaleState;\n\n static scale(n: number, opts?: ScaleOptions) {\n return new Scale(opts).scale(n);\n }\n\n constructor(opts?: ScaleOptions) {\n this.state = parseInitialState(opts);\n }\n\n setRanges(opts: ScaleOptions) {\n this.state = updateStateFromOptions(opts, this.state);\n }\n\n reset(opts: ScaleOptions) {\n this.state = parseInitialState(opts);\n }\n\n value() {\n return this.state.value;\n }\n\n scale(n: number) {\n const { from, to, ratio } = this.state;\n const updates = to.min + (clamp(n, from.min, from.max) - from.min) * ratio;\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { now } from '../utils/now';\nimport { Scale } from './Scale';\n\n/** Snapshot of an Env's internal state. */\nexport type EnvState = {\n duration: number;\n from: number;\n prev: number;\n to: number;\n totalElapsed: number;\n value: number;\n};\n\n/** Options for configuring an Env envelope. */\nexport type EnvOptions = {\n /** Duration of the envelope in milliseconds. */\n duration: number;\n /** Starting value. Defaults to 0. */\n from?: number;\n /** Ending value. Defaults to 1. */\n to?: number;\n};\n\nexport const parseOptions = (opts?: EnvOptions): Required<EnvOptions> => {\n return {\n duration: 0,\n from: 0,\n to: 1,\n ...opts,\n };\n};\n\nconst getInitialState = ({\n from,\n to,\n duration,\n}: Required<EnvOptions>): EnvState => {\n return {\n duration,\n from,\n prev: now(),\n to,\n totalElapsed: 0,\n value: from,\n };\n};\n\nexport const updateStateFromOptions = (\n opts: EnvOptions | undefined,\n prevState: EnvState,\n): EnvState => {\n const { from, to, duration } = {\n ...prevState,\n ...opts,\n };\n\n return {\n ...prevState,\n duration,\n from,\n to,\n totalElapsed: 0,\n };\n};\n\n/**\n * Linear envelope which interpolates between two values over a duration. Useful for audio envelopes, transitions, and animations.\n * @param opts - {@link EnvOptions} for configuring the envelope.\n */\nexport class Env {\n state: EnvState;\n protected _interpolator: Scale;\n\n constructor(opts: EnvOptions) {\n const { from, to, duration } = parseOptions(opts);\n\n this.state = getInitialState({ from, to, duration });\n this._interpolator = new Scale({\n from: {\n min: 0,\n max: duration,\n },\n to: {\n min: from,\n max: to,\n },\n });\n }\n\n setDuration(duration: number) {\n const { to, totalElapsed } = this.state;\n\n this.state = {\n ...this.state,\n ...(duration <= totalElapsed\n ? {\n duration,\n value: to,\n }\n : { duration }),\n };\n }\n\n reset(opts?: EnvOptions) {\n const updates = updateStateFromOptions(opts, this.state);\n\n this.state = {\n ...updates,\n prev: now(),\n value: updates.from,\n };\n this._interpolator.setRanges({\n from: {\n min: 0,\n max: updates.duration,\n },\n to: {\n min: updates.from,\n max: updates.to,\n },\n });\n }\n\n done() {\n return this.state.duration <= this.state.totalElapsed;\n }\n\n value() {\n const { to, value } = this.state;\n\n if (this.done()) {\n return to;\n }\n\n return value;\n }\n\n next() {\n if (this.done()) {\n return this.value();\n }\n\n const { prev, totalElapsed: prevTotalElapsed } = this.state;\n\n const curr = now();\n const tickInterval = curr - prev;\n const totalElapsed = prevTotalElapsed + tickInterval;\n const updates = this._interpolator.scale(totalElapsed);\n\n this.state.prev = curr;\n this.state.totalElapsed = totalElapsed;\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { clamp } from '../utils/clamp';\nimport { now } from '../utils/now';\nimport { Scale } from './Scale';\n\nexport const SINE_PERIOD = Math.PI * 2 - 0.0001;\n\n/** Options for configuring a Sine oscillator. */\nexport type SineOptions = {\n /** Duration of one full cycle in milliseconds. */\n duration: number;\n};\n\n/** Snapshot of a Sine oscillator's internal state. */\nexport type SineState = {\n cycle: number;\n duration: number;\n prev: number;\n totalElapsed: number;\n value: number;\n};\n\nconst getInitialState = (duration: number): SineState => ({\n cycle: 0,\n duration,\n prev: now(),\n totalElapsed: 0,\n value: 0,\n});\n\n/**\n * Time-based sine wave oscillator that outputs values between -1 and 1.\n * @param opts - {@link SineOptions} for configuring the oscillator.\n */\nexport class Sine {\n state: SineState;\n protected _interpolator: Scale;\n\n constructor(opts: SineOptions) {\n const { duration } = opts;\n\n this._interpolator = new Scale({\n from: {\n min: 0,\n max: duration,\n },\n to: {\n min: 0,\n max: SINE_PERIOD,\n },\n });\n this.state = getInitialState(duration);\n }\n\n setDuration(duration: number) {\n this.state = {\n ...this.state,\n duration,\n };\n }\n\n reset(opts?: SineOptions) {\n const { duration } = {\n ...this.state,\n ...opts,\n };\n\n this.state = getInitialState(duration);\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const {\n cycle,\n duration,\n prev,\n totalElapsed: prevTotalElapsed,\n } = this.state;\n const curr = now();\n const tickInterval = curr - prev;\n const totalElapsed = prevTotalElapsed + tickInterval;\n\n const updates = clamp(\n Math.sin(this._interpolator.scale(totalElapsed)),\n -1,\n 1,\n );\n\n if (cycle >= duration) {\n this.state.cycle = 0;\n } else {\n this.state.cycle = cycle + tickInterval;\n }\n\n this.state.prev = curr;\n this.state.totalElapsed = totalElapsed;\n this.state.value = updates;\n\n return updates;\n }\n}\n","export const SIXTY_FPS = 1000 / 60;\nexport const MS_IN_SECOND = 1000;\nexport const MS_IN_MINUTE = 60 * MS_IN_SECOND;\nexport const MS_IN_HOUR = MS_IN_MINUTE * 60;\n","import { MS_IN_SECOND, MS_IN_MINUTE, MS_IN_HOUR } from '../constants';\n\nexport type FPS = 15 | 30 | 60;\n\nexport enum TimeFormat {\n FPS = 'fps',\n HOURS = 'h',\n HZ = 'hz',\n MILLISECONDS = 'ms',\n MINUTES = 'm',\n SECONDS = 's',\n}\n\nexport type AvailableTimeFormats = `${TimeFormat}`;\n\nexport const FORMAT_IDENTIFIERS: AvailableTimeFormats[] = [\n TimeFormat.FPS,\n TimeFormat.HOURS,\n TimeFormat.HZ,\n TimeFormat.MILLISECONDS,\n TimeFormat.MINUTES,\n TimeFormat.SECONDS,\n]\n // Desc length sort so that `ms` matches prior to `m`\n .sort((a, b) => b.length - a.length);\n\ntype FormatGetter = (val: number) => number;\n\nconst FORMATTERS = new Map<AvailableTimeFormats, FormatGetter>([\n [TimeFormat.FPS, (val: number) => MS_IN_SECOND / val],\n [TimeFormat.HOURS, (val: number) => val * MS_IN_HOUR],\n [TimeFormat.HZ, (val: number) => (1 / val) * MS_IN_SECOND],\n [TimeFormat.MILLISECONDS, (val: number) => val],\n [TimeFormat.MINUTES, (val: number) => val * MS_IN_MINUTE],\n [TimeFormat.SECONDS, (val: number) => val * MS_IN_SECOND],\n]);\n\nconst sanitizeStringVal = (val: string) => val.toLocaleLowerCase().trim();\n\nconst parseStringValAndFormat = (val: string) => {\n for (let i = 0; i < FORMAT_IDENTIFIERS.length; i += 1) {\n const format = FORMAT_IDENTIFIERS[i];\n\n if (val.includes(format)) {\n const value = Number(val.replace(' ', '').replace(format, ''));\n\n return {\n format,\n value,\n };\n }\n }\n\n return {\n format: undefined,\n value: undefined,\n };\n};\n\nexport function ms(val: string | null | undefined): number | undefined;\nexport function ms(\n val: string | number | null | undefined,\n format?: AvailableTimeFormats | TimeFormat,\n): number | undefined;\n\n/**\n * Converts time format strings or numeric values to their corresponding value in milliseconds.\n * @param val - A string like `'60fps'`, `'2s'`, or a numeric value.\n * @param format - Explicit time format when `val` is a number.\n * @returns Milliseconds, or undefined if the input is invalid.\n */\nexport function ms(\n val: string | number | null | undefined,\n format?: AvailableTimeFormats | TimeFormat,\n): number | undefined {\n let parsedValue: number | null | undefined = null;\n let parsedFormat: AvailableTimeFormats = format || TimeFormat.MILLISECONDS;\n\n if (typeof val === 'string') {\n const parsed = parseStringValAndFormat(sanitizeStringVal(val));\n\n if (typeof parsed.value !== 'undefined') {\n parsedValue = parsed.value;\n }\n\n if (parsed.format) {\n parsedFormat = parsed.format;\n }\n } else {\n parsedValue = val;\n }\n\n if (\n typeof parsedValue === 'undefined' ||\n parsedValue === null ||\n Number.isNaN(parsedValue)\n ) {\n return undefined;\n }\n\n const formatter = FORMATTERS.get(parsedFormat);\n\n if (!formatter) {\n return undefined;\n }\n\n return formatter(parsedValue);\n}\n","import { SIXTY_FPS } from '../constants';\nimport { now } from '../utils/now';\n\n/** Snapshot of a running timer's internal state. */\nexport type TimerState = {\n initialTime: number;\n isRunning: boolean;\n iterations: number;\n prev: number;\n tickInterval: number;\n time: number;\n totalElapsed: number;\n};\n\nexport const getInitialState = (initialTime: number): TimerState => {\n return {\n initialTime,\n isRunning: false,\n iterations: -1,\n prev: 0,\n tickInterval: 0,\n time: initialTime,\n totalElapsed: 0,\n };\n};\n\nexport const processTimerState = (state: TimerState): TimerState | null => {\n const { time, prev, totalElapsed, iterations } = state;\n const curr = now();\n\n if (iterations === -1) {\n return {\n ...state,\n prev: curr,\n iterations: 0,\n };\n }\n\n const tickInterval = curr - prev;\n\n if (tickInterval <= time) {\n return null;\n }\n\n return {\n ...state,\n iterations: iterations + 1,\n prev: curr,\n tickInterval,\n totalElapsed: totalElapsed + tickInterval,\n };\n};\n\n/** Options for configuring a Metro timer. */\nexport type MetroOptions = {\n /** Interval between ticks in milliseconds. Defaults to ~16.67ms (60fps). */\n time?: number;\n};\n\nexport const parseOptions = (opts?: MetroOptions): Required<MetroOptions> => {\n return {\n time: SIXTY_FPS,\n ...opts,\n };\n};\n\n/** Callback invoked on each timer tick with the timer instance. */\nexport type TimerCallback<T extends Metro> = (timer: T) => void;\n\n/**\n * High-resolution recursive timer with variable interval, provides runtime metrics via callback for time-based calculations.\n * @param callback - {@link TimerCallback} called on each tick with the timer instance.\n * @param opts - {@link MetroOptions} for configuring the timer interval.\n */\nexport class Metro {\n state: TimerState;\n protected _listeners: TimerCallback<Metro>[];\n protected declare _timerId: ReturnType<typeof setTimeout> | number;\n\n constructor(callback: TimerCallback<Metro>, opts?: MetroOptions) {\n const { time } = parseOptions(opts);\n this.state = getInitialState(time);\n this._listeners = [callback];\n }\n\n protected asyncHandler(callback: () => void) {\n this._timerId = setTimeout(callback, SIXTY_FPS);\n }\n\n protected clearAsyncHandler() {\n clearTimeout(this._timerId);\n }\n\n stop = () => {\n const { totalElapsed } = this.state;\n this.reset();\n this.clearAsyncHandler();\n\n return totalElapsed;\n };\n\n reset = () => {\n const { initialTime } = this.state;\n this.state = getInitialState(initialTime);\n };\n\n setTime = (updatedTime = this.state.time) => {\n const time = Math.max(updatedTime, 0);\n\n this.state = {\n ...this.state,\n time,\n initialTime: time,\n };\n };\n\n run = () => {\n if (this.state.isRunning) {\n this.stop();\n }\n\n this.state = {\n ...this.state,\n isRunning: true,\n prev: now(),\n };\n\n const tick = () => {\n const updates = processTimerState(this.state);\n\n if (updates) {\n this.state = updates;\n this._listeners.forEach((listener) => {\n listener(this);\n });\n }\n\n if (this.state.isRunning) {\n this.asyncHandler(tick);\n }\n };\n\n tick();\n };\n}\n","import { ms, TimeFormat, type FPS } from '../utils/ms';\nimport { Metro, type TimerCallback, type MetroOptions } from './Metro';\n\n/** Options for configuring a Frames timer. */\nexport type FramesOptions = {\n /** Target frames per second (15, 30, or 60). Defaults to 60. */\n fps: FPS;\n};\n\nexport const DEFAULT_FPS: FPS = 60;\n\nexport const parseOptions = (opts?: FramesOptions): MetroOptions => {\n const { fps } = {\n fps: DEFAULT_FPS,\n ...opts,\n };\n\n return {\n time: ms(fps, TimeFormat.FPS),\n };\n};\n\n/**\n * Animation-loop timer that uses requestAnimationFrame when available.\n * @param callback - {@link TimerCallback} called on each frame tick.\n * @param opts - {@link FramesOptions} for configuring the target frame rate.\n */\nexport class Frames extends Metro {\n protected declare _timerId: ReturnType<typeof requestAnimationFrame>;\n\n constructor(callback: TimerCallback<Frames>, opts?: FramesOptions) {\n super(() => callback(this), parseOptions(opts));\n }\n\n protected asyncHandler(callback: () => void) {\n if (typeof window === 'undefined' || !('requestAnimationFrame' in window)) {\n super.asyncHandler(callback);\n } else {\n this._timerId = requestAnimationFrame(callback);\n }\n }\n\n protected clearAsyncHandler() {\n if (typeof window === 'undefined' || !('cancelAnimationFrame' in window)) {\n super.clearAsyncHandler();\n } else {\n cancelAnimationFrame(this._timerId);\n }\n }\n\n setFPS = (fps = DEFAULT_FPS) => {\n this.setTime(ms(fps, TimeFormat.FPS));\n };\n}\n","import { clamp } from './clamp';\n\n/**\n * Scales 0...1 by Euler's number to produce a natural feeling curve.\n * @param n - Input value (clamped to 0-1).\n * @returns The exponentially scaled value.\n */\nexport function expo(n: number): number {\n return Math.pow(clamp(n, 0, 1), Math.E);\n}\n"],"mappings":"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","names":["parseOptions","initialNow","parseOptions","updateStateFromOptions","getInitialState","TimeFormat","getInitialState","parseOptions","parseOptions"]}
package/dist/index.d.cts CHANGED
@@ -73,8 +73,13 @@ type ScaleOptions = {
73
73
  };
74
74
  /** Snapshot of a Scale mapper's internal state. */
75
75
  type ScaleState = {
76
+ /** Input range. */
76
77
  from: Required<ScaleRange>;
78
+ /** Precomputed (to.max - to.min) / (from.max - from.min), updated when ranges change. */
79
+ ratio: number;
80
+ /** Output range. */
77
81
  to: Required<ScaleRange>;
82
+ /** Last scaled value. */
78
83
  value: number;
79
84
  };
80
85
  /**
@@ -229,13 +234,6 @@ declare function clamp(n: number, min: number, max: number): number;
229
234
  */
230
235
  declare function expo(n: number): number;
231
236
 
232
- /**
233
- * Flips the sign of a number.
234
- * @param n - The input value.
235
- * @returns The negated value.
236
- */
237
- declare function flip(n: number): number;
238
-
239
237
  /**
240
238
  * Cross-environment high-resolution timestamp (performance.now polyfill).
241
239
  * @returns Elapsed milliseconds since initialization.
@@ -247,4 +245,4 @@ declare const MS_IN_SECOND = 1000;
247
245
  declare const MS_IN_MINUTE: number;
248
246
  declare const MS_IN_HOUR: number;
249
247
 
250
- export { Drunk, type DrunkOptions, type DrunkState, Env, type EnvOptions, type EnvState, type FPS, Frames, type FramesOptions, MS_IN_HOUR, MS_IN_MINUTE, MS_IN_SECOND, Metro, type MetroOptions, Rand, type RandOptions, type RandState, SINE_PERIOD, SIXTY_FPS, Scale, type ScaleOptions, type ScaleRange, type ScaleState, Sine, type SineOptions, type SineState, TimeFormat, type TimerCallback, clamp, expo, flip, ms, now };
248
+ export { Drunk, type DrunkOptions, type DrunkState, Env, type EnvOptions, type EnvState, type FPS, Frames, type FramesOptions, MS_IN_HOUR, MS_IN_MINUTE, MS_IN_SECOND, Metro, type MetroOptions, Rand, type RandOptions, type RandState, SINE_PERIOD, SIXTY_FPS, Scale, type ScaleOptions, type ScaleRange, type ScaleState, Sine, type SineOptions, type SineState, TimeFormat, type TimerCallback, clamp, expo, ms, now };
package/dist/index.d.ts CHANGED
@@ -73,8 +73,13 @@ type ScaleOptions = {
73
73
  };
74
74
  /** Snapshot of a Scale mapper's internal state. */
75
75
  type ScaleState = {
76
+ /** Input range. */
76
77
  from: Required<ScaleRange>;
78
+ /** Precomputed (to.max - to.min) / (from.max - from.min), updated when ranges change. */
79
+ ratio: number;
80
+ /** Output range. */
77
81
  to: Required<ScaleRange>;
82
+ /** Last scaled value. */
78
83
  value: number;
79
84
  };
80
85
  /**
@@ -229,13 +234,6 @@ declare function clamp(n: number, min: number, max: number): number;
229
234
  */
230
235
  declare function expo(n: number): number;
231
236
 
232
- /**
233
- * Flips the sign of a number.
234
- * @param n - The input value.
235
- * @returns The negated value.
236
- */
237
- declare function flip(n: number): number;
238
-
239
237
  /**
240
238
  * Cross-environment high-resolution timestamp (performance.now polyfill).
241
239
  * @returns Elapsed milliseconds since initialization.
@@ -247,4 +245,4 @@ declare const MS_IN_SECOND = 1000;
247
245
  declare const MS_IN_MINUTE: number;
248
246
  declare const MS_IN_HOUR: number;
249
247
 
250
- export { Drunk, type DrunkOptions, type DrunkState, Env, type EnvOptions, type EnvState, type FPS, Frames, type FramesOptions, MS_IN_HOUR, MS_IN_MINUTE, MS_IN_SECOND, Metro, type MetroOptions, Rand, type RandOptions, type RandState, SINE_PERIOD, SIXTY_FPS, Scale, type ScaleOptions, type ScaleRange, type ScaleState, Sine, type SineOptions, type SineState, TimeFormat, type TimerCallback, clamp, expo, flip, ms, now };
248
+ export { Drunk, type DrunkOptions, type DrunkState, Env, type EnvOptions, type EnvState, type FPS, Frames, type FramesOptions, MS_IN_HOUR, MS_IN_MINUTE, MS_IN_SECOND, Metro, type MetroOptions, Rand, type RandOptions, type RandState, SINE_PERIOD, SIXTY_FPS, Scale, type ScaleOptions, type ScaleRange, type ScaleState, Sine, type SineOptions, type SineState, TimeFormat, type TimerCallback, clamp, expo, ms, now };
package/dist/index.js CHANGED
@@ -141,34 +141,29 @@ var Drunk = class {
141
141
  };
142
142
 
143
143
  // src/utils/now.ts
144
- var internal;
145
- if (typeof performance !== "undefined" && "now" in performance) {
146
- internal = () => {
147
- return performance.now();
148
- };
149
- } else if (typeof process === "object" && process.toString() === "[object process]") {
150
- const timestamp = () => {
151
- const hr = process.hrtime();
152
- return hr[0] * 1e9 + hr[1];
153
- };
154
- const initial = timestamp();
155
- internal = () => {
156
- return (timestamp() - initial) / 1e6;
157
- };
158
- } else {
159
- const initial = Date.now();
160
- internal = () => {
161
- return Date.now() - initial;
162
- };
163
- }
144
+ var innerNow = (() => {
145
+ if (typeof performance !== "undefined" && "now" in performance) {
146
+ return () => performance.now();
147
+ }
148
+ if (typeof process === "object" && process.toString() === "[object process]") {
149
+ const ts = () => {
150
+ const hr = process.hrtime();
151
+ return hr[0] * 1e9 + hr[1];
152
+ };
153
+ const initialNow2 = ts();
154
+ return () => (ts() - initialNow2) / 1e6;
155
+ }
156
+ const initialNow = Date.now();
157
+ return () => Date.now() - initialNow;
158
+ })();
164
159
  function now() {
165
- return internal();
160
+ return innerNow();
166
161
  }
167
162
 
168
163
  // src/math/Scale.ts
169
- var parseOptions3 = (opts) => {
170
- const { from, to } = {
171
- ...opts,
164
+ var computeRatio = (from, to) => (to.max - to.min) / (from.max - from.min);
165
+ var parseInitialState = (opts) => {
166
+ const initialRange = {
172
167
  from: {
173
168
  min: 0,
174
169
  max: 1,
@@ -181,22 +176,25 @@ var parseOptions3 = (opts) => {
181
176
  }
182
177
  };
183
178
  return {
184
- from,
185
- to
179
+ ...initialRange,
180
+ ratio: computeRatio(initialRange.from, initialRange.to),
181
+ value: initialRange.to.min
186
182
  };
187
183
  };
188
184
  var updateStateFromOptions = (opts, prevState) => {
189
185
  const { from, to } = opts;
186
+ const updatedFrom = {
187
+ ...prevState.from,
188
+ ...from
189
+ };
190
190
  const updatedTo = {
191
191
  ...prevState.to,
192
192
  ...to
193
193
  };
194
194
  return {
195
195
  ...prevState,
196
- from: {
197
- ...prevState.from,
198
- ...from
199
- },
196
+ from: updatedFrom,
197
+ ratio: computeRatio(updatedFrom, updatedTo),
200
198
  to: updatedTo,
201
199
  value: clamp(prevState.value, updatedTo.min, updatedTo.max)
202
200
  };
@@ -204,8 +202,7 @@ var updateStateFromOptions = (opts, prevState) => {
204
202
  var Scale = class _Scale {
205
203
  constructor(opts) {
206
204
  __publicField(this, "state");
207
- const { from, to } = parseOptions3(opts);
208
- this.state = { from, to, value: to.min };
205
+ this.state = parseInitialState(opts);
209
206
  }
210
207
  static scale(n, opts) {
211
208
  return new _Scale(opts).scale(n);
@@ -214,22 +211,21 @@ var Scale = class _Scale {
214
211
  this.state = updateStateFromOptions(opts, this.state);
215
212
  }
216
213
  reset(opts) {
217
- const { from, to } = parseOptions3(opts);
218
- this.state = { from, to, value: to.min };
214
+ this.state = parseInitialState(opts);
219
215
  }
220
216
  value() {
221
217
  return this.state.value;
222
218
  }
223
219
  scale(n) {
224
- const { from, to } = this.state;
225
- const updates = to.min + (clamp(n, from.min, from.max) - from.min) * (to.max - to.min) / (from.max - from.min);
220
+ const { from, to, ratio } = this.state;
221
+ const updates = to.min + (clamp(n, from.min, from.max) - from.min) * ratio;
226
222
  this.state.value = updates;
227
223
  return updates;
228
224
  }
229
225
  };
230
226
 
231
227
  // src/math/Env.ts
232
- var parseOptions4 = (opts) => {
228
+ var parseOptions3 = (opts) => {
233
229
  return {
234
230
  duration: 0,
235
231
  from: 0,
@@ -268,7 +264,7 @@ var Env = class {
268
264
  constructor(opts) {
269
265
  __publicField(this, "state");
270
266
  __publicField(this, "_interpolator");
271
- const { from, to, duration } = parseOptions4(opts);
267
+ const { from, to, duration } = parseOptions3(opts);
272
268
  this.state = getInitialState({ from, to, duration });
273
269
  this._interpolator = new Scale({
274
270
  from: {
@@ -511,7 +507,7 @@ var processTimerState = (state) => {
511
507
  totalElapsed: totalElapsed + tickInterval
512
508
  };
513
509
  };
514
- var parseOptions5 = (opts) => {
510
+ var parseOptions4 = (opts) => {
515
511
  return {
516
512
  time: SIXTY_FPS,
517
513
  ...opts
@@ -562,7 +558,7 @@ var Metro = class {
562
558
  };
563
559
  tick();
564
560
  });
565
- const { time } = parseOptions5(opts);
561
+ const { time } = parseOptions4(opts);
566
562
  this.state = getInitialState3(time);
567
563
  this._listeners = [callback];
568
564
  }
@@ -576,7 +572,7 @@ var Metro = class {
576
572
 
577
573
  // src/timers/Frames.ts
578
574
  var DEFAULT_FPS = 60;
579
- var parseOptions6 = (opts) => {
575
+ var parseOptions5 = (opts) => {
580
576
  const { fps } = {
581
577
  fps: DEFAULT_FPS,
582
578
  ...opts
@@ -587,7 +583,7 @@ var parseOptions6 = (opts) => {
587
583
  };
588
584
  var Frames = class extends Metro {
589
585
  constructor(callback, opts) {
590
- super(() => callback(this), parseOptions6(opts));
586
+ super(() => callback(this), parseOptions5(opts));
591
587
  __publicField(this, "setFPS", (fps = DEFAULT_FPS) => {
592
588
  this.setTime(ms(fps, "fps" /* FPS */));
593
589
  });
@@ -612,11 +608,6 @@ var Frames = class extends Metro {
612
608
  function expo(n) {
613
609
  return Math.pow(clamp(n, 0, 1), Math.E);
614
610
  }
615
-
616
- // src/utils/flip.ts
617
- function flip(n) {
618
- return n * -1;
619
- }
620
611
  export {
621
612
  Drunk,
622
613
  Env,
@@ -633,7 +624,6 @@ export {
633
624
  TimeFormat,
634
625
  clamp,
635
626
  expo,
636
- flip,
637
627
  ms,
638
628
  now
639
629
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/clamp.ts","../src/math/Rand.ts","../src/math/Drunk.ts","../src/utils/now.ts","../src/math/Scale.ts","../src/math/Env.ts","../src/math/Sine.ts","../src/constants.ts","../src/utils/ms.ts","../src/timers/Metro.ts","../src/timers/Frames.ts","../src/utils/expo.ts","../src/utils/flip.ts"],"sourcesContent":["export function clamp(n: number): number;\nexport function clamp(n: number, max: number): number;\nexport function clamp(n: number, min: number, max: number): number;\n\n/**\n * Constrains an input value to a min...max range.\n * @param n - The value to constrain.\n * @param min - Lower bound (defaults to 0).\n * @param max - Upper bound (defaults to 1).\n * @returns The clamped value.\n */\nexport function clamp(n: number, min?: number, max?: number) {\n let a = 0;\n let b = 1;\n\n if (typeof min === 'number') {\n if (typeof max === 'number') {\n a = min;\n b = max;\n } else {\n a = 0;\n b = min;\n }\n }\n\n return Math.min(Math.max(n, a), b);\n}\n","import { clamp } from '../utils/clamp';\n\n/** Options for configuring a Rand generator. */\nexport type RandOptions = {\n /** Lower bound of the range. Defaults to 0. */\n min?: number;\n /** Upper bound of the range. Defaults to 1. */\n max?: number;\n};\n\n/** Snapshot of a Rand generator's internal state. */\nexport type RandState = {\n min: number;\n max: number;\n value: number;\n};\n\nexport const parseOptions = (opts?: RandOptions): Required<RandOptions> => {\n return {\n min: 0,\n max: 1,\n ...opts,\n };\n};\n\n/**\n * Random number generator that produces values within a bounded range.\n * @param opts - {@link RandOptions} for configuring the range.\n */\nexport class Rand {\n state: RandState;\n\n static rand(opts?: RandOptions) {\n return new Rand(opts).value();\n }\n\n constructor(opts?: RandOptions) {\n const { min, max } = parseOptions(opts);\n\n this.state = { max, min, value: 0 };\n this.next();\n }\n\n setRange(partialOpts: RandOptions) {\n const { value = 0 } = this.state;\n const { min, max } = {\n ...this.state,\n ...partialOpts,\n };\n\n this.state = {\n ...this.state,\n max,\n min,\n value: clamp(value, min, max),\n };\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const { min, max } = this.state;\n const updates = Math.random() * (max - min) + min;\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { clamp } from '../utils/clamp';\nimport { Rand } from './Rand';\n\nexport const DEFAULT_DRUNK_STEP = 0.1;\n\n/** Options for configuring a Drunk random walk. */\nexport type DrunkOptions = {\n /** Upper bound of the range. Defaults to 1. */\n max?: number;\n /** Lower bound of the range. Defaults to 0. */\n min?: number;\n /** Initial value. If omitted, a random value within the range is used. */\n startsAt?: number;\n /** Maximum step size as a fraction of the range (0-1). Defaults to 0.1. */\n step?: number;\n};\n\n/** Snapshot of a Drunk walk's internal state. */\nexport type DrunkState = {\n initialValue: number;\n max: number;\n min: number;\n step: number;\n value: number;\n};\n\nexport const parseStepSize = (step?: number): number =>\n typeof step !== 'undefined' ? clamp(step, 0, 1) : DEFAULT_DRUNK_STEP;\n\nexport const parseOptions = (opts?: DrunkOptions): Required<DrunkOptions> => {\n const { step, ...restOpts } = opts || {};\n const parsedStepSize = parseStepSize(step);\n\n return {\n max: 1,\n min: 0,\n startsAt: 0,\n step: parsedStepSize,\n ...restOpts,\n };\n};\n\n/**\n * Stochastic random walk generator that produces values within a bounded range.\n * @param opts - {@link DrunkOptions} for configuring the walk.\n */\nexport class Drunk {\n state: DrunkState;\n protected _initialValue: Rand;\n protected _step: Rand;\n\n constructor(opts?: DrunkOptions) {\n const { min, max, step, startsAt } = parseOptions(opts);\n\n this._initialValue = new Rand({ min, max });\n this._step = new Rand({ min: -1, max: 1 });\n\n const initialValue =\n typeof opts?.startsAt !== 'undefined'\n ? startsAt\n : this._initialValue.value();\n\n this.state = {\n initialValue,\n max,\n min,\n step,\n value: initialValue,\n };\n }\n\n setRange(partialOpts?: Pick<DrunkOptions, 'min' | 'max'>) {\n const { max, min } = {\n min: this.state.min,\n max: this.state.max,\n ...partialOpts,\n };\n\n this._initialValue.setRange({ min, max });\n this.state = {\n ...this.state,\n ...(min !== this.state.min || max !== this.state.max\n ? {\n initialValue: clamp(this._initialValue.value(), min, max),\n max,\n min,\n value: clamp(this.state.value, min, max),\n }\n : {\n max,\n min,\n }),\n };\n }\n\n setStepSize(partialOpts?: Pick<DrunkOptions, 'step'>) {\n const step = parseStepSize(partialOpts?.step);\n\n this.state = {\n ...this.state,\n step,\n };\n }\n\n reset(opts?: DrunkOptions) {\n const { min, max, startsAt, step } = parseOptions(opts);\n\n this.setRange({ min, max });\n this.setStepSize({ step });\n\n const initialValue =\n typeof opts?.startsAt !== 'undefined'\n ? startsAt\n : this._initialValue.next();\n\n this.state = {\n ...this.state,\n initialValue,\n value: initialValue,\n };\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const { min, max, step, value } = this.state;\n const updates = clamp(value + max * this._step.next() * step, min, max);\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","let internal: () => number;\n\nif (typeof performance !== 'undefined' && 'now' in performance) {\n internal = () => {\n return performance.now();\n };\n} else if (\n typeof process === 'object' &&\n process.toString() === '[object process]'\n) {\n const timestamp = () => {\n const hr = process.hrtime();\n return hr[0] * 1e9 + hr[1];\n };\n const initial = timestamp();\n\n internal = () => {\n return (timestamp() - initial) / 1e6;\n };\n} else {\n const initial = Date.now();\n\n internal = () => {\n return Date.now() - initial;\n };\n}\n\n/**\n * Cross-environment high-resolution timestamp (performance.now polyfill).\n * @returns Elapsed milliseconds since initialization.\n */\nexport function now() {\n return internal();\n}\n","import { clamp } from '../utils/clamp';\n\n/** A numeric range with min and max bounds. */\nexport type ScaleRange = {\n min?: number;\n max: number;\n};\n\n/** Options for configuring a Scale mapper. */\nexport type ScaleOptions = {\n /** Input range. Defaults to { min: 0, max: 1 }. */\n from?: ScaleRange;\n /** Output range. Defaults to { min: 0, max: 1 }. */\n to?: ScaleRange;\n};\n\n/** Snapshot of a Scale mapper's internal state. */\nexport type ScaleState = {\n from: Required<ScaleRange>;\n to: Required<ScaleRange>;\n value: number;\n};\n\nexport const parseOptions = (\n opts?: ScaleOptions,\n): { from: Required<ScaleRange>; to: Required<ScaleRange> } => {\n const { from, to } = {\n ...opts,\n from: {\n min: 0,\n max: 1,\n ...opts?.from,\n },\n to: {\n min: 0,\n max: 1,\n ...opts?.to,\n },\n };\n\n return {\n from,\n to,\n };\n};\n\nexport const updateStateFromOptions = (\n opts: ScaleOptions,\n prevState: ScaleState,\n): ScaleState => {\n const { from, to } = opts;\n\n const updatedTo = {\n ...prevState.to,\n ...to,\n };\n\n return {\n ...prevState,\n from: {\n ...prevState.from,\n ...from,\n },\n to: updatedTo,\n value: clamp(prevState.value, updatedTo.min, updatedTo.max),\n };\n};\n\n/**\n * Linear map of values from one range to another, supports negative values and inversion.\n * @param opts - {@link ScaleOptions} for configuring input and output ranges.\n */\nexport class Scale {\n state: ScaleState;\n\n static scale(n: number, opts?: ScaleOptions) {\n return new Scale(opts).scale(n);\n }\n\n constructor(opts?: ScaleOptions) {\n const { from, to } = parseOptions(opts);\n this.state = { from, to, value: to.min };\n }\n\n setRanges(opts: ScaleOptions) {\n this.state = updateStateFromOptions(opts, this.state);\n }\n\n reset(opts: ScaleOptions) {\n const { from, to } = parseOptions(opts);\n this.state = { from, to, value: to.min };\n }\n\n value() {\n return this.state.value;\n }\n\n scale(n: number) {\n const { from, to } = this.state;\n const updates =\n to.min +\n ((clamp(n, from.min, from.max) - from.min) * (to.max - to.min)) /\n (from.max - from.min);\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { now } from '../utils/now';\nimport { Scale } from './Scale';\n\n/** Snapshot of an Env's internal state. */\nexport type EnvState = {\n duration: number;\n from: number;\n prev: number;\n to: number;\n totalElapsed: number;\n value: number;\n};\n\n/** Options for configuring an Env envelope. */\nexport type EnvOptions = {\n /** Duration of the envelope in milliseconds. */\n duration: number;\n /** Starting value. Defaults to 0. */\n from?: number;\n /** Ending value. Defaults to 1. */\n to?: number;\n};\n\nexport const parseOptions = (opts?: EnvOptions): Required<EnvOptions> => {\n return {\n duration: 0,\n from: 0,\n to: 1,\n ...opts,\n };\n};\n\nconst getInitialState = ({\n from,\n to,\n duration,\n}: Required<EnvOptions>): EnvState => {\n return {\n duration,\n from,\n prev: now(),\n to,\n totalElapsed: 0,\n value: from,\n };\n};\n\nexport const updateStateFromOptions = (\n opts: EnvOptions | undefined,\n prevState: EnvState,\n): EnvState => {\n const { from, to, duration } = {\n ...prevState,\n ...opts,\n };\n\n return {\n ...prevState,\n duration,\n from,\n to,\n totalElapsed: 0,\n };\n};\n\n/**\n * Linear envelope which interpolates between two values over a duration. Useful for audio envelopes, transitions, and animations.\n * @param opts - {@link EnvOptions} for configuring the envelope.\n */\nexport class Env {\n state: EnvState;\n protected _interpolator: Scale;\n\n constructor(opts: EnvOptions) {\n const { from, to, duration } = parseOptions(opts);\n\n this.state = getInitialState({ from, to, duration });\n this._interpolator = new Scale({\n from: {\n min: 0,\n max: duration,\n },\n to: {\n min: from,\n max: to,\n },\n });\n }\n\n setDuration(duration: number) {\n const { to, totalElapsed } = this.state;\n\n this.state = {\n ...this.state,\n ...(duration <= totalElapsed\n ? {\n duration,\n value: to,\n }\n : { duration }),\n };\n }\n\n reset(opts?: EnvOptions) {\n const updates = updateStateFromOptions(opts, this.state);\n\n this.state = {\n ...updates,\n prev: now(),\n value: updates.from,\n };\n this._interpolator.setRanges({\n from: {\n min: 0,\n max: updates.duration,\n },\n to: {\n min: updates.from,\n max: updates.to,\n },\n });\n }\n\n done() {\n return this.state.duration <= this.state.totalElapsed;\n }\n\n value() {\n const { to, value } = this.state;\n\n if (this.done()) {\n return to;\n }\n\n return value;\n }\n\n next() {\n if (this.done()) {\n return this.value();\n }\n\n const { prev, totalElapsed: prevTotalElapsed } = this.state;\n\n const curr = now();\n const tickInterval = curr - prev;\n const totalElapsed = prevTotalElapsed + tickInterval;\n const updates = this._interpolator.scale(totalElapsed);\n\n this.state.prev = curr;\n this.state.totalElapsed = totalElapsed;\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { clamp } from '../utils/clamp';\nimport { now } from '../utils/now';\nimport { Scale } from './Scale';\n\nexport const SINE_PERIOD = Math.PI * 2 - 0.0001;\n\n/** Options for configuring a Sine oscillator. */\nexport type SineOptions = {\n /** Duration of one full cycle in milliseconds. */\n duration: number;\n};\n\n/** Snapshot of a Sine oscillator's internal state. */\nexport type SineState = {\n cycle: number;\n duration: number;\n prev: number;\n totalElapsed: number;\n value: number;\n};\n\nconst getInitialState = (duration: number): SineState => ({\n cycle: 0,\n duration,\n prev: now(),\n totalElapsed: 0,\n value: 0,\n});\n\n/**\n * Time-based sine wave oscillator that outputs values between -1 and 1.\n * @param opts - {@link SineOptions} for configuring the oscillator.\n */\nexport class Sine {\n state: SineState;\n protected _interpolator: Scale;\n\n constructor(opts: SineOptions) {\n const { duration } = opts;\n\n this._interpolator = new Scale({\n from: {\n min: 0,\n max: duration,\n },\n to: {\n min: 0,\n max: SINE_PERIOD,\n },\n });\n this.state = getInitialState(duration);\n }\n\n setDuration(duration: number) {\n this.state = {\n ...this.state,\n duration,\n };\n }\n\n reset(opts?: SineOptions) {\n const { duration } = {\n ...this.state,\n ...opts,\n };\n\n this.state = getInitialState(duration);\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const {\n cycle,\n duration,\n prev,\n totalElapsed: prevTotalElapsed,\n } = this.state;\n const curr = now();\n const tickInterval = curr - prev;\n const totalElapsed = prevTotalElapsed + tickInterval;\n\n const updates = clamp(\n Math.sin(this._interpolator.scale(totalElapsed)),\n -1,\n 1,\n );\n\n if (cycle >= duration) {\n this.state.cycle = 0;\n } else {\n this.state.cycle = cycle + tickInterval;\n }\n\n this.state.prev = curr;\n this.state.totalElapsed = totalElapsed;\n this.state.value = updates;\n\n return updates;\n }\n}\n","export const SIXTY_FPS = 1000 / 60;\nexport const MS_IN_SECOND = 1000;\nexport const MS_IN_MINUTE = 60 * MS_IN_SECOND;\nexport const MS_IN_HOUR = MS_IN_MINUTE * 60;\n","import { MS_IN_SECOND, MS_IN_MINUTE, MS_IN_HOUR } from '../constants';\n\nexport type FPS = 15 | 30 | 60;\n\nexport enum TimeFormat {\n FPS = 'fps',\n HOURS = 'h',\n HZ = 'hz',\n MILLISECONDS = 'ms',\n MINUTES = 'm',\n SECONDS = 's',\n}\n\nexport type AvailableTimeFormats = `${TimeFormat}`;\n\nexport const FORMAT_IDENTIFIERS: AvailableTimeFormats[] = [\n TimeFormat.FPS,\n TimeFormat.HOURS,\n TimeFormat.HZ,\n TimeFormat.MILLISECONDS,\n TimeFormat.MINUTES,\n TimeFormat.SECONDS,\n]\n // Desc length sort so that `ms` matches prior to `m`\n .sort((a, b) => b.length - a.length);\n\ntype FormatGetter = (val: number) => number;\n\nconst FORMATTERS = new Map<AvailableTimeFormats, FormatGetter>([\n [TimeFormat.FPS, (val: number) => MS_IN_SECOND / val],\n [TimeFormat.HOURS, (val: number) => val * MS_IN_HOUR],\n [TimeFormat.HZ, (val: number) => (1 / val) * MS_IN_SECOND],\n [TimeFormat.MILLISECONDS, (val: number) => val],\n [TimeFormat.MINUTES, (val: number) => val * MS_IN_MINUTE],\n [TimeFormat.SECONDS, (val: number) => val * MS_IN_SECOND],\n]);\n\nconst sanitizeStringVal = (val: string) => val.toLocaleLowerCase().trim();\n\nconst parseStringValAndFormat = (val: string) => {\n for (let i = 0; i < FORMAT_IDENTIFIERS.length; i += 1) {\n const format = FORMAT_IDENTIFIERS[i];\n\n if (val.includes(format)) {\n const value = Number(val.replace(' ', '').replace(format, ''));\n\n return {\n format,\n value,\n };\n }\n }\n\n return {\n format: undefined,\n value: undefined,\n };\n};\n\nexport function ms(val: string | null | undefined): number | undefined;\nexport function ms(\n val: string | number | null | undefined,\n format?: AvailableTimeFormats | TimeFormat,\n): number | undefined;\n\n/**\n * Converts time format strings or numeric values to their corresponding value in milliseconds.\n * @param val - A string like `'60fps'`, `'2s'`, or a numeric value.\n * @param format - Explicit time format when `val` is a number.\n * @returns Milliseconds, or undefined if the input is invalid.\n */\nexport function ms(\n val: string | number | null | undefined,\n format?: AvailableTimeFormats | TimeFormat,\n): number | undefined {\n let parsedValue: number | null | undefined = null;\n let parsedFormat: AvailableTimeFormats = format || TimeFormat.MILLISECONDS;\n\n if (typeof val === 'string') {\n const parsed = parseStringValAndFormat(sanitizeStringVal(val));\n\n if (typeof parsed.value !== 'undefined') {\n parsedValue = parsed.value;\n }\n\n if (parsed.format) {\n parsedFormat = parsed.format;\n }\n } else {\n parsedValue = val;\n }\n\n if (\n typeof parsedValue === 'undefined' ||\n parsedValue === null ||\n Number.isNaN(parsedValue)\n ) {\n return undefined;\n }\n\n const formatter = FORMATTERS.get(parsedFormat);\n\n if (!formatter) {\n return undefined;\n }\n\n return formatter(parsedValue);\n}\n","import { SIXTY_FPS } from '../constants';\nimport { now } from '../utils/now';\n\n/** Snapshot of a running timer's internal state. */\nexport type TimerState = {\n initialTime: number;\n isRunning: boolean;\n iterations: number;\n prev: number;\n tickInterval: number;\n time: number;\n totalElapsed: number;\n};\n\nexport const getInitialState = (initialTime: number): TimerState => {\n return {\n initialTime,\n isRunning: false,\n iterations: -1,\n prev: 0,\n tickInterval: 0,\n time: initialTime,\n totalElapsed: 0,\n };\n};\n\nexport const processTimerState = (state: TimerState): TimerState | null => {\n const { time, prev, totalElapsed, iterations } = state;\n const curr = now();\n\n if (iterations === -1) {\n return {\n ...state,\n prev: curr,\n iterations: 0,\n };\n }\n\n const tickInterval = curr - prev;\n\n if (tickInterval <= time) {\n return null;\n }\n\n return {\n ...state,\n iterations: iterations + 1,\n prev: curr,\n tickInterval,\n totalElapsed: totalElapsed + tickInterval,\n };\n};\n\n/** Options for configuring a Metro timer. */\nexport type MetroOptions = {\n /** Interval between ticks in milliseconds. Defaults to ~16.67ms (60fps). */\n time?: number;\n};\n\nexport const parseOptions = (opts?: MetroOptions): Required<MetroOptions> => {\n return {\n time: SIXTY_FPS,\n ...opts,\n };\n};\n\n/** Callback invoked on each timer tick with the timer instance. */\nexport type TimerCallback<T extends Metro> = (timer: T) => void;\n\n/**\n * High-resolution recursive timer with variable interval, provides runtime metrics via callback for time-based calculations.\n * @param callback - {@link TimerCallback} called on each tick with the timer instance.\n * @param opts - {@link MetroOptions} for configuring the timer interval.\n */\nexport class Metro {\n state: TimerState;\n protected _listeners: TimerCallback<Metro>[];\n protected declare _timerId: ReturnType<typeof setTimeout> | number;\n\n constructor(callback: TimerCallback<Metro>, opts?: MetroOptions) {\n const { time } = parseOptions(opts);\n this.state = getInitialState(time);\n this._listeners = [callback];\n }\n\n protected asyncHandler(callback: () => void) {\n this._timerId = setTimeout(callback, SIXTY_FPS);\n }\n\n protected clearAsyncHandler() {\n clearTimeout(this._timerId);\n }\n\n stop = () => {\n const { totalElapsed } = this.state;\n this.reset();\n this.clearAsyncHandler();\n\n return totalElapsed;\n };\n\n reset = () => {\n const { initialTime } = this.state;\n this.state = getInitialState(initialTime);\n };\n\n setTime = (updatedTime = this.state.time) => {\n const time = Math.max(updatedTime, 0);\n\n this.state = {\n ...this.state,\n time,\n initialTime: time,\n };\n };\n\n run = () => {\n if (this.state.isRunning) {\n this.stop();\n }\n\n this.state = {\n ...this.state,\n isRunning: true,\n prev: now(),\n };\n\n const tick = () => {\n const updates = processTimerState(this.state);\n\n if (updates) {\n this.state = updates;\n this._listeners.forEach((listener) => {\n listener(this);\n });\n }\n\n if (this.state.isRunning) {\n this.asyncHandler(tick);\n }\n };\n\n tick();\n };\n}\n","import { ms, TimeFormat, type FPS } from '../utils/ms';\nimport { Metro, type TimerCallback, type MetroOptions } from './Metro';\n\n/** Options for configuring a Frames timer. */\nexport type FramesOptions = {\n /** Target frames per second (15, 30, or 60). Defaults to 60. */\n fps: FPS;\n};\n\nexport const DEFAULT_FPS: FPS = 60;\n\nexport const parseOptions = (opts?: FramesOptions): MetroOptions => {\n const { fps } = {\n fps: DEFAULT_FPS,\n ...opts,\n };\n\n return {\n time: ms(fps, TimeFormat.FPS),\n };\n};\n\n/**\n * Animation-loop timer that uses requestAnimationFrame when available.\n * @param callback - {@link TimerCallback} called on each frame tick.\n * @param opts - {@link FramesOptions} for configuring the target frame rate.\n */\nexport class Frames extends Metro {\n protected declare _timerId: ReturnType<typeof requestAnimationFrame>;\n\n constructor(callback: TimerCallback<Frames>, opts?: FramesOptions) {\n super(() => callback(this), parseOptions(opts));\n }\n\n protected asyncHandler(callback: () => void) {\n if (typeof window === 'undefined' || !('requestAnimationFrame' in window)) {\n super.asyncHandler(callback);\n } else {\n this._timerId = requestAnimationFrame(callback);\n }\n }\n\n protected clearAsyncHandler() {\n if (typeof window === 'undefined' || !('cancelAnimationFrame' in window)) {\n super.clearAsyncHandler();\n } else {\n cancelAnimationFrame(this._timerId);\n }\n }\n\n setFPS = (fps = DEFAULT_FPS) => {\n this.setTime(ms(fps, TimeFormat.FPS));\n };\n}\n","import { clamp } from './clamp';\n\n/**\n * Scales 0...1 by Euler's number to produce a natural feeling curve.\n * @param n - Input value (clamped to 0-1).\n * @returns The exponentially scaled value.\n */\nexport function expo(n: number): number {\n return Math.pow(clamp(n, 0, 1), Math.E);\n}\n","/**\n * Flips the sign of a number.\n * @param n - The input value.\n * @returns The negated value.\n */\nexport function flip(n: number): number {\n return n * -1;\n}\n"],"mappings":"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","names":["parseOptions","parseOptions","parseOptions","updateStateFromOptions","getInitialState","TimeFormat","getInitialState","parseOptions","parseOptions"]}
1
+ {"version":3,"sources":["../src/utils/clamp.ts","../src/math/Rand.ts","../src/math/Drunk.ts","../src/utils/now.ts","../src/math/Scale.ts","../src/math/Env.ts","../src/math/Sine.ts","../src/constants.ts","../src/utils/ms.ts","../src/timers/Metro.ts","../src/timers/Frames.ts","../src/utils/expo.ts"],"sourcesContent":["export function clamp(n: number): number;\nexport function clamp(n: number, max: number): number;\nexport function clamp(n: number, min: number, max: number): number;\n\n/**\n * Constrains an input value to a min...max range.\n * @param n - The value to constrain.\n * @param min - Lower bound (defaults to 0).\n * @param max - Upper bound (defaults to 1).\n * @returns The clamped value.\n */\nexport function clamp(n: number, min?: number, max?: number) {\n let a = 0;\n let b = 1;\n\n if (typeof min === 'number') {\n if (typeof max === 'number') {\n a = min;\n b = max;\n } else {\n a = 0;\n b = min;\n }\n }\n\n return Math.min(Math.max(n, a), b);\n}\n","import { clamp } from '../utils/clamp';\n\n/** Options for configuring a Rand generator. */\nexport type RandOptions = {\n /** Lower bound of the range. Defaults to 0. */\n min?: number;\n /** Upper bound of the range. Defaults to 1. */\n max?: number;\n};\n\n/** Snapshot of a Rand generator's internal state. */\nexport type RandState = {\n min: number;\n max: number;\n value: number;\n};\n\nexport const parseOptions = (opts?: RandOptions): Required<RandOptions> => {\n return {\n min: 0,\n max: 1,\n ...opts,\n };\n};\n\n/**\n * Random number generator that produces values within a bounded range.\n * @param opts - {@link RandOptions} for configuring the range.\n */\nexport class Rand {\n state: RandState;\n\n static rand(opts?: RandOptions) {\n return new Rand(opts).value();\n }\n\n constructor(opts?: RandOptions) {\n const { min, max } = parseOptions(opts);\n\n this.state = { max, min, value: 0 };\n this.next();\n }\n\n setRange(partialOpts: RandOptions) {\n const { value = 0 } = this.state;\n const { min, max } = {\n ...this.state,\n ...partialOpts,\n };\n\n this.state = {\n ...this.state,\n max,\n min,\n value: clamp(value, min, max),\n };\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const { min, max } = this.state;\n const updates = Math.random() * (max - min) + min;\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { clamp } from '../utils/clamp';\nimport { Rand } from './Rand';\n\nexport const DEFAULT_DRUNK_STEP = 0.1;\n\n/** Options for configuring a Drunk random walk. */\nexport type DrunkOptions = {\n /** Upper bound of the range. Defaults to 1. */\n max?: number;\n /** Lower bound of the range. Defaults to 0. */\n min?: number;\n /** Initial value. If omitted, a random value within the range is used. */\n startsAt?: number;\n /** Maximum step size as a fraction of the range (0-1). Defaults to 0.1. */\n step?: number;\n};\n\n/** Snapshot of a Drunk walk's internal state. */\nexport type DrunkState = {\n initialValue: number;\n max: number;\n min: number;\n step: number;\n value: number;\n};\n\nexport const parseStepSize = (step?: number): number =>\n typeof step !== 'undefined' ? clamp(step, 0, 1) : DEFAULT_DRUNK_STEP;\n\nexport const parseOptions = (opts?: DrunkOptions): Required<DrunkOptions> => {\n const { step, ...restOpts } = opts || {};\n const parsedStepSize = parseStepSize(step);\n\n return {\n max: 1,\n min: 0,\n startsAt: 0,\n step: parsedStepSize,\n ...restOpts,\n };\n};\n\n/**\n * Stochastic random walk generator that produces values within a bounded range.\n * @param opts - {@link DrunkOptions} for configuring the walk.\n */\nexport class Drunk {\n state: DrunkState;\n protected _initialValue: Rand;\n protected _step: Rand;\n\n constructor(opts?: DrunkOptions) {\n const { min, max, step, startsAt } = parseOptions(opts);\n\n this._initialValue = new Rand({ min, max });\n this._step = new Rand({ min: -1, max: 1 });\n\n const initialValue =\n typeof opts?.startsAt !== 'undefined'\n ? startsAt\n : this._initialValue.value();\n\n this.state = {\n initialValue,\n max,\n min,\n step,\n value: initialValue,\n };\n }\n\n setRange(partialOpts?: Pick<DrunkOptions, 'min' | 'max'>) {\n const { max, min } = {\n min: this.state.min,\n max: this.state.max,\n ...partialOpts,\n };\n\n this._initialValue.setRange({ min, max });\n this.state = {\n ...this.state,\n ...(min !== this.state.min || max !== this.state.max\n ? {\n initialValue: clamp(this._initialValue.value(), min, max),\n max,\n min,\n value: clamp(this.state.value, min, max),\n }\n : {\n max,\n min,\n }),\n };\n }\n\n setStepSize(partialOpts?: Pick<DrunkOptions, 'step'>) {\n const step = parseStepSize(partialOpts?.step);\n\n this.state = {\n ...this.state,\n step,\n };\n }\n\n reset(opts?: DrunkOptions) {\n const { min, max, startsAt, step } = parseOptions(opts);\n\n this.setRange({ min, max });\n this.setStepSize({ step });\n\n const initialValue =\n typeof opts?.startsAt !== 'undefined'\n ? startsAt\n : this._initialValue.next();\n\n this.state = {\n ...this.state,\n initialValue,\n value: initialValue,\n };\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const { min, max, step, value } = this.state;\n const updates = clamp(value + max * this._step.next() * step, min, max);\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","type InnerNow = () => number;\n\n/** Resolve the best available clock once at module load. */\nconst innerNow = ((): InnerNow => {\n // Browser or modern Node (>= 16)\n if (typeof performance !== 'undefined' && 'now' in performance) {\n return () => performance.now();\n }\n\n // Older Node — use process.hrtime, offset from first call\n if (\n typeof process === 'object' &&\n process.toString() === '[object process]'\n ) {\n const ts = () => {\n const hr = process.hrtime();\n return hr[0] * 1e9 + hr[1];\n };\n const initialNow = ts();\n return () => (ts() - initialNow) / 1e6;\n }\n\n // Fallback — Date.now with manual offset\n const initialNow = Date.now();\n return () => Date.now() - initialNow;\n})();\n\n/**\n * Cross-environment high-resolution timestamp (performance.now polyfill).\n * @returns Elapsed milliseconds since initialization.\n */\nexport function now(): number {\n return innerNow();\n}\n","import { clamp } from '../utils/clamp';\n\n/** A numeric range with min and max bounds. */\nexport type ScaleRange = {\n min?: number;\n max: number;\n};\n\n/** Options for configuring a Scale mapper. */\nexport type ScaleOptions = {\n /** Input range. Defaults to { min: 0, max: 1 }. */\n from?: ScaleRange;\n /** Output range. Defaults to { min: 0, max: 1 }. */\n to?: ScaleRange;\n};\n\n/** Snapshot of a Scale mapper's internal state. */\nexport type ScaleState = {\n /** Input range. */\n from: Required<ScaleRange>;\n /** Precomputed (to.max - to.min) / (from.max - from.min), updated when ranges change. */\n ratio: number;\n /** Output range. */\n to: Required<ScaleRange>;\n /** Last scaled value. */\n value: number;\n};\n\n/** Precompute the scale factor so the hot path avoids a division per call. */\nconst computeRatio = (from: Required<ScaleRange>, to: Required<ScaleRange>) =>\n (to.max - to.min) / (from.max - from.min);\n\n/** Build initial state from options, applying defaults and computing the ratio. */\nexport const parseInitialState = (opts?: ScaleOptions): ScaleState => {\n const initialRange: Pick<ScaleState, 'from' | 'to'> = {\n from: {\n min: 0,\n max: 1,\n ...opts?.from,\n },\n to: {\n min: 0,\n max: 1,\n ...opts?.to,\n },\n };\n\n return {\n ...initialRange,\n ratio: computeRatio(initialRange.from, initialRange.to),\n value: initialRange.to.min,\n };\n};\n\n/** Merge partial range updates into existing state, recomputing the ratio. */\nexport const updateStateFromOptions = (\n opts: ScaleOptions,\n prevState: ScaleState,\n): ScaleState => {\n const { from, to } = opts;\n const updatedFrom: Required<ScaleRange> = {\n ...prevState.from,\n ...from,\n };\n const updatedTo: Required<ScaleRange> = {\n ...prevState.to,\n ...to,\n };\n\n return {\n ...prevState,\n from: updatedFrom,\n ratio: computeRatio(updatedFrom, updatedTo),\n to: updatedTo,\n value: clamp(prevState.value, updatedTo.min, updatedTo.max),\n };\n};\n\n/**\n * Linear map of values from one range to another, supports negative values and inversion.\n * @param opts - {@link ScaleOptions} for configuring input and output ranges.\n */\nexport class Scale {\n state: ScaleState;\n\n static scale(n: number, opts?: ScaleOptions) {\n return new Scale(opts).scale(n);\n }\n\n constructor(opts?: ScaleOptions) {\n this.state = parseInitialState(opts);\n }\n\n setRanges(opts: ScaleOptions) {\n this.state = updateStateFromOptions(opts, this.state);\n }\n\n reset(opts: ScaleOptions) {\n this.state = parseInitialState(opts);\n }\n\n value() {\n return this.state.value;\n }\n\n scale(n: number) {\n const { from, to, ratio } = this.state;\n const updates = to.min + (clamp(n, from.min, from.max) - from.min) * ratio;\n\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { now } from '../utils/now';\nimport { Scale } from './Scale';\n\n/** Snapshot of an Env's internal state. */\nexport type EnvState = {\n duration: number;\n from: number;\n prev: number;\n to: number;\n totalElapsed: number;\n value: number;\n};\n\n/** Options for configuring an Env envelope. */\nexport type EnvOptions = {\n /** Duration of the envelope in milliseconds. */\n duration: number;\n /** Starting value. Defaults to 0. */\n from?: number;\n /** Ending value. Defaults to 1. */\n to?: number;\n};\n\nexport const parseOptions = (opts?: EnvOptions): Required<EnvOptions> => {\n return {\n duration: 0,\n from: 0,\n to: 1,\n ...opts,\n };\n};\n\nconst getInitialState = ({\n from,\n to,\n duration,\n}: Required<EnvOptions>): EnvState => {\n return {\n duration,\n from,\n prev: now(),\n to,\n totalElapsed: 0,\n value: from,\n };\n};\n\nexport const updateStateFromOptions = (\n opts: EnvOptions | undefined,\n prevState: EnvState,\n): EnvState => {\n const { from, to, duration } = {\n ...prevState,\n ...opts,\n };\n\n return {\n ...prevState,\n duration,\n from,\n to,\n totalElapsed: 0,\n };\n};\n\n/**\n * Linear envelope which interpolates between two values over a duration. Useful for audio envelopes, transitions, and animations.\n * @param opts - {@link EnvOptions} for configuring the envelope.\n */\nexport class Env {\n state: EnvState;\n protected _interpolator: Scale;\n\n constructor(opts: EnvOptions) {\n const { from, to, duration } = parseOptions(opts);\n\n this.state = getInitialState({ from, to, duration });\n this._interpolator = new Scale({\n from: {\n min: 0,\n max: duration,\n },\n to: {\n min: from,\n max: to,\n },\n });\n }\n\n setDuration(duration: number) {\n const { to, totalElapsed } = this.state;\n\n this.state = {\n ...this.state,\n ...(duration <= totalElapsed\n ? {\n duration,\n value: to,\n }\n : { duration }),\n };\n }\n\n reset(opts?: EnvOptions) {\n const updates = updateStateFromOptions(opts, this.state);\n\n this.state = {\n ...updates,\n prev: now(),\n value: updates.from,\n };\n this._interpolator.setRanges({\n from: {\n min: 0,\n max: updates.duration,\n },\n to: {\n min: updates.from,\n max: updates.to,\n },\n });\n }\n\n done() {\n return this.state.duration <= this.state.totalElapsed;\n }\n\n value() {\n const { to, value } = this.state;\n\n if (this.done()) {\n return to;\n }\n\n return value;\n }\n\n next() {\n if (this.done()) {\n return this.value();\n }\n\n const { prev, totalElapsed: prevTotalElapsed } = this.state;\n\n const curr = now();\n const tickInterval = curr - prev;\n const totalElapsed = prevTotalElapsed + tickInterval;\n const updates = this._interpolator.scale(totalElapsed);\n\n this.state.prev = curr;\n this.state.totalElapsed = totalElapsed;\n this.state.value = updates;\n\n return updates;\n }\n}\n","import { clamp } from '../utils/clamp';\nimport { now } from '../utils/now';\nimport { Scale } from './Scale';\n\nexport const SINE_PERIOD = Math.PI * 2 - 0.0001;\n\n/** Options for configuring a Sine oscillator. */\nexport type SineOptions = {\n /** Duration of one full cycle in milliseconds. */\n duration: number;\n};\n\n/** Snapshot of a Sine oscillator's internal state. */\nexport type SineState = {\n cycle: number;\n duration: number;\n prev: number;\n totalElapsed: number;\n value: number;\n};\n\nconst getInitialState = (duration: number): SineState => ({\n cycle: 0,\n duration,\n prev: now(),\n totalElapsed: 0,\n value: 0,\n});\n\n/**\n * Time-based sine wave oscillator that outputs values between -1 and 1.\n * @param opts - {@link SineOptions} for configuring the oscillator.\n */\nexport class Sine {\n state: SineState;\n protected _interpolator: Scale;\n\n constructor(opts: SineOptions) {\n const { duration } = opts;\n\n this._interpolator = new Scale({\n from: {\n min: 0,\n max: duration,\n },\n to: {\n min: 0,\n max: SINE_PERIOD,\n },\n });\n this.state = getInitialState(duration);\n }\n\n setDuration(duration: number) {\n this.state = {\n ...this.state,\n duration,\n };\n }\n\n reset(opts?: SineOptions) {\n const { duration } = {\n ...this.state,\n ...opts,\n };\n\n this.state = getInitialState(duration);\n }\n\n value() {\n return this.state.value;\n }\n\n next() {\n const {\n cycle,\n duration,\n prev,\n totalElapsed: prevTotalElapsed,\n } = this.state;\n const curr = now();\n const tickInterval = curr - prev;\n const totalElapsed = prevTotalElapsed + tickInterval;\n\n const updates = clamp(\n Math.sin(this._interpolator.scale(totalElapsed)),\n -1,\n 1,\n );\n\n if (cycle >= duration) {\n this.state.cycle = 0;\n } else {\n this.state.cycle = cycle + tickInterval;\n }\n\n this.state.prev = curr;\n this.state.totalElapsed = totalElapsed;\n this.state.value = updates;\n\n return updates;\n }\n}\n","export const SIXTY_FPS = 1000 / 60;\nexport const MS_IN_SECOND = 1000;\nexport const MS_IN_MINUTE = 60 * MS_IN_SECOND;\nexport const MS_IN_HOUR = MS_IN_MINUTE * 60;\n","import { MS_IN_SECOND, MS_IN_MINUTE, MS_IN_HOUR } from '../constants';\n\nexport type FPS = 15 | 30 | 60;\n\nexport enum TimeFormat {\n FPS = 'fps',\n HOURS = 'h',\n HZ = 'hz',\n MILLISECONDS = 'ms',\n MINUTES = 'm',\n SECONDS = 's',\n}\n\nexport type AvailableTimeFormats = `${TimeFormat}`;\n\nexport const FORMAT_IDENTIFIERS: AvailableTimeFormats[] = [\n TimeFormat.FPS,\n TimeFormat.HOURS,\n TimeFormat.HZ,\n TimeFormat.MILLISECONDS,\n TimeFormat.MINUTES,\n TimeFormat.SECONDS,\n]\n // Desc length sort so that `ms` matches prior to `m`\n .sort((a, b) => b.length - a.length);\n\ntype FormatGetter = (val: number) => number;\n\nconst FORMATTERS = new Map<AvailableTimeFormats, FormatGetter>([\n [TimeFormat.FPS, (val: number) => MS_IN_SECOND / val],\n [TimeFormat.HOURS, (val: number) => val * MS_IN_HOUR],\n [TimeFormat.HZ, (val: number) => (1 / val) * MS_IN_SECOND],\n [TimeFormat.MILLISECONDS, (val: number) => val],\n [TimeFormat.MINUTES, (val: number) => val * MS_IN_MINUTE],\n [TimeFormat.SECONDS, (val: number) => val * MS_IN_SECOND],\n]);\n\nconst sanitizeStringVal = (val: string) => val.toLocaleLowerCase().trim();\n\nconst parseStringValAndFormat = (val: string) => {\n for (let i = 0; i < FORMAT_IDENTIFIERS.length; i += 1) {\n const format = FORMAT_IDENTIFIERS[i];\n\n if (val.includes(format)) {\n const value = Number(val.replace(' ', '').replace(format, ''));\n\n return {\n format,\n value,\n };\n }\n }\n\n return {\n format: undefined,\n value: undefined,\n };\n};\n\nexport function ms(val: string | null | undefined): number | undefined;\nexport function ms(\n val: string | number | null | undefined,\n format?: AvailableTimeFormats | TimeFormat,\n): number | undefined;\n\n/**\n * Converts time format strings or numeric values to their corresponding value in milliseconds.\n * @param val - A string like `'60fps'`, `'2s'`, or a numeric value.\n * @param format - Explicit time format when `val` is a number.\n * @returns Milliseconds, or undefined if the input is invalid.\n */\nexport function ms(\n val: string | number | null | undefined,\n format?: AvailableTimeFormats | TimeFormat,\n): number | undefined {\n let parsedValue: number | null | undefined = null;\n let parsedFormat: AvailableTimeFormats = format || TimeFormat.MILLISECONDS;\n\n if (typeof val === 'string') {\n const parsed = parseStringValAndFormat(sanitizeStringVal(val));\n\n if (typeof parsed.value !== 'undefined') {\n parsedValue = parsed.value;\n }\n\n if (parsed.format) {\n parsedFormat = parsed.format;\n }\n } else {\n parsedValue = val;\n }\n\n if (\n typeof parsedValue === 'undefined' ||\n parsedValue === null ||\n Number.isNaN(parsedValue)\n ) {\n return undefined;\n }\n\n const formatter = FORMATTERS.get(parsedFormat);\n\n if (!formatter) {\n return undefined;\n }\n\n return formatter(parsedValue);\n}\n","import { SIXTY_FPS } from '../constants';\nimport { now } from '../utils/now';\n\n/** Snapshot of a running timer's internal state. */\nexport type TimerState = {\n initialTime: number;\n isRunning: boolean;\n iterations: number;\n prev: number;\n tickInterval: number;\n time: number;\n totalElapsed: number;\n};\n\nexport const getInitialState = (initialTime: number): TimerState => {\n return {\n initialTime,\n isRunning: false,\n iterations: -1,\n prev: 0,\n tickInterval: 0,\n time: initialTime,\n totalElapsed: 0,\n };\n};\n\nexport const processTimerState = (state: TimerState): TimerState | null => {\n const { time, prev, totalElapsed, iterations } = state;\n const curr = now();\n\n if (iterations === -1) {\n return {\n ...state,\n prev: curr,\n iterations: 0,\n };\n }\n\n const tickInterval = curr - prev;\n\n if (tickInterval <= time) {\n return null;\n }\n\n return {\n ...state,\n iterations: iterations + 1,\n prev: curr,\n tickInterval,\n totalElapsed: totalElapsed + tickInterval,\n };\n};\n\n/** Options for configuring a Metro timer. */\nexport type MetroOptions = {\n /** Interval between ticks in milliseconds. Defaults to ~16.67ms (60fps). */\n time?: number;\n};\n\nexport const parseOptions = (opts?: MetroOptions): Required<MetroOptions> => {\n return {\n time: SIXTY_FPS,\n ...opts,\n };\n};\n\n/** Callback invoked on each timer tick with the timer instance. */\nexport type TimerCallback<T extends Metro> = (timer: T) => void;\n\n/**\n * High-resolution recursive timer with variable interval, provides runtime metrics via callback for time-based calculations.\n * @param callback - {@link TimerCallback} called on each tick with the timer instance.\n * @param opts - {@link MetroOptions} for configuring the timer interval.\n */\nexport class Metro {\n state: TimerState;\n protected _listeners: TimerCallback<Metro>[];\n protected declare _timerId: ReturnType<typeof setTimeout> | number;\n\n constructor(callback: TimerCallback<Metro>, opts?: MetroOptions) {\n const { time } = parseOptions(opts);\n this.state = getInitialState(time);\n this._listeners = [callback];\n }\n\n protected asyncHandler(callback: () => void) {\n this._timerId = setTimeout(callback, SIXTY_FPS);\n }\n\n protected clearAsyncHandler() {\n clearTimeout(this._timerId);\n }\n\n stop = () => {\n const { totalElapsed } = this.state;\n this.reset();\n this.clearAsyncHandler();\n\n return totalElapsed;\n };\n\n reset = () => {\n const { initialTime } = this.state;\n this.state = getInitialState(initialTime);\n };\n\n setTime = (updatedTime = this.state.time) => {\n const time = Math.max(updatedTime, 0);\n\n this.state = {\n ...this.state,\n time,\n initialTime: time,\n };\n };\n\n run = () => {\n if (this.state.isRunning) {\n this.stop();\n }\n\n this.state = {\n ...this.state,\n isRunning: true,\n prev: now(),\n };\n\n const tick = () => {\n const updates = processTimerState(this.state);\n\n if (updates) {\n this.state = updates;\n this._listeners.forEach((listener) => {\n listener(this);\n });\n }\n\n if (this.state.isRunning) {\n this.asyncHandler(tick);\n }\n };\n\n tick();\n };\n}\n","import { ms, TimeFormat, type FPS } from '../utils/ms';\nimport { Metro, type TimerCallback, type MetroOptions } from './Metro';\n\n/** Options for configuring a Frames timer. */\nexport type FramesOptions = {\n /** Target frames per second (15, 30, or 60). Defaults to 60. */\n fps: FPS;\n};\n\nexport const DEFAULT_FPS: FPS = 60;\n\nexport const parseOptions = (opts?: FramesOptions): MetroOptions => {\n const { fps } = {\n fps: DEFAULT_FPS,\n ...opts,\n };\n\n return {\n time: ms(fps, TimeFormat.FPS),\n };\n};\n\n/**\n * Animation-loop timer that uses requestAnimationFrame when available.\n * @param callback - {@link TimerCallback} called on each frame tick.\n * @param opts - {@link FramesOptions} for configuring the target frame rate.\n */\nexport class Frames extends Metro {\n protected declare _timerId: ReturnType<typeof requestAnimationFrame>;\n\n constructor(callback: TimerCallback<Frames>, opts?: FramesOptions) {\n super(() => callback(this), parseOptions(opts));\n }\n\n protected asyncHandler(callback: () => void) {\n if (typeof window === 'undefined' || !('requestAnimationFrame' in window)) {\n super.asyncHandler(callback);\n } else {\n this._timerId = requestAnimationFrame(callback);\n }\n }\n\n protected clearAsyncHandler() {\n if (typeof window === 'undefined' || !('cancelAnimationFrame' in window)) {\n super.clearAsyncHandler();\n } else {\n cancelAnimationFrame(this._timerId);\n }\n }\n\n setFPS = (fps = DEFAULT_FPS) => {\n this.setTime(ms(fps, TimeFormat.FPS));\n };\n}\n","import { clamp } from './clamp';\n\n/**\n * Scales 0...1 by Euler's number to produce a natural feeling curve.\n * @param n - Input value (clamped to 0-1).\n * @returns The exponentially scaled value.\n */\nexport function expo(n: number): number {\n return Math.pow(clamp(n, 0, 1), Math.E);\n}\n"],"mappings":"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","names":["parseOptions","initialNow","parseOptions","updateStateFromOptions","getInitialState","TimeFormat","getInitialState","parseOptions","parseOptions"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prtcl/plonk",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Tiny library that provides timers, envelopes, and random generators",
5
5
  "author": "Cory O'Brien <cory@prtcl.cc>",
6
6
  "license": "MIT",