physics-animator 0.16.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,19 +12,20 @@ Why use this over other animation systems?
12
12
 
13
13
  This library focuses on simplicity and correctness – I've generally run into design troubles with popular animation libraries like framer motion: for example complex framer animations become convoluted and don't correctly handled interruptions without discontinuities in velocity
14
14
 
15
- For example in react, to animate opacity we could do
15
+ For example in react, to animate DOM opacity we could do
16
16
 
17
17
  ```tsx
18
18
  useSpringValue(
19
- { initial: 0, target: 1, duration_s: 0.8 },
20
- value => el.style.opacity = value
19
+ 1.0, // target
20
+ { duration_s: 0.8 },
21
+ value => el.style.opacity = value // onChange
21
22
  )
22
23
  ```
23
24
 
24
25
  Or via state
25
26
 
26
27
  ```tsx
27
- const opacitySpring = useSpringState({ initial: 0, duration_s: 0.8, target: opacity })
28
+ const opacitySpring = useSpringState(opacity, { duration_s: 0.8 })
28
29
 
29
30
  return <div style={{ opacity: opacitySpring }} />
30
31
  ```
@@ -32,8 +33,8 @@ return <div style={{ opacity: opacitySpring }} />
32
33
  It works with arrays and objects
33
34
 
34
35
  ```tsx
35
- const rgb = useSpringState({ initial: [0, 0, 0], target: [1, 0, 0], duration_s: 0.8 })
36
- const xy = useSpringState({ initial: { x: 0, y: 0 }, target: {x: mouse.x, y: mouse.y}, duration_s: 0.1 })
36
+ const rgb = useSpringState([1, 0, 0], { initial: [0, 0, 0], duration_s: 0.8 })
37
+ const xy = useSpringState({x: mouse.x, y: mouse.y})
37
38
  ```
38
39
 
39
40
  Outside of react we use the animator object
@@ -14,12 +14,11 @@ const useSpringValue_js_1 = require("./useSpringValue.js");
14
14
  *
15
15
  * See {@link useSpringValue} for a version that does not cause re-renders.
16
16
  */
17
- function useSpringState(options) {
18
- const [state, setState] = (0, react_1.useState)(options.initial);
19
- (0, useSpringValue_js_1.useSpringValue)({
20
- ...options,
21
- initial: options.initial,
22
- target: options.target,
23
- }, setState);
17
+ function useSpringState(value, options = {
18
+ duration_s: 0.5,
19
+ }) {
20
+ // type N = WidenNumber<T>;
21
+ const [state, setState] = (0, react_1.useState)(value);
22
+ (0, useSpringValue_js_1.useSpringValue)(value, options, setState);
24
23
  return state;
25
24
  }
@@ -4,35 +4,16 @@ exports.useSpringValue = useSpringValue;
4
4
  const use_initializer_1 = require("use-initializer");
5
5
  const useAnimator_js_1 = require("./useAnimator.js");
6
6
  const react_1 = require("react");
7
- /**
8
- * A value that animates to a target value using a spring animation.
9
- * This will **not** cause a re-render when the value changes.
10
- *
11
- * Usage example:
12
- * ```tsx
13
- * useSpringValue(
14
- * { initial: 0, target: 1, duration_s: 0.8 },
15
- * // onChange
16
- * value => el.style.opacity = value
17
- * );
18
- * ```
19
- *
20
- * See {@link useSpringState} for a version that does cause re-renders.
21
- */
22
- function useSpringValue(options, onChange) {
7
+ function useSpringValue(value, optionsOrOnChange, maybeOnChange) {
8
+ const options = typeof optionsOrOnChange === 'function'
9
+ ? { duration_s: 0.5 }
10
+ : optionsOrOnChange;
11
+ const onChange = typeof optionsOrOnChange === 'function'
12
+ ? optionsOrOnChange
13
+ : maybeOnChange;
23
14
  const animator = (0, useAnimator_js_1.useAnimator)(options.animator);
24
- const springValue = (0, use_initializer_1.useInitializer)(() => {
25
- return {
26
- value: structuredClone(options.initial),
27
- };
28
- });
29
- (0, react_1.useEffect)(() => {
30
- let remove = animator.onChange(springValue, () => {
31
- onChange(springValue.value);
32
- }).remove;
33
- return () => {
34
- remove();
35
- };
36
- }, [springValue, onChange]);
37
- animator.springTo(springValue, { value: options.target }, options);
15
+ const springObject = (0, use_initializer_1.useInitializer)(() => ({ value: options.initial ?? value }));
16
+ (0, react_1.useEffect)(() => animator.onChange(springObject, () => onChange(springObject.value)).remove // return the cleanup function
17
+ , [springObject, onChange]);
18
+ animator.springTo(springObject, { value }, options);
38
19
  }
@@ -11,12 +11,11 @@ import { useSpringValue } from "./useSpringValue.js";
11
11
  *
12
12
  * See {@link useSpringValue} for a version that does not cause re-renders.
13
13
  */
14
- export function useSpringState(options) {
15
- const [state, setState] = useState(options.initial);
16
- useSpringValue({
17
- ...options,
18
- initial: options.initial,
19
- target: options.target,
20
- }, setState);
14
+ export function useSpringState(value, options = {
15
+ duration_s: 0.5,
16
+ }) {
17
+ // type N = WidenNumber<T>;
18
+ const [state, setState] = useState(value);
19
+ useSpringValue(value, options, setState);
21
20
  return state;
22
21
  }
@@ -1,35 +1,16 @@
1
1
  import { useInitializer } from "use-initializer";
2
2
  import { useAnimator } from "./useAnimator.js";
3
3
  import { useEffect } from "react";
4
- /**
5
- * A value that animates to a target value using a spring animation.
6
- * This will **not** cause a re-render when the value changes.
7
- *
8
- * Usage example:
9
- * ```tsx
10
- * useSpringValue(
11
- * { initial: 0, target: 1, duration_s: 0.8 },
12
- * // onChange
13
- * value => el.style.opacity = value
14
- * );
15
- * ```
16
- *
17
- * See {@link useSpringState} for a version that does cause re-renders.
18
- */
19
- export function useSpringValue(options, onChange) {
4
+ export function useSpringValue(value, optionsOrOnChange, maybeOnChange) {
5
+ const options = typeof optionsOrOnChange === 'function'
6
+ ? { duration_s: 0.5 }
7
+ : optionsOrOnChange;
8
+ const onChange = typeof optionsOrOnChange === 'function'
9
+ ? optionsOrOnChange
10
+ : maybeOnChange;
20
11
  const animator = useAnimator(options.animator);
21
- const springValue = useInitializer(() => {
22
- return {
23
- value: structuredClone(options.initial),
24
- };
25
- });
26
- useEffect(() => {
27
- let remove = animator.onChange(springValue, () => {
28
- onChange(springValue.value);
29
- }).remove;
30
- return () => {
31
- remove();
32
- };
33
- }, [springValue, onChange]);
34
- animator.springTo(springValue, { value: options.target }, options);
12
+ const springObject = useInitializer(() => ({ value: options.initial ?? value }));
13
+ useEffect(() => animator.onChange(springObject, () => onChange(springObject.value)).remove // return the cleanup function
14
+ , [springObject, onChange]);
15
+ animator.springTo(springObject, { value }, options);
35
16
  }
@@ -53,21 +53,8 @@ export declare class Animator {
53
53
  easeInOutTo<Obj>(object: Obj, target: Partial<Public<Obj>>, duration_s: number): void;
54
54
  easeInTo<Obj>(object: Obj, target: Partial<Public<Obj>>, duration_s: number): void;
55
55
  easeOutTo<Obj>(object: Obj, target: Partial<Public<Obj>>, duration_s: number): void;
56
- onCompleteField<Obj, Name extends keyof Obj>(object: Obj, field: Name, callback: (object: Obj, field: Name) => void, once?: 'once'): {
57
- priority: number;
58
- listener: (event: {
59
- object: any;
60
- field: FieldKey;
61
- }) => void;
62
- remove: () => void;
63
- };
64
- onComplete<Obj>(object: Obj, callback: (object: Obj) => void, once?: 'once'): {
65
- priority: number;
66
- listener: (event: {
67
- object: any;
68
- }) => void;
69
- remove: () => void;
70
- };
56
+ onCompleteField<Obj, Name extends keyof Obj>(object: Obj, field: Name, callback: (object: Obj, field: Name) => void, once?: 'once'): EventSignal.Listener;
57
+ onComplete<Obj>(object: Obj, callback: (object: Obj) => void, once?: 'once'): EventSignal.Listener;
71
58
  /**
72
59
  * Execute a callback when a specific field of an object is changed by the animator
73
60
  */
@@ -80,20 +67,8 @@ export declare class Animator {
80
67
  onChange<Obj>(object: Obj, callback: (object: Obj) => void): {
81
68
  remove: () => void;
82
69
  };
83
- onBeforeStep(callback: (dt_s: number) => void): {
84
- priority: number;
85
- listener: (event: {
86
- dt_s: number;
87
- }) => void;
88
- remove: () => void;
89
- };
90
- onAfterStep(callback: (dt_s: number) => void): {
91
- priority: number;
92
- listener: (event: {
93
- dt_s: number;
94
- }) => void;
95
- remove: () => void;
96
- };
70
+ onBeforeStep(callback: (dt_s: number) => void): EventSignal.Listener;
71
+ onAfterStep(callback: (dt_s: number) => void): EventSignal.Listener;
97
72
  step(dt_s: number): void;
98
73
  private t_last;
99
74
  tick(): number;
@@ -1,6 +1,5 @@
1
1
  import { Animator } from "../Animator.js";
2
2
  import { SpringParameters } from "../animators/SpringAnimator.js";
3
- type WidenNumber<T> = T extends number ? number : T;
4
3
  /**
5
4
  * A value that animates to a target value using a spring animation.
6
5
  * This **will** cause a re-render when the value changes.
@@ -14,9 +13,7 @@ type WidenNumber<T> = T extends number ? number : T;
14
13
  */
15
14
  export declare function useSpringState<T extends number | number[] | {
16
15
  [field: PropertyKey]: number;
17
- }>(options: {
16
+ }>(value: T, options?: {
18
17
  animator?: Animator;
19
- initial: T;
20
- target: T;
21
- } & SpringParameters): WidenNumber<T>;
22
- export {};
18
+ initial?: T;
19
+ } & SpringParameters): T;
@@ -1,5 +1,9 @@
1
1
  import { Animator } from "../Animator.js";
2
2
  import { SpringParameters } from "../animators/SpringAnimator.js";
3
+ type SpringOptions<T> = {
4
+ animator?: Animator;
5
+ initial?: T;
6
+ } & SpringParameters;
3
7
  /**
4
8
  * A value that animates to a target value using a spring animation.
5
9
  * This will **not** cause a re-render when the value changes.
@@ -7,18 +11,24 @@ import { SpringParameters } from "../animators/SpringAnimator.js";
7
11
  * Usage example:
8
12
  * ```tsx
9
13
  * useSpringValue(
10
- * { initial: 0, target: 1, duration_s: 0.8 },
14
+ * 1,
15
+ * { initial: 0, duration_s: 0.8 },
11
16
  * // onChange
12
17
  * value => el.style.opacity = value
13
18
  * );
14
19
  * ```
15
20
  *
21
+ * Or with default options:
22
+ * ```tsx
23
+ * useSpringValue(1, value => el.style.opacity = value);
24
+ * ```
25
+ *
16
26
  * See {@link useSpringState} for a version that does cause re-renders.
17
27
  */
18
28
  export declare function useSpringValue<T extends number | number[] | {
19
29
  [field: PropertyKey]: number;
20
- }>(options: {
21
- animator?: Animator;
22
- initial: T;
23
- target: T;
24
- } & SpringParameters, onChange: (value: T) => void): void;
30
+ }>(value: T, onChange: (value: T) => void): void;
31
+ export declare function useSpringValue<T extends number | number[] | {
32
+ [field: PropertyKey]: number;
33
+ }>(value: T, options: SpringOptions<T>, onChange: (value: T) => void): void;
34
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "physics-animator",
3
- "version": "0.16.0",
3
+ "version": "1.0.0",
4
4
  "author": "haxiomic (George Corney)",
5
5
  "license": "MIT",
6
6
  "description": "A TypeScript animation system grounded in physics with three.js and react support.",
@@ -47,7 +47,7 @@
47
47
  "typescript": "^5.0.0"
48
48
  },
49
49
  "dependencies": {
50
- "@haxiomic/event-signal": "^1.1.0",
50
+ "@haxiomic/event-signal": "^1.2.0",
51
51
  "use-initializer": "^1.1.0"
52
52
  },
53
53
  "peerDependencies": {