anim-engine 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,15 @@
1
+ /**
2
+ * Represents a value that can either be a static number or a function
3
+ * that returns a number. Functions are re-evaluated each time the value
4
+ * is resolved, allowing dynamic values that change over time.
5
+ */
1
6
  export type DynamicValue = number | (() => number);
7
+ /**
8
+ * Resolves a {@link DynamicValue} to a concrete number.
9
+ * If the value is a function, it is called and its return value is used.
10
+ * If the value is a number, it is returned directly.
11
+ *
12
+ * @param value - The dynamic value to resolve.
13
+ * @returns The resolved number.
14
+ */
2
15
  export declare const resolveValue: (value: DynamicValue) => number;
@@ -1,4 +1,12 @@
1
1
  //#region src/domain/resolve-value.ts
2
+ /**
3
+ * Resolves a {@link DynamicValue} to a concrete number.
4
+ * If the value is a function, it is called and its return value is used.
5
+ * If the value is a number, it is returned directly.
6
+ *
7
+ * @param value - The dynamic value to resolve.
8
+ * @returns The resolved number.
9
+ */
2
10
  var resolveValue = (value) => typeof value === "function" ? value() : value;
3
11
  //#endregion
4
12
  export { resolveValue };
@@ -1,8 +1,36 @@
1
+ /**
2
+ * A function that is called on each tick with the elapsed time in milliseconds.
3
+ *
4
+ * @param deltaMs - The time elapsed since the last tick in milliseconds.
5
+ */
1
6
  export type TickHandler = (deltaMs: number) => void;
7
+ /**
8
+ * A ticker that drives frame updates. It manages a list of {@link TickHandler}
9
+ * callbacks and distributes time updates to them on each frame.
10
+ */
2
11
  export type Ticker = {
12
+ /** Starts the ticker, beginning to dispatch updates to registered handlers. */
3
13
  start: () => void;
14
+ /** Stops the ticker, halting further dispatch of updates. */
4
15
  stop: () => void;
16
+ /**
17
+ * Manually advances the ticker by the given delta, dispatching to all
18
+ * registered handlers.
19
+ */
5
20
  update: (deltaMs: number) => void;
21
+ /** Registers a handler to receive tick updates. */
6
22
  add: (handler: TickHandler) => void;
23
+ /** Unregisters a previously registered handler. */
24
+ remove: (handler: TickHandler) => void;
25
+ };
26
+ /**
27
+ * A minimal ticker interface exposing only subscription capabilities.
28
+ * Useful for external tickers (e.g. from a game loop or an animation
29
+ * framework) where start/stop/update are managed externally.
30
+ */
31
+ export type ExternalTicker = {
32
+ /** Registers a handler to receive tick updates. */
33
+ add: (handler: TickHandler) => void;
34
+ /** Unregisters a previously registered handler. */
7
35
  remove: (handler: TickHandler) => void;
8
36
  };
@@ -1,5 +1,11 @@
1
- import { DynamicValue } from '../domain';
2
1
  import { KeyframeAnimationOptions, AnimationStatus } from './animation';
2
+ import { DynamicValue } from './resolve-value';
3
+ import { ExternalTicker } from './ticker';
4
+ /**
5
+ * A single layer in a timeline, describing when an animation plays.
6
+ * - `at`: The animation starts at this absolute point in time (in ms).
7
+ * - `gap`: The animation starts this many ms after the previous layer ends.
8
+ */
3
9
  export type TimelineLayer = {
4
10
  animation: KeyframeAnimationOptions;
5
11
  at: DynamicValue;
@@ -7,15 +13,54 @@ export type TimelineLayer = {
7
13
  animation: KeyframeAnimationOptions;
8
14
  gap: number;
9
15
  };
16
+ /**
17
+ * Callback hooks and options for a timeline animation.
18
+ */
19
+ export type TimelineCallbacks = {
20
+ /** Callback fired when the timeline starts playing. */
21
+ onStarted?: () => void;
22
+ /**
23
+ * Callback fired on each update with the current values and velocities
24
+ * of all layers in the timeline.
25
+ */
26
+ onUpdate?: (values: number[], velocities: number[]) => void;
27
+ /** Callback fired on each update with the current progress (0 to 1). */
28
+ onProgress?: (progress: number) => void;
29
+ /** Callback fired when the timeline ends. */
30
+ onEnded?: () => void;
31
+ /** Optional external ticker to drive the timeline. */
32
+ ticker?: ExternalTicker;
33
+ };
34
+ /**
35
+ * Represents a timeline animation instance that sequences multiple layers
36
+ * and can be controlled and queried for its aggregate state.
37
+ */
10
38
  export type Timeline = {
39
+ /** Plays the timeline from the current state. Returns a promise that resolves when the timeline ends. */
11
40
  play: () => Promise<void>;
41
+ /** Pauses the timeline if it is currently playing. */
12
42
  pause: () => void;
43
+ /** Resumes the timeline if it is currently paused. */
13
44
  resume: () => void;
45
+ /** Stops the timeline and resets its state. */
14
46
  stop: () => void;
47
+ /** Skips the timeline to its end state immediately. */
15
48
  skipToEnd: () => void;
16
- kill: () => void;
49
+ /** Sets the progress of the timeline to a specific value between 0 and 1. If playing, pauses. */
17
50
  setProgress: (value: number) => void;
51
+ /** The current progress of the timeline (0 to 1). */
18
52
  progress: number;
53
+ /**
54
+ * The current status of the timeline, which can be "playing", "paused", or "stopped".
55
+ * - "playing": The timeline is currently running.
56
+ * - "paused": The timeline is temporarily halted but can be resumed.
57
+ * - "stopped": The timeline has finished or has been stopped.
58
+ */
19
59
  status: AnimationStatus;
60
+ /** The total duration of the timeline in milliseconds. */
20
61
  durationMs: number;
62
+ /** The current values of all layers in the timeline. */
63
+ values: number[];
64
+ /** The current velocities of all layers in the timeline. */
65
+ velocities: number[];
21
66
  };
package/dist/index.d.ts CHANGED
@@ -7,4 +7,4 @@ export { createSpring } from './spring';
7
7
  export { lerpRgba, hexToRgba } from './lerp-rgba';
8
8
  export { getTicker } from './ticker';
9
9
  export { cubicBezier } from './domain';
10
- export type { EaseName, Interpolation, AnimationStatus, InterpolationStatus, DynamicValue, Animation, Keyframe, AnimationOptions, KeyframeAnimationOptions, TimelineLayer, Timeline, Ticker, LerpOptions, SmoothDampOptions, SpringOptions, RgbaTuple, } from './domain';
10
+ export type { EaseName, Interpolation, AnimationStatus, InterpolationStatus, DynamicValue, Animation, Keyframe, AnimationOptions, KeyframeAnimationOptions, TimelineLayer, Timeline, Ticker, LerpOptions, SmoothDampOptions, SpringOptions, RgbaTuple, ExternalTicker, } from './domain';
@@ -1,2 +1,14 @@
1
1
  import { Interpolation, LerpOptions } from '../domain';
2
- export declare const createLerp: (options: LerpOptions) => Interpolation;
2
+ /**
3
+ * Creates a linear interpolation that smoothly moves a value toward a
4
+ * target over a specified time constant. Uses exponential decay for a
5
+ * smooth, asymptotic approach.
6
+ *
7
+ * The interpolation automatically starts and runs until it reaches the
8
+ * target within the configured precision. The target is re-evaluated
9
+ * every frame, allowing it to change dynamically.
10
+ *
11
+ * @param options - Configuration options for the interpolation.
12
+ * @returns An {@link Interpolation} instance for controlling the lerp.
13
+ */
14
+ export declare const createLerp: ({ precision, onUpdate, onEnded, to, smoothTimeMs: rawSmoothTimeMs, ticker, }: LerpOptions) => Interpolation;
@@ -2,21 +2,29 @@ import { resolveValue } from "../domain/resolve-value.js";
2
2
  import { getTicker } from "../ticker/get-ticker.js";
3
3
  import { lerpStep } from "./step.js";
4
4
  //#region src/lerp/create-lerp.ts
5
- var createLerp = (options) => {
6
- const precision = options.precision ?? .01;
7
- const onUpdate = options.onUpdate;
8
- const onEnded = options.onEnded;
5
+ /**
6
+ * Creates a linear interpolation that smoothly moves a value toward a
7
+ * target over a specified time constant. Uses exponential decay for a
8
+ * smooth, asymptotic approach.
9
+ *
10
+ * The interpolation automatically starts and runs until it reaches the
11
+ * target within the configured precision. The target is re-evaluated
12
+ * every frame, allowing it to change dynamically.
13
+ *
14
+ * @param options - Configuration options for the interpolation.
15
+ * @returns An {@link Interpolation} instance for controlling the lerp.
16
+ */
17
+ var createLerp = ({ precision = .01, onUpdate, onEnded, to, smoothTimeMs: rawSmoothTimeMs, ticker = getTicker() }) => {
9
18
  const state = { current: 0 };
10
19
  let previousValue = 0;
11
20
  let currentVelocity = 0;
12
21
  let active = true;
13
- const ticker = getTicker();
14
- state.current = options.to();
22
+ state.current = to();
15
23
  previousValue = state.current;
16
24
  const update = (deltaMs) => {
17
25
  if (!active) return;
18
- const target = options.to();
19
- const smoothTimeMs = resolveValue(options.smoothTimeMs);
26
+ const target = to();
27
+ const smoothTimeMs = resolveValue(rawSmoothTimeMs);
20
28
  lerpStep(state, target, smoothTimeMs, deltaMs);
21
29
  currentVelocity = (state.current - previousValue) / (deltaMs / 1e3);
22
30
  previousValue = state.current;
@@ -28,7 +36,7 @@ var createLerp = (options) => {
28
36
  }
29
37
  };
30
38
  ticker.add(update);
31
- const start = () => {
39
+ const resume = () => {
32
40
  if (active) return;
33
41
  active = true;
34
42
  ticker.add(update);
@@ -37,20 +45,15 @@ var createLerp = (options) => {
37
45
  active = false;
38
46
  ticker.remove(update);
39
47
  };
40
- const kill = () => {
41
- active = false;
42
- ticker.remove(update);
43
- };
44
48
  return {
45
- start,
49
+ resume,
46
50
  stop,
47
- kill,
48
- setCurrentValue: (value) => {
51
+ setValue: (value) => {
49
52
  state.current = value;
50
53
  previousValue = value;
51
54
  currentVelocity = 0;
52
55
  },
53
- get currentValue() {
56
+ get value() {
54
57
  return state.current;
55
58
  },
56
59
  get velocity() {
@@ -1,2 +1,16 @@
1
1
  import { Interpolation, SmoothDampOptions } from '../domain';
2
- export declare const createSmoothDamp: (options: SmoothDampOptions) => Interpolation;
2
+ /**
3
+ * Creates a smooth damped interpolation that progressively moves a value
4
+ * toward a target with velocity that decreases as it approaches, producing
5
+ * a natural deceleration effect.
6
+ *
7
+ * Unlike a simple lerp, smooth damp respects an optional max speed and
8
+ * maintains velocity continuity, making it suitable for camera-relative
9
+ * movement, UI animations, and game object tracking.
10
+ *
11
+ * The target is re-evaluated every frame, allowing it to change dynamically.
12
+ *
13
+ * @param options - Configuration options for the smooth damp interpolation.
14
+ * @returns An {@link Interpolation} instance for controlling the smooth damp.
15
+ */
16
+ export declare const createSmoothDamp: ({ to, smoothTimeMs: rawSmoothTimeMs, maxSpeed: rawMaxSpeed, precision, onUpdate, onEnded, ticker, }: SmoothDampOptions) => Interpolation;
@@ -2,19 +2,42 @@ import { resolveValue } from "../domain/resolve-value.js";
2
2
  import { getTicker } from "../ticker/get-ticker.js";
3
3
  import { smoothDampStep } from "./step.js";
4
4
  //#region src/smooth-damp/create-smooth-damp.ts
5
- var createSmoothDamp = (options) => {
6
- const precision = options.precision ?? .01;
7
- const onUpdate = options.onUpdate;
8
- const onEnded = options.onEnded;
5
+ /**
6
+ * Creates a smooth damped interpolation that progressively moves a value
7
+ * toward a target with velocity that decreases as it approaches, producing
8
+ * a natural deceleration effect.
9
+ *
10
+ * Unlike a simple lerp, smooth damp respects an optional max speed and
11
+ * maintains velocity continuity, making it suitable for camera-relative
12
+ * movement, UI animations, and game object tracking.
13
+ *
14
+ * The target is re-evaluated every frame, allowing it to change dynamically.
15
+ *
16
+ * @param options - Configuration options for the smooth damp interpolation.
17
+ * @returns An {@link Interpolation} instance for controlling the smooth damp.
18
+ */
19
+ var createSmoothDamp = ({ to, smoothTimeMs: rawSmoothTimeMs, maxSpeed: rawMaxSpeed, precision = .01, onUpdate, onEnded, ticker = getTicker() }) => {
9
20
  const state = {
10
21
  current: 0,
11
22
  velocity: 0
12
23
  };
13
24
  let active = true;
14
- const ticker = getTicker();
15
- state.current = options.to();
25
+ state.current = to();
26
+ const update = (deltaMs) => {
27
+ if (!active) return;
28
+ const target = to();
29
+ const smoothTimeMs = resolveValue(rawSmoothTimeMs);
30
+ const maxSpeed = rawMaxSpeed !== void 0 ? resolveValue(rawMaxSpeed) : Infinity;
31
+ smoothDampStep(state, target, smoothTimeMs, maxSpeed, deltaMs);
32
+ onUpdate?.(state.current, state.velocity);
33
+ if (onEnded && Math.abs(state.current - target) < precision && Math.abs(state.velocity) < precision) {
34
+ state.current = target;
35
+ state.velocity = 0;
36
+ onEnded();
37
+ }
38
+ };
16
39
  ticker.add(update);
17
- const start = () => {
40
+ const resume = () => {
18
41
  if (active) return;
19
42
  active = true;
20
43
  ticker.add(update);
@@ -23,32 +46,14 @@ var createSmoothDamp = (options) => {
23
46
  active = false;
24
47
  ticker.remove(update);
25
48
  };
26
- const kill = () => {
27
- active = false;
28
- ticker.remove(update);
29
- };
30
- function update(deltaMs) {
31
- if (!active) return;
32
- const target = options.to();
33
- const smoothTimeMs = resolveValue(options.smoothTimeMs);
34
- const maxSpeed = options.maxSpeed !== void 0 ? resolveValue(options.maxSpeed) : Infinity;
35
- smoothDampStep(state, target, smoothTimeMs, maxSpeed, deltaMs);
36
- onUpdate?.(state.current, state.velocity);
37
- if (onEnded && Math.abs(state.current - target) < precision && Math.abs(state.velocity) < precision) {
38
- state.current = target;
39
- state.velocity = 0;
40
- onEnded();
41
- }
42
- }
43
49
  return {
44
- start,
50
+ resume,
45
51
  stop,
46
- kill,
47
- setCurrentValue: (value) => {
52
+ setValue: (value) => {
48
53
  state.current = value;
49
54
  state.velocity = 0;
50
55
  },
51
- get currentValue() {
56
+ get value() {
52
57
  return state.current;
53
58
  },
54
59
  get velocity() {
@@ -1,2 +1,13 @@
1
1
  import { Interpolation, SpringOptions } from '../domain';
2
- export declare const createSpring: (options: SpringOptions) => Interpolation;
2
+ /**
3
+ * Creates a spring-based interpolation that simulates mass-spring-damper
4
+ * physics, producing bouncy or elastic movement toward the target value.
5
+ *
6
+ * Uses Verlet integration for stable, energy-conserving simulation.
7
+ * Higher stiffness produces faster, snappier motion; higher damping
8
+ * reduces oscillation. The target is re-evaluated every frame.
9
+ *
10
+ * @param options - Configuration options for the spring interpolation.
11
+ * @returns An {@link Interpolation} instance for controlling the spring.
12
+ */
13
+ export declare const createSpring: ({ precision, onUpdate, onEnded, to: rawTo, stiffness: rawStiffness, damping: rawDamping, mass: rawMass, ticker, }: SpringOptions) => Interpolation;
@@ -2,22 +2,25 @@ import { resolveValue } from "../domain/resolve-value.js";
2
2
  import { getTicker } from "../ticker/get-ticker.js";
3
3
  import { verletStep } from "./verlet.js";
4
4
  //#region src/spring/create-spring.ts
5
- var createSpring = (options) => {
6
- const precision = options.precision ?? .01;
7
- const onUpdate = options.onUpdate;
8
- const onEnded = options.onEnded;
9
- const rawTo = options.to;
10
- const rawStiffness = options.stiffness ?? 180;
11
- const rawDamping = options.damping ?? 12;
12
- const rawMass = options.mass ?? 1;
5
+ /**
6
+ * Creates a spring-based interpolation that simulates mass-spring-damper
7
+ * physics, producing bouncy or elastic movement toward the target value.
8
+ *
9
+ * Uses Verlet integration for stable, energy-conserving simulation.
10
+ * Higher stiffness produces faster, snappier motion; higher damping
11
+ * reduces oscillation. The target is re-evaluated every frame.
12
+ *
13
+ * @param options - Configuration options for the spring interpolation.
14
+ * @returns An {@link Interpolation} instance for controlling the spring.
15
+ */
16
+ var createSpring = ({ precision = .01, onUpdate, onEnded, to: rawTo, stiffness: rawStiffness = 180, damping: rawDamping = 12, mass: rawMass = 1, ticker = getTicker() }) => {
13
17
  const state = {
14
18
  current: rawTo(),
15
19
  velocity: 0
16
20
  };
17
21
  let active = true;
18
- const ticker = getTicker();
19
22
  ticker.add(update);
20
- const start = () => {
23
+ const resume = () => {
21
24
  if (active) return;
22
25
  active = true;
23
26
  ticker.add(update);
@@ -26,10 +29,6 @@ var createSpring = (options) => {
26
29
  active = false;
27
30
  ticker.remove(update);
28
31
  };
29
- const kill = () => {
30
- active = false;
31
- ticker.remove(update);
32
- };
33
32
  function update(deltaMs) {
34
33
  if (!active) return;
35
34
  const target = rawTo();
@@ -45,14 +44,13 @@ var createSpring = (options) => {
45
44
  }
46
45
  }
47
46
  return {
48
- start,
47
+ resume,
49
48
  stop,
50
- kill,
51
- setCurrentValue: (value) => {
49
+ setValue: (value) => {
52
50
  state.current = value;
53
51
  state.velocity = 0;
54
52
  },
55
- get currentValue() {
53
+ get value() {
56
54
  return state.current;
57
55
  },
58
56
  get velocity() {
@@ -1,5 +1,13 @@
1
1
  import { Ticker } from '../domain';
2
- /** Returns the default ticker singleton. Created lazily on first access. */
2
+ /**
3
+ * Returns the application-wide default ticker singleton.
4
+ *
5
+ * The ticker is created lazily on first access and reused for all
6
+ * subsequent calls. It drives all animations and interpolations that
7
+ * don't specify an external ticker.
8
+ *
9
+ * @returns The default {@link Ticker} instance.
10
+ */
3
11
  export declare const getTicker: () => Ticker;
4
12
  /**
5
13
  * Create a ticker that drives active animations.
@@ -1,6 +1,14 @@
1
1
  //#region src/ticker/get-ticker.ts
2
2
  var singleton;
3
- /** Returns the default ticker singleton. Created lazily on first access. */
3
+ /**
4
+ * Returns the application-wide default ticker singleton.
5
+ *
6
+ * The ticker is created lazily on first access and reused for all
7
+ * subsequent calls. It drives all animations and interpolations that
8
+ * don't specify an external ticker.
9
+ *
10
+ * @returns The default {@link Ticker} instance.
11
+ */
4
12
  var getTicker = () => {
5
13
  if (!singleton) singleton = createTicker();
6
14
  return singleton;
@@ -1,6 +1,16 @@
1
- import { TimelineLayer, Timeline } from '../domain';
2
- export declare const createTimeline: (layers: TimelineLayer[], options?: {
3
- onStarted?: () => void;
4
- onProgress?: (progress: number) => void;
5
- onEnded?: () => void;
6
- }) => Timeline;
1
+ import { TimelineLayer, Timeline, TimelineCallbacks, ExternalTicker } from '../domain';
2
+ /**
3
+ * Creates a timeline animation that sequences multiple keyframe animation
4
+ * layers, each starting at a specified time or gap after the previous layer.
5
+ *
6
+ * The timeline aggregates all layers into a single controllable animation
7
+ * with its own play/pause/resume/stop semantics and returns the combined
8
+ * values and velocities of all layers on each update.
9
+ *
10
+ * @param layers - An array of {@link TimelineLayer} configs describing each
11
+ * animation in the sequence and when it should play.
12
+ * @param callbacks - Optional callback hooks and configuration.
13
+ * @param ticker - An optional external ticker. Defaults to the global ticker.
14
+ * @returns A {@link Timeline} instance for controlling the sequenced animation.
15
+ */
16
+ export declare const createTimeline: (layers: TimelineLayer[], { onStarted, onUpdate, onEnded, onProgress }?: TimelineCallbacks, ticker?: ExternalTicker) => Timeline;
@@ -38,17 +38,40 @@ var buildFromConfigs = (rawLayers) => {
38
38
  totalDurationMs: Math.max(0, ...activeLayers.map((l) => l.endAt))
39
39
  };
40
40
  };
41
- var createTimeline = (layers, options) => {
42
- const { onStarted, onEnded, onProgress = noOp } = options ?? {};
41
+ /**
42
+ * Creates a timeline animation that sequences multiple keyframe animation
43
+ * layers, each starting at a specified time or gap after the previous layer.
44
+ *
45
+ * The timeline aggregates all layers into a single controllable animation
46
+ * with its own play/pause/resume/stop semantics and returns the combined
47
+ * values and velocities of all layers on each update.
48
+ *
49
+ * @param layers - An array of {@link TimelineLayer} configs describing each
50
+ * animation in the sequence and when it should play.
51
+ * @param callbacks - Optional callback hooks and configuration.
52
+ * @param ticker - An optional external ticker. Defaults to the global ticker.
53
+ * @returns A {@link Timeline} instance for controlling the sequenced animation.
54
+ */
55
+ var createTimeline = (layers, { onStarted, onUpdate, onEnded, onProgress = noOp } = {}, ticker = getTicker()) => {
43
56
  const rawLayers = layers;
44
57
  let state = buildFromConfigs(rawLayers);
45
58
  let activeLayers = state.activeLayers;
46
59
  let totalDurationMs = state.totalDurationMs;
60
+ let valuesCache = [];
61
+ let velocitiesCache = [];
62
+ const syncValues = () => {
63
+ valuesCache.length = activeLayers.length;
64
+ velocitiesCache.length = activeLayers.length;
65
+ for (let i = 0; i < activeLayers.length; i++) {
66
+ valuesCache[i] = activeLayers[i].runner.velocity;
67
+ velocitiesCache[i] = activeLayers[i].runner.velocity;
68
+ }
69
+ };
70
+ syncValues();
47
71
  let timelineStatus = "stopped";
48
72
  let elapsedMs = 0;
49
73
  let resolvePromise;
50
74
  let remainingLayers = activeLayers.length;
51
- const ticker = getTicker();
52
75
  const finish = () => {
53
76
  timelineStatus = "stopped";
54
77
  ticker.remove(update);
@@ -71,15 +94,19 @@ var createTimeline = (layers, options) => {
71
94
  }
72
95
  }
73
96
  }
97
+ syncValues();
98
+ onUpdate?.(valuesCache, velocitiesCache);
74
99
  onProgress(totalDurationMs > 0 ? Math.min(elapsedMs / totalDurationMs, 1) : 1);
75
100
  if (remainingLayers <= 0) finish();
76
101
  };
77
102
  const play = () => {
78
- if (timelineStatus === "dead") throw new Error("Cannot play a dead timeline");
79
103
  state = buildFromConfigs(rawLayers);
80
104
  activeLayers = state.activeLayers;
81
105
  totalDurationMs = state.totalDurationMs;
82
106
  remainingLayers = activeLayers.length;
107
+ valuesCache = [];
108
+ velocitiesCache = [];
109
+ syncValues();
83
110
  elapsedMs = 0;
84
111
  const promise = new Promise((resolve) => {
85
112
  resolvePromise = resolve;
@@ -111,17 +138,13 @@ var createTimeline = (layers, options) => {
111
138
  layer.runner.evaluate(1);
112
139
  layer.runner.onEnded?.();
113
140
  }
141
+ syncValues();
114
142
  timelineStatus = "stopped";
115
143
  ticker.remove(update);
116
144
  onEnded?.();
117
145
  resolvePromise?.();
118
146
  resolvePromise = void 0;
119
147
  };
120
- const kill = () => {
121
- timelineStatus = "dead";
122
- ticker.remove(update);
123
- resolvePromise = void 0;
124
- };
125
148
  const setProgress = (value) => {
126
149
  if (timelineStatus === "playing") pause();
127
150
  elapsedMs = Math.max(0, Math.min(1, value)) * totalDurationMs;
@@ -136,6 +159,7 @@ var createTimeline = (layers, options) => {
136
159
  layer.runner.evaluate(localProgress);
137
160
  layer.ended = localProgress >= 1;
138
161
  }
162
+ syncValues();
139
163
  remainingLayers = activeLayers.filter((l) => !l.ended).length;
140
164
  };
141
165
  return {
@@ -144,11 +168,16 @@ var createTimeline = (layers, options) => {
144
168
  resume,
145
169
  stop,
146
170
  skipToEnd,
147
- kill,
148
171
  setProgress,
149
172
  get progress() {
150
173
  return totalDurationMs > 0 ? Math.min(elapsedMs / totalDurationMs, 1) : 1;
151
174
  },
175
+ get values() {
176
+ return valuesCache;
177
+ },
178
+ get velocities() {
179
+ return velocitiesCache;
180
+ },
152
181
  get status() {
153
182
  return timelineStatus;
154
183
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anim-engine",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "description": "JavaScript library for animating numbers",
6
6
  "license": "MIT",