@msb235/blits 0.7.0 → 0.8.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.
Files changed (156) hide show
  1. package/CHANGELOG.md +196 -0
  2. package/README.md +22 -4
  3. package/dist/book.js +4 -4
  4. package/dist/chain.d.ts +1 -1
  5. package/dist/chain.js +57 -54
  6. package/dist/channels.d.ts +26 -5
  7. package/dist/channels.js +12 -8
  8. package/dist/clock.d.ts +8 -1
  9. package/dist/clock.js +14 -3
  10. package/dist/clone.d.ts +3 -0
  11. package/dist/clone.js +16 -1
  12. package/dist/closed.d.ts +1 -1
  13. package/dist/closed.js +3 -2
  14. package/dist/color.d.ts +0 -11
  15. package/dist/color.js +4 -24
  16. package/dist/columns.js +0 -1
  17. package/dist/copyout.d.ts +6 -0
  18. package/dist/copyout.js +38 -0
  19. package/dist/crowd.d.ts +7 -5
  20. package/dist/crowd.js +32 -18
  21. package/dist/cue.d.ts +3 -1
  22. package/dist/cue.js +33 -20
  23. package/dist/departed.d.ts +34 -0
  24. package/dist/departed.js +73 -0
  25. package/dist/easing.d.ts +5 -0
  26. package/dist/easing.js +31 -2
  27. package/dist/everyone.d.ts +56 -0
  28. package/dist/everyone.js +221 -0
  29. package/dist/fade.d.ts +8 -1
  30. package/dist/fade.js +36 -6
  31. package/dist/fill.d.ts +22 -13
  32. package/dist/fill.js +104 -41
  33. package/dist/fit.js +2 -1
  34. package/dist/fold.d.ts +37 -0
  35. package/dist/fold.js +213 -28
  36. package/dist/gather.d.ts +15 -9
  37. package/dist/gather.js +60 -25
  38. package/dist/gone.d.ts +32 -0
  39. package/dist/gone.js +144 -0
  40. package/dist/handle.d.ts +16 -5
  41. package/dist/handle.js +56 -6
  42. package/dist/held.d.ts +8 -5
  43. package/dist/held.js +56 -58
  44. package/dist/history.d.ts +17 -13
  45. package/dist/history.js +49 -28
  46. package/dist/hosts.js +57 -9
  47. package/dist/index.d.ts +9 -4
  48. package/dist/index.js +5 -2
  49. package/dist/keyfill.d.ts +7 -0
  50. package/dist/keyfill.js +124 -0
  51. package/dist/keyrows.d.ts +1 -0
  52. package/dist/keyrows.js +1 -1
  53. package/dist/lane.d.ts +32 -2
  54. package/dist/lane.js +5 -0
  55. package/dist/lanes.d.ts +32 -8
  56. package/dist/lanes.js +69 -37
  57. package/dist/leavings.d.ts +26 -0
  58. package/dist/leavings.js +70 -0
  59. package/dist/meet.js +14 -8
  60. package/dist/mixer.d.ts +43 -7
  61. package/dist/mixer.js +60 -11
  62. package/dist/motion.d.ts +2 -0
  63. package/dist/motion.js +4 -1
  64. package/dist/motions.d.ts +22 -15
  65. package/dist/motions.js +40 -34
  66. package/dist/move.js +31 -20
  67. package/dist/moved.d.ts +11 -0
  68. package/dist/moved.js +29 -0
  69. package/dist/origin.d.ts +19 -0
  70. package/dist/origin.js +68 -0
  71. package/dist/owed.d.ts +4 -4
  72. package/dist/owed.js +8 -8
  73. package/dist/owner.d.ts +1 -1
  74. package/dist/owner.js +2 -2
  75. package/dist/pace.d.ts +13 -5
  76. package/dist/pace.js +21 -8
  77. package/dist/pack.d.ts +3 -1
  78. package/dist/pack.js +15 -24
  79. package/dist/paging.d.ts +8 -2
  80. package/dist/paging.js +44 -4
  81. package/dist/patch.d.ts +14 -9
  82. package/dist/patch.js +83 -21
  83. package/dist/place.js +188 -30
  84. package/dist/project.d.ts +12 -1
  85. package/dist/project.js +101 -83
  86. package/dist/pull.d.ts +2 -0
  87. package/dist/pull.js +8 -0
  88. package/dist/qualify.js +10 -2
  89. package/dist/reading.d.ts +5 -0
  90. package/dist/reading.js +5 -0
  91. package/dist/record.d.ts +9 -0
  92. package/dist/record.js +42 -0
  93. package/dist/relink.d.ts +11 -5
  94. package/dist/relink.js +7 -5
  95. package/dist/restored.d.ts +41 -0
  96. package/dist/restored.js +91 -0
  97. package/dist/revive.d.ts +10 -3
  98. package/dist/revive.js +31 -23
  99. package/dist/roster.d.ts +11 -0
  100. package/dist/roster.js +46 -0
  101. package/dist/rotation.d.ts +29 -0
  102. package/dist/rotation.js +91 -0
  103. package/dist/rows.d.ts +5 -5
  104. package/dist/rows.js +5 -5
  105. package/dist/sample.d.ts +3 -2
  106. package/dist/sample.js +32 -15
  107. package/dist/scored.d.ts +57 -0
  108. package/dist/scored.js +196 -0
  109. package/dist/seek.js +97 -114
  110. package/dist/shared.d.ts +6 -0
  111. package/dist/shared.js +15 -0
  112. package/dist/signals.d.ts +24 -3
  113. package/dist/signals.js +50 -11
  114. package/dist/spans.js +7 -0
  115. package/dist/stack.d.ts +11 -0
  116. package/dist/stack.js +47 -0
  117. package/dist/standing.d.ts +10 -0
  118. package/dist/standing.js +79 -0
  119. package/dist/store.d.ts +3 -3
  120. package/dist/store.js +3 -3
  121. package/dist/strays.js +3 -0
  122. package/dist/tape.d.ts +8 -5
  123. package/dist/tape.js +21 -13
  124. package/dist/testing.d.ts +35 -0
  125. package/dist/testing.js +116 -0
  126. package/dist/touch.d.ts +6 -0
  127. package/dist/touch.js +28 -0
  128. package/dist/transport.d.ts +53 -6
  129. package/dist/transport.js +102 -20
  130. package/dist/turns.d.ts +18 -0
  131. package/dist/turns.js +72 -0
  132. package/dist/tweened.js +1 -1
  133. package/dist/types/channel.d.ts +46 -0
  134. package/dist/types/channel.js +1 -0
  135. package/dist/types/history.d.ts +139 -0
  136. package/dist/types/history.js +1 -0
  137. package/dist/types/mix.d.ts +336 -0
  138. package/dist/types/mix.js +1 -0
  139. package/dist/types/patch.d.ts +187 -0
  140. package/dist/types/patch.js +1 -0
  141. package/dist/types/place.d.ts +157 -0
  142. package/dist/types/place.js +1 -0
  143. package/dist/types/transport.d.ts +71 -0
  144. package/dist/types/transport.js +1 -0
  145. package/dist/types/voice.d.ts +323 -0
  146. package/dist/types/voice.js +1 -0
  147. package/dist/types.d.ts +7 -1162
  148. package/dist/unpage.d.ts +2 -2
  149. package/dist/unpage.js +55 -25
  150. package/dist/voice.d.ts +92 -22
  151. package/dist/voice.js +108 -43
  152. package/dist/wave.d.ts +42 -0
  153. package/dist/wave.js +62 -0
  154. package/dist/weigh.js +1 -1
  155. package/docs/schema.html +42 -36
  156. package/package.json +8 -3
@@ -0,0 +1,336 @@
1
+ import type { Kit } from './channel.js';
2
+ import type { HistoryOptions, Tape } from './history.js';
3
+ import type { Patch, Sent, Signal } from './patch.js';
4
+ import type { Booker, BookOptions, Marked } from './place.js';
5
+ import type { Transport } from './transport.js';
6
+ import type { Handle, OwnerSpec, SpanHandle, SpanSpec, VoiceSpec } from './voice.js';
7
+ /**
8
+ * How a mix is built: its engine, reduced motion, the host, and its limits.
9
+ *
10
+ * @category mix
11
+ */
12
+ export interface MixOptions<H = unknown> {
13
+ engine?: Engine;
14
+ /** Reduced motion: fades and warm-ups snap, `dt` reads Infinity. */
15
+ reduce?: boolean | (() => boolean);
16
+ /** Merged into every `setting.host`. Its type is the mix's `H`, which every patch and signal it cues reads. */
17
+ host?: H;
18
+ /**
19
+ * The band a rest-less channel's contribution switches on and off across. It has to clear the frame
20
+ * noise in a real signal; these are placeholders until the klieg port measures one.
21
+ */
22
+ band?: {
23
+ on: number;
24
+ off: number;
25
+ };
26
+ /**
27
+ * The most `dt` a `step` or signal is handed, however long the gap. Off by default, since a
28
+ * patch with a closed form wants the whole gap; an integrator wants this set.
29
+ */
30
+ maxDt?: number;
31
+ /**
32
+ * Run every `step` at this fixed interval, ms, instead of once by the frame's gap, so stateful
33
+ * patches play the same at any frame rate. Intervals count from when a subject's delay ran out,
34
+ * the remainder carrying to the next sample; `maxDt` then caps how many one sample may run.
35
+ * Signals and `at` still see the frame. Off by default.
36
+ */
37
+ stepMs?: number;
38
+ /**
39
+ * How far back `project` may read, in ms of mix time, and how often a stateful voice's state is
40
+ * kept per subject on the way, `every` ms (default 200). Within it the mix remembers what it cued,
41
+ * every change a handle made and when, the voices that have left, and those copies of state, so a
42
+ * read back restores the nearest copy and steps forward from it. Off by default, and a mix without
43
+ * it keeps nothing. With `inputs`, it also keeps what each input signal on a voice's weight read
44
+ * per subject, and the host fields patches `reads`, each time they changed, so a read back over a
45
+ * `level` or a pointer is known rather than held. With `tape`, the mix also records every call
46
+ * the host makes on it, its handles and its motion patches, so `seek` can move it and play those
47
+ * calls again.
48
+ */
49
+ history?: HistoryOptions;
50
+ /**
51
+ * A subject's key, for a history `store`: unique among this mix's subjects for the session. A
52
+ * string or number subject is its own key; with a store, an object subject needs this.
53
+ */
54
+ keyOf?(subject: never): string | number;
55
+ /**
56
+ * Whether a channel may run as a lane: computed for every subject at once in flat arrays, when
57
+ * every voice writing it can run that way. On by default; what a host reads is the same either
58
+ * way (`probe`, `pull`, `atRest`, `weightOf`, `inert` and `project`), so turning it off is for
59
+ * ruling a lane out, or for comparing against. A voice weighted by an input signal `input` did not
60
+ * make, or whose patch reads host fields, never runs on a lane, since a change to either
61
+ * between two probes would not reach it. Two things differ: a
62
+ * stateless patch's `setting.send` from `at` sends for every subject a lane fills, those probed
63
+ * this frame or the last, and a patch that first calls `setting.keep` partway through playing can
64
+ * advance that state once more for one subject probed the frame before (see `Setting.keep`).
65
+ */
66
+ lanes?: boolean;
67
+ /**
68
+ * The transport this mix plays on, shared with other mixes, so they keep one clock and a query
69
+ * naming a score looks in all of them. The transport's `sync`, `rebase`, `rate`, `ramp` and
70
+ * `seek` move it, and the mix's own throw. Its history is the transport's, so the mix takes no
71
+ * `history` of its own.
72
+ */
73
+ transport?: Transport;
74
+ /** What `Marked.mix` and errors call this mix. */
75
+ name?: string;
76
+ }
77
+ /**
78
+ * How sure a projection is of one channel: `exact` where only the clock and known changes drove
79
+ * it; `stepped` where state was advanced across a gap in one go, which is as good as the patch's
80
+ * step makes it; `held` where it depends on input from outside the clock, whose value at that time
81
+ * is not known, so the value it had is held.
82
+ *
83
+ * @category mix
84
+ */
85
+ export type Doubt = 'exact' | 'stepped' | 'held';
86
+ /**
87
+ * The mix read at another time: what `probe` would give at that timestamp, with nothing in the
88
+ * live mix moved. Valid until the mix is next synced or cued.
89
+ *
90
+ * @category mix
91
+ */
92
+ export interface Projection<I, O> {
93
+ /** The mix time it reads at. */
94
+ readonly timestamp: number;
95
+ /** The merged pose for one subject at this projection's timestamp. */
96
+ probe(subject: I, out?: O): O;
97
+ /** Per channel, how sure that pose is; the least sure voice that fed a channel decides. */
98
+ assess(subject: I): {
99
+ [K in keyof O]-?: Doubt;
100
+ };
101
+ }
102
+ /**
103
+ * Arrays for `pull` to write, one per channel it reads: any channel whose value is a number or an
104
+ * array of numbers.
105
+ *
106
+ * @category mix
107
+ */
108
+ export type Columns<O> = {
109
+ [K in keyof O as NonNullable<O[K]> extends number | readonly number[] ? K : never]?: Float64Array;
110
+ };
111
+ /**
112
+ * The live voices over one kit, folded into one pose per subject per frame.
113
+ *
114
+ * @category mix
115
+ */
116
+ export interface Mix<I, O, H = unknown> {
117
+ /** Cues a voice. Throws when the engine cannot run the patch's form, or the kit lacks a channel. */
118
+ cue(spec: VoiceSpec<I, O, H>): Handle<I>;
119
+ /**
120
+ * N voices whose weights split one signal, cued into one locus so they fold as alternatives. The
121
+ * signal is read once per subject per frame, with the first member's setting, and every member
122
+ * takes its share of that one reading; a signal keeping state keeps it once, not per member.
123
+ */
124
+ blend(patches: readonly Patch<I, O, unknown, H>[], by: Signal<I, H>, spec?: Omit<VoiceSpec<I, O, H>, 'patch' | 'weight' | 'locus'>): Handle<I>[];
125
+ /**
126
+ * Cues an owner: a voice with no patch that holds the voices cued with `owner` set to its handle,
127
+ * and plays them on its own clock, so they can be placed, timed and faded as one. Its handle acts
128
+ * on all of them: `rate` and `ramp` multiply into theirs, `seek` moves their clocks with its own
129
+ * and rebuilds their state as it does a voice's, and `weight` and `fade()` multiply into their weights, by
130
+ * what its `weightOf` reports; it fades as a whole, not by subject or at rest. It is
131
+ * `played` once every voice it held has finished its passes, and leaves, `done`, with its last; a
132
+ * fade that ends takes the rest with it. One that never holds a voice stays until faded. Owners
133
+ * nest. Throws for a `loop`: a pass would have to restart its children.
134
+ */
135
+ owns(spec: OwnerSpec<I, H>): Handle<I>;
136
+ /**
137
+ * Cues a span: an owner that lays out the voices it holds in `order` and fits them into its
138
+ * `duration`, again each time one joins or leaves early. A child's start and rate are the
139
+ * span's to set, so it takes neither `start` nor an anchored start; its `SpanHints` say how it
140
+ * may give way. A span with a budget stays until the budget has passed, though its children
141
+ * finish sooner, so late ones can still join, and its `end` mark is where its children end or
142
+ * its budget does, whichever is later. A voice that loops for good cannot join one.
143
+ */
144
+ span(spec: SpanSpec<I, H>): SpanHandle<I>;
145
+ /**
146
+ * The host reports the clock, once a frame. Nothing advances at the call. Throws for a timestamp
147
+ * earlier than the last sync's, short of a `rebase`: the host's clock only goes forward, and
148
+ * `seek` moves the mix.
149
+ */
150
+ sync(timestamp: number): void;
151
+ /**
152
+ * The time between the last sync and the next one is not to count: a host calls it when a
153
+ * hidden tab comes back. Every voice, fade and subject resumes where it was left.
154
+ */
155
+ rebase(): void;
156
+ /**
157
+ * The mix's own playback rate, multiplied into every voice's: 1 is real time and 0 pauses the
158
+ * whole mix. A negative rate throws: the mix plays only forward, and `seek` moves it back. Setting it changes speed at
159
+ * once; `ramp` eases into a new one. It scales mix time, which everything a voice owns runs on:
160
+ * its clock, its fades and a handle's ramp, `stagger`, an anchor's `by`, `stepMs`, `maxDt`,
161
+ * `history.ms`, every `dt`, and `setting.timestamp`. Timestamps on the host's clock name the same
162
+ * moment whatever the rate does: a `start`, an anchor given as a number, an announced mark, what
163
+ * `marks` reports and the time `project` reads, so a start ahead of a paused mix waits for the
164
+ * host's clock to reach it. A weight signal is still asked at every probe, so one reading host
165
+ * input follows it while the mix is paused.
166
+ */
167
+ rate: number;
168
+ /**
169
+ * Moves the mix's rate to `rate` linearly over `over` ms of the host's clock, as `Handle.ramp`
170
+ * moves a voice's. Mix time integrates the ramp and a voice's clock integrates mix time, so a ramp
171
+ * on both multiplies and every position stays continuous. A later `rate` write or `ramp` replaces
172
+ * it.
173
+ */
174
+ ramp(rate: number, over: number): void;
175
+ /**
176
+ * The merged pose for one subject at the synced frame, written into `out` when given. Without
177
+ * it, each call makes a new object, so a host reading every subject every frame passes `out` or
178
+ * reads by `pull`. An array `out` already holds for a `vec` channel, a `quat` that
179
+ * runs on a lane, or a `color` that averages in OKLab or runs on a lane, is written in place where it is the channel's length, so a host that
180
+ * kept one from an earlier probe into the same `out` sees it change: copy what has to outlast the
181
+ * next probe.
182
+ */
183
+ probe(subject: I, out?: O): O;
184
+ /**
185
+ * Writes each subject's pose into arrays, one per channel, subject by subject in the order given:
186
+ * what `probe(subject, out)` gives, without a pose object per subject. A channel of `n` numbers
187
+ * takes `n` places per subject, side by side; one with no value for a subject writes NaN there.
188
+ * Fastest while every voice runs on a lane, and when `subjects` is an array read again in the
189
+ * same order: the mix remembers the last array's subjects by position, holding them until the
190
+ * next `pull`, and skips looking up any still in its place. Throws when an array is too short for
191
+ * the subjects.
192
+ */
193
+ pull(subjects: Iterable<I>, into: Columns<O>): void;
194
+ /**
195
+ * Reads the mix at another mix time, without moving it. Ahead of the mix it plays what is cued
196
+ * forward, and throws for a time past a call the tape will play again after a `seek` back, which
197
+ * only a seek there makes; behind it, with `history`, it reads the last frame at or before `time`
198
+ * as that frame showed, and throws for a time older than the history reaches. On a transport it
199
+ * reads every mix on it together, so anchors across them answer.
200
+ *
201
+ * Without `history` it reads back only where how the mix stands now says what it showed then,
202
+ * and throws otherwise, saying why. Every voice has to play as it was cued and read by its clock
203
+ * alone: no state, motion, `from: 'current'`, anchor or owner, no write to its handle, and no channel without a rest
204
+ * at a weight that moves. The mix's rate has never been set. And `time` is no earlier than the
205
+ * last cue, `drop`, `touch`, `announce` or `rebase`, or the last frame a voice left in.
206
+ */
207
+ project(time: number): Projection<I, O>;
208
+ /**
209
+ * Moves the mix to mix time `time`, as it stood at the end of that frame, and plays on from
210
+ * there; where rate 0 held the clock at `time` for several frames, the last of them. Needs
211
+ * `history` with a `tape`, which records the host's calls by the host time they were made at.
212
+ *
213
+ * Back, the mix restores itself: controls, records, voices and marks as they stood then. Voices
214
+ * that left after it are back on the handles the host holds, their `done` and `played` starting
215
+ * over where they had settled since. Voices cued after it wait as `pending` until the mix plays
216
+ * their cue again. Stateful voices restart from the copy `history` kept nearest before it and
217
+ * step once to it, exact under `stepMs`. A subject faded out of a voice or dropped after it comes
218
+ * back with the record it had, a motion patch's state included. Recorded input and host fields
219
+ * after it are let go: after a seek back, signals and host fields read live again, and `assess`
220
+ * reports what they fed as `held`.
221
+ *
222
+ * Forward, through a sync or a later seek, the mix plays the recorded calls again in the frames
223
+ * they were made in: cues, handle writes, fades, retargets and pushes, its rate, marks,
224
+ * `mute` and `drop`. A call the host makes while there are recorded calls ahead starts a new
225
+ * branch, and the tape keeps the old future beside it; `tape.switchBranch` picks one back.
226
+ * Playing past a time again sends its events and books its marks and hits again.
227
+ *
228
+ * The host goes on passing its own clock: the next `sync` reads the moment sought plus the
229
+ * host's time since its last sync. Throws for a time older than history reaches, and before
230
+ * the first sync. With a history `store`, a time older than memory needs `prepare` first, or
231
+ * throws `HistoryMiss` before anything moves.
232
+ */
233
+ seek(time: number): void;
234
+ /** As `Transport.prepare`, for a mix made alone. */
235
+ prepare(time: number): Promise<void>;
236
+ /**
237
+ * The mix clock at the last sync or seek, which `seek` and `project` take; NaN before the first
238
+ * sync. Host time at the mix's rate, less what `rebase` took out and `seek` moved.
239
+ */
240
+ readonly now: number;
241
+ /** The tape `history.tape` made, undefined without one. */
242
+ readonly tape: Tape | undefined;
243
+ /**
244
+ * Every channel at rest for this subject this frame, so a host can skip the write. After a probe
245
+ * of the subject this frame, it answers for the pose that probe gave, without folding again.
246
+ */
247
+ atRest(subject: I): boolean;
248
+ /**
249
+ * A handle on every voice still in the mix, pending, live, frozen or fading, in the order they were
250
+ * cued; given a tag, only the voices whose `tags` carry it. Each is the handle `cue` returned for
251
+ * that voice, so a listed handle is `===` the cued one.
252
+ */
253
+ voices(tag?: string): Handle<I>[];
254
+ /** Anything still contributing, fading, or pending. */
255
+ readonly live: boolean;
256
+ /**
257
+ * Another frame would change no pose, so a host's frame loop may sleep: every voice is done, frozen
258
+ * at a plain weight, or a motion whose every subject has landed on its target. At rate 0 it is
259
+ * enough that every voice not done has started, at a plain weight, with no anchor. A change made
260
+ * since the last sync, a retarget or a rate included, makes it false until the next.
261
+ */
262
+ readonly inert: boolean;
263
+ /**
264
+ * Calls `fn` when a host call makes the mix need frames again after a sync: a cue, a fade, a
265
+ * handle's or the mix's rate, a seek, a `drop`, a motion retargeted. It fires once until the next
266
+ * sync clears the change, and never during `sync`. Returns a function that unsubscribes `fn`.
267
+ * A frame loop sleeping on `inert` subscribes here to wake.
268
+ */
269
+ onWake(fn: () => void): () => void;
270
+ /** Fades every voice out: over `over` when given, over each voice's own `fade.out` otherwise. */
271
+ mute(opts?: {
272
+ over?: number;
273
+ }): void;
274
+ /**
275
+ * Forgets per-subject state, a motion patch's for the subject included, and any fade of the
276
+ * subject out of a voice, so nothing keeps the subject alive.
277
+ */
278
+ drop(subject: I): void;
279
+ /**
280
+ * Says that something a patch reads from outside the mix has changed since the last sync, such as
281
+ * a table its `at` looks a subject up in, so the next probe calls the patch again where it would
282
+ * have answered with what it read this frame. Given a subject, for that subject only; with none,
283
+ * for every subject. The clock stays where it is and no `step` runs again, and it wakes a frame
284
+ * loop sleeping on `inert`, as any change does.
285
+ */
286
+ touch(subject?: I): void;
287
+ /**
288
+ * Puts a named mark on a score, for anchors to target as they target a voice's marks: a voice
289
+ * placed `{ with: 'reply' }` waits until the host announces `reply`. `at` is a timestamp on the
290
+ * host's clock, default now, and may lie ahead, so a read ahead sees it. A mark stays while it is
291
+ * ahead or while the mix's history reaches it.
292
+ */
293
+ announce(name: string, opts?: {
294
+ at?: number;
295
+ score?: string;
296
+ tags?: readonly string[];
297
+ }): void;
298
+ /**
299
+ * Every mark the plan knows between two timestamps on the host's clock, earliest first: when
300
+ * voices start, are fully in, end their last pass, begin to fade and are gone, and what the host
301
+ * announced. A mark
302
+ * nothing has fixed yet, such as the out of a voice that loops for good, is not listed.
303
+ */
304
+ marks(from: number, to: number): Marked[];
305
+ /**
306
+ * Every event patches have sent since the last drain, earliest first, in the order they were sent
307
+ * where two share a timestamp. A subject's events are made while it catches up, which is when it is
308
+ * probed, so one nobody probes has sent nothing yet: promptness is the host's, by probing. A
309
+ * stateless patch's `at` on a lane is the exception: it runs at the frame's first probe for every
310
+ * subject probed that frame or the last. Under `stepMs` each carries the end of the interval it happened in, so
311
+ * what is sent and when does not depend on how the host spaces its probes. Time `rebase` took out
312
+ * sends nothing. Given a tag, it takes only the events of voices carrying it and leaves the rest for
313
+ * whoever drains them.
314
+ */
315
+ drain<E = unknown>(tag?: string): Sent<I, E>[];
316
+ /**
317
+ * Hands the host each mark and hit before it comes, against a clock of its own, so it can schedule
318
+ * the thing itself: a sound on an `AudioContext`, a MIDI message with a timestamp, a video loaded
319
+ * before the voice that shows it starts. Booking runs at each `sync`, `ahead` ms out, and a
320
+ * booking whose time moves is stopped and taken again. Nothing is booked twice: a mark is known by
321
+ * its voice and which mark, a hit by its voice, index and pass. `project` books nothing, and
322
+ * nothing about booking is replayed under `history`. A mix with no booker pays nothing for it.
323
+ */
324
+ book<E = unknown>(opts: BookOptions<E>): Booker;
325
+ }
326
+ /**
327
+ * The implementation behind a mix: which patch forms it runs, and how it makes one.
328
+ *
329
+ * @category engine
330
+ */
331
+ export interface Engine {
332
+ readonly name: string;
333
+ /** Which patch forms this engine can run. A voice it cannot run is refused at `cue`, by name. */
334
+ readonly runs: ReadonlySet<'fn' | 'keys' | 'motion'>;
335
+ create<I, O, H = unknown>(kit: Kit<O>, opts: MixOptions<H>): Mix<I, O, H>;
336
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,187 @@
1
+ import type { WaveOptions } from '../wave.js';
2
+ import type { Kit } from './channel.js';
3
+ /**
4
+ * A curve on 0..1, as data where it can be: CSS's names, a `cubic-bezier`, or `steps`, which a
5
+ * WAAPI or GPU engine can read. The function form runs on the CPU engine only.
6
+ *
7
+ * @category patch
8
+ */
9
+ export type Easing = ((u: number) => number) | 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | {
10
+ readonly bezier: readonly [x1: number, y1: number, x2: number, y2: number];
11
+ } | {
12
+ readonly steps: number;
13
+ readonly jump?: 'start' | 'end';
14
+ };
15
+ /**
16
+ * One stop of a `keys` patch.
17
+ *
18
+ * @category patch
19
+ */
20
+ export interface Keyframe<O> {
21
+ /** Phase, 0..1. */
22
+ at: number;
23
+ delta: Partial<O>;
24
+ ease?: Easing;
25
+ }
26
+ /**
27
+ * What a patch may read and did not compute, for one subject this frame. The mix reuses the object,
28
+ * so it is valid only during the call it is handed to.
29
+ *
30
+ * @category state
31
+ */
32
+ export interface Setting<S = void, H = unknown> {
33
+ /**
34
+ * The mix clock at this frame: the host's timestamp less any time `rebase` took out, run at the
35
+ * mix's `rate`. Identical for every probe in the frame.
36
+ */
37
+ timestamp: number;
38
+ /**
39
+ * The gap this subject is catching up by: milliseconds since it last advanced, which is the gap
40
+ * since the previous sync only for a subject sampled every frame. Infinity under reduced motion;
41
+ * no more than `maxDt` where the mix sets one. Inside a `step` under `stepMs`, it is `stepMs`, and
42
+ * `timestamp` is the end of that interval.
43
+ */
44
+ dt: number;
45
+ /** Milliseconds this voice has been playing, rate applied. */
46
+ elapsed: number;
47
+ /** Which pass this is, 0 first. */
48
+ pass: number;
49
+ /** This voice's weight for this subject this frame, after fades, signals and any locus. */
50
+ weight: number;
51
+ /** This subject's state, when the patch declares one. */
52
+ state: S;
53
+ /** Anything the host adds for its own patches: the mix's `host`, typed as its `H`. */
54
+ host: H;
55
+ /**
56
+ * The state `owner` keeps for this voice and this subject, made by `init` on first ask. The mix
57
+ * holds it, so a read at another time can copy it instead of moving it. A stateful signal keeps
58
+ * its state here and nowhere else. With lanes on, a patch or weight signal that first calls it
59
+ * partway through playing can have that state advanced once for one subject probed the frame
60
+ * before it starts and not on that frame; one that keeps state from its first call, or a patch
61
+ * that declares `state`, never does.
62
+ */
63
+ keep<K>(owner: object, init: () => K): K;
64
+ /**
65
+ * Reports an event at `timestamp`, for this voice and this subject. The mix queues it until the
66
+ * host drains it, and never calls back. Meant for `step`, where under `stepMs` the timestamp is
67
+ * the interval the event happened in rather than the frame that sampled it. Sent from a stateless
68
+ * patch's `at` while it runs on a lane, it goes out for every subject the lane fills, probed that
69
+ * frame or not: each probed that frame or the last; `at` is not asked for a subject at weight 0,
70
+ * so nothing is sent from it there.
71
+ */
72
+ send(event: unknown): void;
73
+ }
74
+ /**
75
+ * One event a patch sent, as `drain` hands it back.
76
+ *
77
+ * @category state
78
+ */
79
+ export interface Sent<I, E = unknown> {
80
+ /** The mix clock when it was sent. */
81
+ timestamp: number;
82
+ subject: I;
83
+ /** The id of the voice whose patch sent it, as its handle reports. */
84
+ voice: number;
85
+ /** That voice's tags. */
86
+ tags: readonly string[];
87
+ event: E;
88
+ }
89
+ /**
90
+ * What a `'motion'` patch is made of, as data an engine can read: the kind of motion and its
91
+ * constants. Each subject's start, target and starting velocity stay on the patch, since they may
92
+ * be functions of the subject.
93
+ *
94
+ * @category patch
95
+ */
96
+ export type MotionSpec = {
97
+ readonly kind: 'spring';
98
+ /** Per second squared. */
99
+ readonly stiffness: number;
100
+ /** Per second. */
101
+ readonly damping: number;
102
+ readonly mass: number;
103
+ readonly settle: number;
104
+ } | {
105
+ readonly kind: 'glide';
106
+ /** The friction's time constant, ms. */
107
+ readonly ms: number;
108
+ readonly settle: number;
109
+ } | {
110
+ readonly kind: 'tween';
111
+ /** How long a stretch takes; undefined where it varies by subject, kept on the patch then. */
112
+ readonly ms: number | undefined;
113
+ readonly ease: Easing;
114
+ };
115
+ /**
116
+ * A pure function of phase and a subject that returns a delta. Optionally stateful.
117
+ *
118
+ * @category patch
119
+ */
120
+ export interface Patch<I, O, S = void, H = unknown> {
121
+ /**
122
+ * Which authoring form built it: `'fn'` from `patch`, `'keys'` from `keys`, `'motion'` from
123
+ * `spring`, `glide` or `tween`. An engine declares which forms it runs.
124
+ */
125
+ readonly form: 'fn' | 'keys' | 'motion';
126
+ /** Milliseconds one pass lasts, whether or not the voice loops. 0 has no passes: phase and pass stay 0. */
127
+ readonly duration: number;
128
+ /** The channels this patch contributes to. Every key `at` sets, and no others. */
129
+ readonly writes: readonly (keyof O)[];
130
+ /**
131
+ * The channels this patch was written against. `cue` refuses a mix whose channel of the same name
132
+ * is of another kind, so a patch published in one package cannot fold by another's arithmetic.
133
+ */
134
+ readonly kit?: Partial<Kit<O>>;
135
+ /** The fields of `setting.host` this patch reads. `cue` refuses a mix whose host lacks one. */
136
+ readonly reads?: readonly string[];
137
+ /**
138
+ * `phase` is 0..1 across one pass, wrapping. Not asked for a subject its voice gives no weight, unless the voice is fading to rest;
139
+ * `step` still runs. A `keys` patch's stops are not read there either, unless its voice is in a locus.
140
+ */
141
+ at(phase: number, subject: I, setting: Setting<S, H>): Partial<O>;
142
+ /** Per-subject state, created on the first frame this patch sees a subject. */
143
+ state?(subject: I): S;
144
+ /**
145
+ * Advances state once per subject per sampled frame, by the whole gap since it last advanced; or,
146
+ * where the mix sets `stepMs`, once per whole interval of that length.
147
+ */
148
+ step?(state: S, dt: number, subject: I, setting: Setting<S, H>): void;
149
+ /** Present when the patch was authored as keyframes, so an engine that reads data can. */
150
+ readonly keys?: readonly Keyframe<O>[];
151
+ /**
152
+ * Present on a `keys` patch that was given them: what `keys` took besides its stops, each as
153
+ * `KeysOptions` describes it. They are read off the patch, so a copy that changes one, as
154
+ * `{ ...p, ease: 'linear' }` does, plays by its own.
155
+ */
156
+ readonly ease?: Easing;
157
+ easeBy?(channel: keyof O): Easing | undefined;
158
+ delayBy?(channel: keyof O): number;
159
+ lerpBy?(channel: keyof O): ((a: never, b: never, u: number) => unknown) | undefined;
160
+ /** Present on a `wave` patch: what `wave` took, which a copy may change as it may a `keys` field. */
161
+ readonly wave?: WaveOptions<O>;
162
+ /** Present on a `'motion'` patch: its kind and constants, for an engine that reads data. */
163
+ readonly motion?: MotionSpec;
164
+ /**
165
+ * A copy of `state` that shares nothing with it, for a read at another time. Default
166
+ * `structuredClone`, which is enough for plain data; a state holding a class instance or a
167
+ * function needs its own.
168
+ */
169
+ clone?(state: S): S;
170
+ /**
171
+ * `state` as data that survives `structuredClone`, for a history `store` to keep; `unpack` makes
172
+ * a state from it again. With a store, a patch with `state` or `step` needs both, or `cue`
173
+ * refuses it.
174
+ */
175
+ pack?(state: S): unknown;
176
+ unpack?(data: unknown): S;
177
+ }
178
+ /**
179
+ * A 0..1 scalar resolved per subject per frame from something outside the clock. `input` is set
180
+ * when it reads something the clock does not drive, such as a value the host writes; a signal
181
+ * built on one inherits it.
182
+ *
183
+ * @category signal
184
+ */
185
+ export type Signal<I, H = unknown> = ((subject: I, setting: Setting<void, H>) => number) & {
186
+ readonly input?: boolean;
187
+ };
@@ -0,0 +1 @@
1
+ export {};