coily 0.1.1 → 0.3.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/dist/index.cjs +47 -9
- package/dist/index.d.ts +19 -6
- package/dist/index.js +39 -8
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -17,7 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
}
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
21
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
29
|
|
|
23
30
|
// src/index.ts
|
|
@@ -51,13 +58,14 @@ var getArrivalFunction = (behavior) => {
|
|
|
51
58
|
return result;
|
|
52
59
|
};
|
|
53
60
|
var createSpringImpl = (initial, config, options) => {
|
|
61
|
+
var _a, _b, _c;
|
|
54
62
|
let state = "resting";
|
|
55
63
|
let velocity = 0;
|
|
56
64
|
let target = initial;
|
|
57
65
|
let value = initial;
|
|
58
|
-
const restingDistance = Math.max((options == null ? void 0 : options.restingDistance)
|
|
59
|
-
const restingVelocity = Math.max((options == null ? void 0 : options.restingVelocity)
|
|
60
|
-
const arrivalFunction = getArrivalFunction((options == null ? void 0 : options.arrivalBehavior)
|
|
66
|
+
const restingDistance = Math.max((_a = options == null ? void 0 : options.restingDistance) != null ? _a : 1e-4, 0);
|
|
67
|
+
const restingVelocity = Math.max((_b = options == null ? void 0 : options.restingVelocity) != null ? _b : 1e-4, 0);
|
|
68
|
+
const arrivalFunction = getArrivalFunction((_c = options == null ? void 0 : options.arrivalBehavior) != null ? _c : 1);
|
|
61
69
|
const emitter = (0, import_mitt.default)();
|
|
62
70
|
const { emit, ...emitterApi } = emitter;
|
|
63
71
|
const spring = {
|
|
@@ -67,26 +75,38 @@ var createSpringImpl = (initial, config, options) => {
|
|
|
67
75
|
},
|
|
68
76
|
set target(val) {
|
|
69
77
|
target = val;
|
|
70
|
-
if (Math.abs(value - target) > restingDistance) {
|
|
78
|
+
if (state !== "moving" && Math.abs(value - target) > restingDistance) {
|
|
71
79
|
state = "moving";
|
|
72
80
|
emit("update:state", state);
|
|
73
81
|
}
|
|
74
82
|
},
|
|
83
|
+
getTarget: () => target,
|
|
75
84
|
get value() {
|
|
76
85
|
return value;
|
|
77
86
|
},
|
|
87
|
+
getValue: () => value,
|
|
78
88
|
get velocity() {
|
|
79
89
|
return velocity;
|
|
80
90
|
},
|
|
91
|
+
getVelocity: () => velocity,
|
|
81
92
|
get state() {
|
|
82
93
|
return state;
|
|
83
94
|
},
|
|
95
|
+
getState: () => state,
|
|
84
96
|
get config() {
|
|
85
97
|
return config;
|
|
86
98
|
},
|
|
87
99
|
set config(value2) {
|
|
88
100
|
config = value2;
|
|
89
101
|
},
|
|
102
|
+
getConfig: () => config,
|
|
103
|
+
jumpTo: (_value, killVelocity = true) => {
|
|
104
|
+
value = _value;
|
|
105
|
+
if (killVelocity) {
|
|
106
|
+
velocity = 0;
|
|
107
|
+
}
|
|
108
|
+
state = Math.abs(velocity) > restingVelocity || Math.abs(value - target) > restingDistance ? "moving" : "resting";
|
|
109
|
+
},
|
|
90
110
|
freeze: () => {
|
|
91
111
|
state = "frozen";
|
|
92
112
|
emit("update:state", state);
|
|
@@ -96,13 +116,15 @@ var createSpringImpl = (initial, config, options) => {
|
|
|
96
116
|
emit("update:state", state);
|
|
97
117
|
}
|
|
98
118
|
};
|
|
119
|
+
const tension = -config.tension * 1e-6;
|
|
120
|
+
const friction = -config.friction * 1e-3;
|
|
99
121
|
const simulate = (deltaTime) => {
|
|
100
122
|
if (state === "moving") {
|
|
101
123
|
const iterations = Math.ceil(deltaTime);
|
|
102
124
|
for (let n = 0; n < iterations; n++) {
|
|
103
125
|
const previousDelta = value - target;
|
|
104
|
-
const springForce =
|
|
105
|
-
const dampingForce =
|
|
126
|
+
const springForce = tension * previousDelta;
|
|
127
|
+
const dampingForce = friction * velocity;
|
|
106
128
|
const acceleration = (springForce + dampingForce) / config.mass;
|
|
107
129
|
velocity = velocity + acceleration;
|
|
108
130
|
value = value + velocity;
|
|
@@ -161,7 +183,12 @@ var createSpringChainImpl = (initial, links, config, options) => {
|
|
|
161
183
|
if (typeof link === "number") {
|
|
162
184
|
spring.target = previousSpring.value + link;
|
|
163
185
|
} else {
|
|
164
|
-
spring.target = link(
|
|
186
|
+
spring.target = link(
|
|
187
|
+
previousSpring.value,
|
|
188
|
+
previousSpring.target,
|
|
189
|
+
spring.value,
|
|
190
|
+
spring.target
|
|
191
|
+
);
|
|
165
192
|
}
|
|
166
193
|
targets[index + 1] = spring.target;
|
|
167
194
|
states[index + 1] = spring.state;
|
|
@@ -169,7 +196,11 @@ var createSpringChainImpl = (initial, links, config, options) => {
|
|
|
169
196
|
state = "moving";
|
|
170
197
|
}
|
|
171
198
|
} else {
|
|
172
|
-
const [spring, simulate2] = createSpringImpl(
|
|
199
|
+
const [spring, simulate2] = createSpringImpl(
|
|
200
|
+
typeof link === "number" ? previousSpring.value + link : link(previousSpring.value, previousSpring.target),
|
|
201
|
+
config,
|
|
202
|
+
options
|
|
203
|
+
);
|
|
173
204
|
springs.push(spring);
|
|
174
205
|
simulateFns.push(simulate2);
|
|
175
206
|
targets[index + 1] = spring.target;
|
|
@@ -224,9 +255,11 @@ var createSpringChainImpl = (initial, links, config, options) => {
|
|
|
224
255
|
currentTarget = val;
|
|
225
256
|
updateChainState(currentTarget, currentLinks);
|
|
226
257
|
},
|
|
258
|
+
getTarget: () => targets[0],
|
|
227
259
|
get targets() {
|
|
228
260
|
return targets;
|
|
229
261
|
},
|
|
262
|
+
getTargets: () => targets,
|
|
230
263
|
get links() {
|
|
231
264
|
return links;
|
|
232
265
|
},
|
|
@@ -237,18 +270,23 @@ var createSpringChainImpl = (initial, links, config, options) => {
|
|
|
237
270
|
get config() {
|
|
238
271
|
return config;
|
|
239
272
|
},
|
|
273
|
+
getConfig: () => config,
|
|
240
274
|
get values() {
|
|
241
275
|
return values;
|
|
242
276
|
},
|
|
277
|
+
getValues: () => values,
|
|
243
278
|
get velocities() {
|
|
244
279
|
return velocities;
|
|
245
280
|
},
|
|
281
|
+
getVelocities: () => velocities,
|
|
246
282
|
get state() {
|
|
247
283
|
return state;
|
|
248
284
|
},
|
|
285
|
+
getState: () => state,
|
|
249
286
|
get states() {
|
|
250
287
|
return states;
|
|
251
288
|
},
|
|
289
|
+
getStates: () => states,
|
|
252
290
|
freeze: () => {
|
|
253
291
|
for (const spring of springs) {
|
|
254
292
|
spring.freeze();
|
package/dist/index.d.ts
CHANGED
|
@@ -5,46 +5,59 @@ interface SpringConfig {
|
|
|
5
5
|
tension: number;
|
|
6
6
|
friction: number;
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
type SpringArrivalBehavior = 'bounce' | 'clamp' | 'none' | number | ((velocity: number) => number);
|
|
9
9
|
interface SpringOptions {
|
|
10
10
|
restingDistance?: number;
|
|
11
11
|
restingVelocity?: number;
|
|
12
12
|
arrivalBehavior?: SpringArrivalBehavior;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
type SpringState = 'moving' | 'frozen' | 'resting';
|
|
15
|
+
type SpringEmitter = Emitter<{
|
|
16
16
|
'update:value': number;
|
|
17
17
|
'update:state': SpringState;
|
|
18
18
|
'*': number | SpringState;
|
|
19
19
|
}>;
|
|
20
20
|
interface Spring extends Omit<SpringEmitter, 'emit'> {
|
|
21
21
|
target: number;
|
|
22
|
+
readonly getTarget: () => number;
|
|
22
23
|
config: Readonly<SpringConfig>;
|
|
24
|
+
readonly getConfig: () => Readonly<SpringConfig>;
|
|
23
25
|
readonly value: number;
|
|
26
|
+
readonly getValue: () => number;
|
|
24
27
|
readonly velocity: number;
|
|
28
|
+
readonly getVelocity: () => number;
|
|
25
29
|
readonly state: SpringState;
|
|
30
|
+
readonly getState: () => SpringState;
|
|
31
|
+
readonly jumpTo: (value: number, killVelocity?: boolean) => void;
|
|
26
32
|
readonly freeze: () => void;
|
|
27
33
|
readonly unfreeze: () => void;
|
|
28
34
|
}
|
|
29
|
-
|
|
35
|
+
type SimulateFn = (delta: number) => void;
|
|
30
36
|
interface StandaloneSpring extends Spring {
|
|
31
37
|
readonly simulate: SimulateFn;
|
|
32
38
|
}
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
type SpringChainLinkGetter = number | ((previousValue: number, previousTarget: number, currentValue?: number, currentTarget?: number) => number);
|
|
40
|
+
type SpringChainEmitter = Emitter<{
|
|
35
41
|
'update:value': number[];
|
|
36
42
|
'update:state': SpringState;
|
|
37
43
|
'*': number[] | SpringState;
|
|
38
44
|
}>;
|
|
39
45
|
interface SpringChain extends Omit<SpringChainEmitter, 'emit'> {
|
|
40
46
|
target: number;
|
|
47
|
+
readonly getTarget: () => number;
|
|
41
48
|
links: SpringChainLinkGetter[];
|
|
42
49
|
config: Readonly<SpringConfig>;
|
|
50
|
+
readonly getConfig: () => Readonly<SpringConfig>;
|
|
43
51
|
readonly targets: ReadonlyArray<number>;
|
|
52
|
+
readonly getTargets: () => ReadonlyArray<number>;
|
|
44
53
|
readonly values: ReadonlyArray<number>;
|
|
54
|
+
readonly getValues: () => ReadonlyArray<number>;
|
|
45
55
|
readonly velocities: ReadonlyArray<number>;
|
|
56
|
+
readonly getVelocities: () => ReadonlyArray<number>;
|
|
46
57
|
readonly state: SpringState;
|
|
58
|
+
readonly getState: () => SpringState;
|
|
47
59
|
readonly states: ReadonlyArray<SpringState>;
|
|
60
|
+
readonly getStates: () => ReadonlyArray<SpringState>;
|
|
48
61
|
readonly freeze: () => void;
|
|
49
62
|
readonly unfreeze: () => void;
|
|
50
63
|
}
|
package/dist/index.js
CHANGED
|
@@ -20,13 +20,14 @@ var getArrivalFunction = (behavior) => {
|
|
|
20
20
|
return result;
|
|
21
21
|
};
|
|
22
22
|
var createSpringImpl = (initial, config, options) => {
|
|
23
|
+
var _a, _b, _c;
|
|
23
24
|
let state = "resting";
|
|
24
25
|
let velocity = 0;
|
|
25
26
|
let target = initial;
|
|
26
27
|
let value = initial;
|
|
27
|
-
const restingDistance = Math.max((options == null ? void 0 : options.restingDistance)
|
|
28
|
-
const restingVelocity = Math.max((options == null ? void 0 : options.restingVelocity)
|
|
29
|
-
const arrivalFunction = getArrivalFunction((options == null ? void 0 : options.arrivalBehavior)
|
|
28
|
+
const restingDistance = Math.max((_a = options == null ? void 0 : options.restingDistance) != null ? _a : 1e-4, 0);
|
|
29
|
+
const restingVelocity = Math.max((_b = options == null ? void 0 : options.restingVelocity) != null ? _b : 1e-4, 0);
|
|
30
|
+
const arrivalFunction = getArrivalFunction((_c = options == null ? void 0 : options.arrivalBehavior) != null ? _c : 1);
|
|
30
31
|
const emitter = mitt();
|
|
31
32
|
const { emit, ...emitterApi } = emitter;
|
|
32
33
|
const spring = {
|
|
@@ -36,26 +37,38 @@ var createSpringImpl = (initial, config, options) => {
|
|
|
36
37
|
},
|
|
37
38
|
set target(val) {
|
|
38
39
|
target = val;
|
|
39
|
-
if (Math.abs(value - target) > restingDistance) {
|
|
40
|
+
if (state !== "moving" && Math.abs(value - target) > restingDistance) {
|
|
40
41
|
state = "moving";
|
|
41
42
|
emit("update:state", state);
|
|
42
43
|
}
|
|
43
44
|
},
|
|
45
|
+
getTarget: () => target,
|
|
44
46
|
get value() {
|
|
45
47
|
return value;
|
|
46
48
|
},
|
|
49
|
+
getValue: () => value,
|
|
47
50
|
get velocity() {
|
|
48
51
|
return velocity;
|
|
49
52
|
},
|
|
53
|
+
getVelocity: () => velocity,
|
|
50
54
|
get state() {
|
|
51
55
|
return state;
|
|
52
56
|
},
|
|
57
|
+
getState: () => state,
|
|
53
58
|
get config() {
|
|
54
59
|
return config;
|
|
55
60
|
},
|
|
56
61
|
set config(value2) {
|
|
57
62
|
config = value2;
|
|
58
63
|
},
|
|
64
|
+
getConfig: () => config,
|
|
65
|
+
jumpTo: (_value, killVelocity = true) => {
|
|
66
|
+
value = _value;
|
|
67
|
+
if (killVelocity) {
|
|
68
|
+
velocity = 0;
|
|
69
|
+
}
|
|
70
|
+
state = Math.abs(velocity) > restingVelocity || Math.abs(value - target) > restingDistance ? "moving" : "resting";
|
|
71
|
+
},
|
|
59
72
|
freeze: () => {
|
|
60
73
|
state = "frozen";
|
|
61
74
|
emit("update:state", state);
|
|
@@ -65,13 +78,15 @@ var createSpringImpl = (initial, config, options) => {
|
|
|
65
78
|
emit("update:state", state);
|
|
66
79
|
}
|
|
67
80
|
};
|
|
81
|
+
const tension = -config.tension * 1e-6;
|
|
82
|
+
const friction = -config.friction * 1e-3;
|
|
68
83
|
const simulate = (deltaTime) => {
|
|
69
84
|
if (state === "moving") {
|
|
70
85
|
const iterations = Math.ceil(deltaTime);
|
|
71
86
|
for (let n = 0; n < iterations; n++) {
|
|
72
87
|
const previousDelta = value - target;
|
|
73
|
-
const springForce =
|
|
74
|
-
const dampingForce =
|
|
88
|
+
const springForce = tension * previousDelta;
|
|
89
|
+
const dampingForce = friction * velocity;
|
|
75
90
|
const acceleration = (springForce + dampingForce) / config.mass;
|
|
76
91
|
velocity = velocity + acceleration;
|
|
77
92
|
value = value + velocity;
|
|
@@ -130,7 +145,12 @@ var createSpringChainImpl = (initial, links, config, options) => {
|
|
|
130
145
|
if (typeof link === "number") {
|
|
131
146
|
spring.target = previousSpring.value + link;
|
|
132
147
|
} else {
|
|
133
|
-
spring.target = link(
|
|
148
|
+
spring.target = link(
|
|
149
|
+
previousSpring.value,
|
|
150
|
+
previousSpring.target,
|
|
151
|
+
spring.value,
|
|
152
|
+
spring.target
|
|
153
|
+
);
|
|
134
154
|
}
|
|
135
155
|
targets[index + 1] = spring.target;
|
|
136
156
|
states[index + 1] = spring.state;
|
|
@@ -138,7 +158,11 @@ var createSpringChainImpl = (initial, links, config, options) => {
|
|
|
138
158
|
state = "moving";
|
|
139
159
|
}
|
|
140
160
|
} else {
|
|
141
|
-
const [spring, simulate2] = createSpringImpl(
|
|
161
|
+
const [spring, simulate2] = createSpringImpl(
|
|
162
|
+
typeof link === "number" ? previousSpring.value + link : link(previousSpring.value, previousSpring.target),
|
|
163
|
+
config,
|
|
164
|
+
options
|
|
165
|
+
);
|
|
142
166
|
springs.push(spring);
|
|
143
167
|
simulateFns.push(simulate2);
|
|
144
168
|
targets[index + 1] = spring.target;
|
|
@@ -193,9 +217,11 @@ var createSpringChainImpl = (initial, links, config, options) => {
|
|
|
193
217
|
currentTarget = val;
|
|
194
218
|
updateChainState(currentTarget, currentLinks);
|
|
195
219
|
},
|
|
220
|
+
getTarget: () => targets[0],
|
|
196
221
|
get targets() {
|
|
197
222
|
return targets;
|
|
198
223
|
},
|
|
224
|
+
getTargets: () => targets,
|
|
199
225
|
get links() {
|
|
200
226
|
return links;
|
|
201
227
|
},
|
|
@@ -206,18 +232,23 @@ var createSpringChainImpl = (initial, links, config, options) => {
|
|
|
206
232
|
get config() {
|
|
207
233
|
return config;
|
|
208
234
|
},
|
|
235
|
+
getConfig: () => config,
|
|
209
236
|
get values() {
|
|
210
237
|
return values;
|
|
211
238
|
},
|
|
239
|
+
getValues: () => values,
|
|
212
240
|
get velocities() {
|
|
213
241
|
return velocities;
|
|
214
242
|
},
|
|
243
|
+
getVelocities: () => velocities,
|
|
215
244
|
get state() {
|
|
216
245
|
return state;
|
|
217
246
|
},
|
|
247
|
+
getState: () => state,
|
|
218
248
|
get states() {
|
|
219
249
|
return states;
|
|
220
250
|
},
|
|
251
|
+
getStates: () => states,
|
|
221
252
|
freeze: () => {
|
|
222
253
|
for (const spring of springs) {
|
|
223
254
|
spring.freeze();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coily",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Simulate values using spring physics",
|
|
5
5
|
"author": "Tim Morris <timthewebguy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/tkofh/coily#readme",
|
|
@@ -32,18 +32,18 @@
|
|
|
32
32
|
"test": "vitest run",
|
|
33
33
|
"test:watch": "vitest watch",
|
|
34
34
|
"test:ui": "vitest --ui",
|
|
35
|
-
"prepublish": "
|
|
35
|
+
"prepublish": "pnpm test && pnpm build"
|
|
36
36
|
},
|
|
37
37
|
"bugs": {
|
|
38
38
|
"url": "https://github.com/tkofh/coily/issues"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@vitest/ui": "^0.
|
|
42
|
-
"tsup": "^6.
|
|
43
|
-
"vitest": "^0.
|
|
41
|
+
"@vitest/ui": "^0.29.2",
|
|
42
|
+
"tsup": "^6.6.3",
|
|
43
|
+
"vitest": "^0.29.2"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"mitt": "^3.0.0"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "f6f52d538e85578e1d734a729e4161f54c5b900f"
|
|
49
49
|
}
|