@msb235/blits 0.2.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/motion.d.ts CHANGED
@@ -1,7 +1,16 @@
1
- import type { Patch } from './types.js';
2
- /** A number, or one number per axis. */
1
+ import { type Curve } from './easing.js';
2
+ import type { Easing, Patch } from './types.js';
3
+ /**
4
+ * A number, or one number per axis.
5
+ *
6
+ * @category patch
7
+ */
3
8
  export type Value = number | readonly number[];
4
- /** One value for every subject, or one per subject. */
9
+ /**
10
+ * One value for every subject, or one per subject.
11
+ *
12
+ * @category patch
13
+ */
5
14
  export type PerSubject<I, V> = V | ((subject: I) => V);
6
15
  /**
7
16
  * Where a subject is and how fast it is moving, at one moment of voice time.
@@ -13,6 +22,17 @@ export interface Motion<V extends Value = number> {
13
22
  /** Units per second. */
14
23
  velocity: V;
15
24
  }
25
+ interface Change {
26
+ /**
27
+ * Voice ms it takes effect at; absent, until the subject's next read stamps it with that read's
28
+ * time, for one made while no frame had met the subject.
29
+ */
30
+ at?: number;
31
+ to?: number[];
32
+ v?: number[];
33
+ }
34
+ /** A motion patch's `frame` while no mix plays it: no subject has a latest frame. */
35
+ export declare const noFrame: () => number;
16
36
  /**
17
37
  * A patch whose motion is a closed form per subject, so it lands in the same place at any frame
18
38
  * rate, and whose changes mid-flight start from where the subject is and how fast it moves.
@@ -20,11 +40,122 @@ export interface Motion<V extends Value = number> {
20
40
  * @category patch
21
41
  */
22
42
  export type Moving<I, O, V extends Value> = Patch<I, O, void> & {
23
- /** Where `subject` is and how fast it moves at voice time `at`, default its last read. */
43
+ /**
44
+ * Where `subject` is and how fast it moves at voice time `at`, default the mix's latest frame,
45
+ * counting every change due by then. With no time given, undefined until a frame of its voice
46
+ * has met the subject, while the subject is still inside its stagger, and once that voice is gone.
47
+ */
24
48
  read(subject: I, at?: number): Motion<V> | undefined;
25
- /** Sets `subject` moving at `velocity`, units per second, from voice time `at`, default its next read. */
49
+ /**
50
+ * Sets `subject` moving at `velocity`, units per second, from voice time `at`, default the mix's
51
+ * latest frame; for a subject no frame of its voice has met yet, or still inside its stagger, its
52
+ * first read, after any change with a time due by then.
53
+ */
26
54
  push(subject: I, velocity: V, at?: number): void;
27
55
  };
56
+ interface Shape<I> {
57
+ from: (subject: I) => number[];
58
+ velocity: (subject: I) => number[];
59
+ /** Where it heads when released from `x` at `v`, given where it was heading. */
60
+ aim: (x: number[], v: number[], was: number[] | null, subject: I) => number[];
61
+ /** `[form, settle, k1, k2, k3]`. */
62
+ law: readonly number[];
63
+ /** Whether a subject's value is a number rather than an array. */
64
+ scalar: (subject: I) => boolean;
65
+ /** A tween's easing, which its law cannot hold; undefined, but present, on every other shape. */
66
+ ease: Curve | undefined;
67
+ }
68
+ /**
69
+ * A motion patch's subjects: the stretch each is playing, in one flat array by a number the patch
70
+ * gives it, with earlier stretches a read back may reach and changes not yet applied beside them.
71
+ * The one copy, read by `at` and by a mix's lane alike.
72
+ *
73
+ * After the law, each subject's run of `stride` numbers is its release time, its flags, then `x0`,
74
+ * `v0` and `to` per axis. A live sample reads this one buffer and nothing else the patch owns: at
75
+ * 10k springs of one subject each, a buffer per field, a map lookup per sample and the law in an
76
+ * object of its own took a call from 130 ns to 490.
77
+ */
78
+ export declare class Motions<I> {
79
+ private readonly shape;
80
+ private readonly numbers;
81
+ private readonly slots;
82
+ /** Axes per subject; -1 until the first subject sets it. */
83
+ n: number;
84
+ private cap;
85
+ private stride;
86
+ private runs;
87
+ /**
88
+ * Where `sample` leaves a subject's position and velocity, per axis. Shared by every patch, so
89
+ * read it before the next sample.
90
+ */
91
+ xs: Float64Array<ArrayBuffer>;
92
+ vs: Float64Array<ArrayBuffer>;
93
+ private readonly pending;
94
+ private readonly older;
95
+ /**
96
+ * The subject's voice time at the mix's latest frame, which an untimed change and a `read` with
97
+ * no time take; NaN where no frame of the patch's voice has met the subject. Set by the mix that
98
+ * cues the patch, and put back when its voice retires.
99
+ */
100
+ frame: (subject: I) => number;
101
+ constructor(shape: Shape<I>);
102
+ /** The patch's number for `subject`, made with its first stretch on first ask. */
103
+ slot(subject: I): number;
104
+ /** Forgets a subject, so a later ask starts it afresh from `from`. */
105
+ release(subject: I): void;
106
+ /** Whether subject `s`'s value is a number rather than an array. */
107
+ scalar(s: number): boolean;
108
+ /** The value `at` hands the mix: the first axis for a number, a fresh array otherwise. */
109
+ value(s: number, xs: Float64Array): number | number[];
110
+ /**
111
+ * Position and velocity at voice time `t` into `xo` and `vo`, a tween's velocity left at 0. A live
112
+ * read stamps every untimed change with `t` and commits every change due by then, in time order;
113
+ * a projection's read applies the timed ones to a copy and commits nothing.
114
+ */
115
+ sample(s: number, t: number, xo: Float64Array, vo: Float64Array): void;
116
+ /**
117
+ * Whether a live `sample` at `t` would leave the subject's state as it is: nothing to stamp or
118
+ * commit by then, and nothing older than `reading.horizon` to let go of.
119
+ */
120
+ quiet(s: number, t: number): boolean;
121
+ /** Position and velocity at `at`, default the latest frame; undefined until there is one. */
122
+ read(subject: I, at?: number): {
123
+ x: Float64Array;
124
+ v: Float64Array;
125
+ s: number;
126
+ } | undefined;
127
+ /**
128
+ * Queues a retarget or push, untimed at the latest frame, for `subject`'s next read past its time.
129
+ * The queue keeps the changes with a time in time order, ahead of any still waiting for one.
130
+ */
131
+ change(subject: I, c: Change): void;
132
+ /** Files a change with a time after every one due by then, ahead of those still waiting for one. */
133
+ private queue;
134
+ /** Every change due by `t` applied to a copy of the stretch playing then, committing nothing. */
135
+ private peek;
136
+ private check;
137
+ private flag;
138
+ private forget;
139
+ /** Where subject `s`'s run starts in `runs`. */
140
+ private base;
141
+ private grow;
142
+ private write;
143
+ /** The stretch subject `s` is playing now, as an object. */
144
+ private latest;
145
+ /** The stretch playing at voice time `t`: the latest released by then, else the first. */
146
+ private playing;
147
+ private applied;
148
+ private commit;
149
+ private insert;
150
+ /** Lets go of stretches older than the one in force at `reading.horizon`. */
151
+ private prune;
152
+ private evaluateSegment;
153
+ private evaluate;
154
+ /** A tween's stretch, `dt` seconds after release, kept out of `evaluate` so a spring's stays small. */
155
+ private eased;
156
+ }
157
+ /** The state behind a `'motion'` patch, for an engine that reads it directly. */
158
+ export declare function motionOf<I>(p: object): Motions<I> | undefined;
28
159
  interface Common<I, V extends Value> {
29
160
  /** Units per second each subject starts moving at. Default 0. */
30
161
  velocity?: PerSubject<I, V>;
@@ -37,9 +168,8 @@ interface Common<I, V extends Value> {
37
168
  /**
38
169
  * A damped spring toward a target, solved in closed form. `to(subject, target)` retargets one
39
170
  * subject mid-flight, and the new stretch starts from where it is and how fast it moves, so there is
40
- * no kink. Time is the voice's, so `rate` and `seek` apply; a read earlier than the latest change
41
- * evaluates the latest stretch, not history. Its state is its own, kept per subject: cue each spring
42
- * on one voice.
171
+ * no kink. Time is the voice's, so `rate` and `seek` apply. Its state is its own, kept per subject:
172
+ * cue each spring on one voice. Every subject moves on the same number of axes.
43
173
  *
44
174
  * @category patch
45
175
  */
@@ -53,7 +183,11 @@ export declare function spring<I, O, V extends Value = number>(writes: keyof O,
53
183
  damping?: number;
54
184
  mass?: number;
55
185
  }): Moving<I, O, V> & {
56
- /** Heads `subject` for `target` from voice time `at`, default its next read, keeping its velocity. */
186
+ /**
187
+ * Heads `subject` for `target` from voice time `at`, keeping its velocity: by default the mix's
188
+ * latest frame, or for a subject no frame of its voice has met yet, or still inside its stagger,
189
+ * its first read, after any change with a time due by then.
190
+ */
57
191
  to(subject: I, target: V, at?: number): void;
58
192
  };
59
193
  /**
@@ -69,4 +203,30 @@ export declare function glide<I, O, V extends Value = number>(writes: keyof O, o
69
203
  /** The friction's time constant, ms. Default 325, a touch scroll's. */
70
204
  ms?: number;
71
205
  }): Moving<I, O, V>;
206
+ /**
207
+ * From one value to another over `ms` along an easing, solved in closed form, so frame rate does not
208
+ * change where a subject is. `to(subject, target)` retargets one subject mid-flight: the new stretch
209
+ * starts from where it is and takes the full `ms` again, so its velocity jumps where a spring's
210
+ * would not. Time is the voice's, so `rate` and `seek` apply, and a voice's `loop` does not repeat
211
+ * it. Cue each tween on one voice. Every subject moves on the same number of axes.
212
+ *
213
+ * @category patch
214
+ */
215
+ export declare function tween<I, O, V extends Value = number>(writes: keyof O, opts: {
216
+ /** Where each subject starts. */
217
+ from: PerSubject<I, V>;
218
+ /** Where each subject ends. */
219
+ to: PerSubject<I, V>;
220
+ /** How long a stretch takes, ms. */
221
+ ms: number;
222
+ /** The curve from `from` to `to`. Default `'ease'`, as CSS's. */
223
+ ease?: Easing;
224
+ }): Omit<Moving<I, O, V>, 'push'> & {
225
+ /**
226
+ * Heads `subject` for `target` from voice time `at`, over a full `ms` from where it is: by default
227
+ * the mix's latest frame, or for a subject no frame of its voice has met yet, or still inside its
228
+ * stagger, its first read, after any change with a time due by then.
229
+ */
230
+ to(subject: I, target: V, at?: number): void;
231
+ };
72
232
  export {};