@msb235/blits 0.14.0 → 0.15.1
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/CHANGELOG.md +198 -0
- package/README.md +3 -3
- package/dist/ahead.d.ts +26 -0
- package/dist/ahead.js +264 -0
- package/dist/around.d.ts +11 -0
- package/dist/around.js +32 -0
- package/dist/bare.js +37 -14
- package/dist/blank.d.ts +10 -0
- package/dist/blank.js +26 -0
- package/dist/blend.d.ts +2 -1
- package/dist/blend.js +1 -6
- package/dist/bound.d.ts +70 -0
- package/dist/bound.js +351 -0
- package/dist/chain.d.ts +2 -1
- package/dist/chain.js +7 -5
- package/dist/changes.d.ts +24 -0
- package/dist/changes.js +189 -0
- package/dist/channels.d.ts +39 -13
- package/dist/channels.js +14 -5
- package/dist/color.d.ts +12 -10
- package/dist/color.js +25 -25
- package/dist/columns.d.ts +2 -1
- package/dist/columns.js +62 -38
- package/dist/contribution.d.ts +30 -0
- package/dist/contribution.js +374 -0
- package/dist/copyout.d.ts +10 -0
- package/dist/copyout.js +69 -24
- package/dist/crowd.d.ts +16 -6
- package/dist/crowd.js +20 -11
- package/dist/cue.d.ts +8 -1
- package/dist/cue.js +39 -13
- package/dist/cut.d.ts +8 -0
- package/dist/cut.js +4 -0
- package/dist/delay.d.ts +3 -0
- package/dist/delay.js +7 -0
- package/dist/drop.d.ts +9 -0
- package/dist/drop.js +84 -0
- package/dist/due.d.ts +24 -5
- package/dist/due.js +114 -34
- package/dist/easing.d.ts +6 -4
- package/dist/easing.js +7 -3
- package/dist/everyone.d.ts +8 -2
- package/dist/everyone.js +33 -3
- package/dist/fade.d.ts +2 -1
- package/dist/fade.js +2 -1
- package/dist/fill.d.ts +3 -2
- package/dist/fill.js +52 -20
- package/dist/fit.d.ts +44 -26
- package/dist/fit.js +10 -9
- package/dist/fold.d.ts +4 -37
- package/dist/fold.js +5 -513
- package/dist/gather.d.ts +12 -7
- package/dist/gather.js +179 -44
- package/dist/gone.js +2 -2
- package/dist/grid.d.ts +47 -0
- package/dist/grid.js +247 -0
- package/dist/handle.d.ts +2 -0
- package/dist/handle.js +14 -8
- package/dist/held.d.ts +2 -1
- package/dist/held.js +2 -1
- package/dist/history.d.ts +6 -5
- package/dist/history.js +7 -9
- package/dist/hosts.js +9 -15
- package/dist/index.d.ts +5 -4
- package/dist/keyfill.d.ts +1 -1
- package/dist/keyfill.js +5 -3
- package/dist/keyrows.d.ts +12 -0
- package/dist/keyrows.js +99 -12
- package/dist/lane.d.ts +38 -11
- package/dist/lane.js +46 -11
- package/dist/lanes.d.ts +30 -12
- package/dist/lanes.js +56 -36
- package/dist/leavings.d.ts +2 -2
- package/dist/leavings.js +1 -1
- package/dist/lives.d.ts +47 -0
- package/dist/lives.js +180 -0
- package/dist/meet.d.ts +2 -2
- package/dist/meet.js +95 -7
- package/dist/mixer.d.ts +56 -37
- package/dist/mixer.js +57 -171
- package/dist/motion.d.ts +14 -118
- package/dist/motion.js +16 -8
- package/dist/motions.d.ts +62 -155
- package/dist/motions.js +56 -370
- package/dist/moved.d.ts +1 -1
- package/dist/moved.js +16 -7
- package/dist/named.d.ts +6 -2
- package/dist/named.js +49 -3
- package/dist/numbers.d.ts +7 -0
- package/dist/numbers.js +33 -0
- package/dist/owed.d.ts +2 -0
- package/dist/owed.js +4 -0
- package/dist/pack.d.ts +2 -1
- package/dist/pack.js +2 -3
- package/dist/patch.d.ts +7 -3
- package/dist/patch.js +6 -2
- package/dist/places.d.ts +53 -0
- package/dist/places.js +171 -0
- package/dist/plot.d.ts +12 -0
- package/dist/plot.js +52 -0
- package/dist/project.d.ts +4 -4
- package/dist/project.js +9 -212
- package/dist/pull.js +22 -9
- package/dist/qualify.js +93 -31
- package/dist/reading.d.ts +6 -0
- package/dist/reading.js +5 -0
- package/dist/record.d.ts +5 -1
- package/dist/record.js +3 -2
- package/dist/relink.d.ts +1 -1
- package/dist/renumber.d.ts +10 -0
- package/dist/renumber.js +75 -0
- package/dist/restored.d.ts +2 -2
- package/dist/restored.js +1 -1
- package/dist/rests.d.ts +9 -0
- package/dist/rests.js +76 -0
- package/dist/revive.d.ts +3 -2
- package/dist/revive.js +2 -2
- package/dist/{locus.d.ts → role.d.ts} +10 -9
- package/dist/{locus.js → role.js} +3 -3
- package/dist/roles.d.ts +10 -0
- package/dist/roles.js +158 -0
- package/dist/roster.js +3 -3
- package/dist/rotation.d.ts +1 -1
- package/dist/rotation.js +1 -1
- package/dist/rows.js +28 -20
- package/dist/sample.d.ts +2 -2
- package/dist/sample.js +33 -7
- package/dist/seat.d.ts +17 -0
- package/dist/seat.js +25 -0
- package/dist/seek.js +5 -5
- package/dist/setting.d.ts +27 -0
- package/dist/setting.js +55 -0
- package/dist/shared.d.ts +1 -1
- package/dist/shared.js +1 -1
- package/dist/signals.d.ts +64 -32
- package/dist/signals.js +20 -18
- package/dist/stack.d.ts +5 -5
- package/dist/stack.js +5 -5
- package/dist/standing.d.ts +2 -1
- package/dist/standing.js +3 -2
- package/dist/store.d.ts +9 -0
- package/dist/store.js +24 -0
- package/dist/strays.d.ts +2 -1
- package/dist/strays.js +23 -15
- package/dist/stretch.d.ts +112 -0
- package/dist/stretch.js +9 -0
- package/dist/subject.d.ts +142 -0
- package/dist/subject.js +1 -0
- package/dist/tape.d.ts +9 -5
- package/dist/tape.js +5 -1
- package/dist/then.d.ts +9 -0
- package/dist/then.js +57 -0
- package/dist/ticker.d.ts +4 -4
- package/dist/trace.d.ts +4 -0
- package/dist/trace.js +255 -0
- package/dist/transport.d.ts +0 -8
- package/dist/transport.js +0 -4
- package/dist/turns.d.ts +4 -3
- package/dist/turns.js +4 -3
- package/dist/types/arc.d.ts +12 -11
- package/dist/types/channel.d.ts +12 -8
- package/dist/types/history.d.ts +35 -19
- package/dist/types/mix.d.ts +237 -163
- package/dist/types/motion.d.ts +151 -0
- package/dist/types/motion.js +1 -0
- package/dist/types/patch.d.ts +67 -34
- package/dist/types/place.d.ts +51 -36
- package/dist/types/trace.d.ts +51 -0
- package/dist/types/trace.js +1 -0
- package/dist/types/transport.d.ts +20 -18
- package/dist/types/voice.d.ts +144 -73
- package/dist/types/watch.d.ts +88 -40
- package/dist/types.d.ts +2 -0
- package/dist/unreached.d.ts +2 -0
- package/dist/unreached.js +7 -0
- package/dist/voice.d.ts +10 -143
- package/dist/voice.js +37 -82
- package/dist/warn.d.ts +2 -0
- package/dist/warn.js +1 -1
- package/dist/watch.d.ts +2 -2
- package/dist/watch.js +5 -3
- package/dist/wave.d.ts +4 -3
- package/dist/wave.js +3 -2
- package/dist/weigh.d.ts +7 -1
- package/dist/weigh.js +27 -0
- package/docs/schema.html +223 -34
- package/package.json +2 -2
package/dist/mixer.js
CHANGED
|
@@ -1,35 +1,43 @@
|
|
|
1
1
|
import { cueArc } from './arcs.js';
|
|
2
|
+
import { around } from './around.js';
|
|
3
|
+
import { blanks } from './blank.js';
|
|
2
4
|
import { blended, blendOf, laneRead, shareKept } from './blend.js';
|
|
3
|
-
import { aims, chain,
|
|
5
|
+
import { aims, chain, linkable, relink } from './chain.js';
|
|
4
6
|
import { lerpInto, STOCK_BAND, scalarOp } from './channels.js';
|
|
5
|
-
import {
|
|
7
|
+
import { baseFor, contribution, isRest, keyed, read, slopeFor, tick } from './contribution.js';
|
|
8
|
+
import { cue, roleTags } from './cue.js';
|
|
6
9
|
import { DepartedIndex } from './departed.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
+
import { drop, forgetIn, recordDrop, releaseIn } from './drop.js';
|
|
11
|
+
import { DueQueue } from './due.js';
|
|
12
|
+
import { beginFade, parting } from './fade.js';
|
|
13
|
+
import { apply, clamp, fold, foldDetour, folded, foldSharers, foldWith, linked, owedBy, passes, shared, } from './fold.js';
|
|
14
|
+
import { GoneIndex } from './gone.js';
|
|
10
15
|
import { held, shownOf, sinceOf, unreachedOf } from './held.js';
|
|
11
|
-
import { releasing } from './history.js';
|
|
12
16
|
import { book, laneHost } from './hosts.js';
|
|
13
17
|
import { Lanes } from './lanes.js';
|
|
14
|
-
import { foldLocus } from './locus.js';
|
|
15
18
|
import { listed } from './marks.js';
|
|
16
19
|
import { nextFrame } from './move.js';
|
|
17
20
|
import { ownerPatch } from './owner.js';
|
|
18
21
|
import { Keys } from './paging.js';
|
|
22
|
+
import { moved, place, plot, put } from './plot.js';
|
|
19
23
|
import { projectAll } from './project.js';
|
|
20
24
|
import { keep, pull } from './pull.js';
|
|
21
25
|
import { Steps } from './relink.js';
|
|
26
|
+
import { atRest, restful, rests, restsKey, restsLaned, still } from './rests.js';
|
|
22
27
|
import { Outs } from './revive.js';
|
|
28
|
+
import { foldRole } from './role.js';
|
|
29
|
+
import { foldRoles } from './roles.js';
|
|
23
30
|
import { ScoreIndex } from './scored.js';
|
|
24
31
|
import { seek } from './seek.js';
|
|
25
32
|
import { Fitting, refit } from './spans.js';
|
|
26
|
-
import {
|
|
27
|
-
import { record
|
|
33
|
+
import { Store } from './store.js';
|
|
34
|
+
import { record } from './tape.js';
|
|
28
35
|
import { touch } from './touch.js';
|
|
36
|
+
import { traceMix } from './trace.js';
|
|
29
37
|
import { announce, Transport } from './transport.js';
|
|
30
38
|
import { none } from './voice.js';
|
|
31
39
|
import { gave, historyFor, register, unregister } from './watch.js';
|
|
32
|
-
import { base, capped, fadeOf, horizonFor, ownedBy, ownerBase, prime, weigh, weighOwned, } from './weigh.js';
|
|
40
|
+
import { base, capped, fadeOf, horizonFor, ownedBy, ownerBase, prime, primeLaned, weigh, weighOwned, } from './weigh.js';
|
|
33
41
|
/**
|
|
34
42
|
* What a mix takes where its options say nothing. Not exported from the package: the suite turns
|
|
35
43
|
* `lanes` off to run every test on the general path, which is what makes each one an equivalence check.
|
|
@@ -63,7 +71,7 @@ export class Mixer {
|
|
|
63
71
|
hostLog = [];
|
|
64
72
|
hostThen;
|
|
65
73
|
/** Each subject's last two poses and when they were probed, for `from: 'current'`. */
|
|
66
|
-
|
|
74
|
+
lastPoses = new Store();
|
|
67
75
|
/** The clock this mix plays on, which also holds its tape and the marks announced on it. */
|
|
68
76
|
transport;
|
|
69
77
|
/** Its place among the mixes on its transport, in the order they joined. */
|
|
@@ -82,7 +90,7 @@ export class Mixer {
|
|
|
82
90
|
/** The pose `pull` folds a subject into where it cannot read straight from the lanes. */
|
|
83
91
|
scratch;
|
|
84
92
|
/** Live voices by the earliest mix time `moveTo` would change each, a binary heap. */
|
|
85
|
-
due =
|
|
93
|
+
due = new DueQueue();
|
|
86
94
|
/** Voices retired since `moveTo` last pruned them, in the order they retired. */
|
|
87
95
|
retired = [];
|
|
88
96
|
/** Visit every voice each sync, as before the due queue; for tests that compare the two. */
|
|
@@ -151,6 +159,8 @@ export class Mixer {
|
|
|
151
159
|
*/
|
|
152
160
|
chains = new Store();
|
|
153
161
|
version = 0;
|
|
162
|
+
/** The positions `plot` gave, which a voice's `within` reads: see `bound.ts`. */
|
|
163
|
+
places = null;
|
|
154
164
|
/** What `prime` reads its clock, voice time and pass from: see `Primed`. */
|
|
155
165
|
primed = new Float64Array(3 /* Primed.SIZE */);
|
|
156
166
|
steps = new Steps();
|
|
@@ -182,8 +192,10 @@ export class Mixer {
|
|
|
182
192
|
unshared = false;
|
|
183
193
|
/** 0 where a fold is a walk of the chain: see `detour` in `everyone.ts`. */
|
|
184
194
|
detours = 0;
|
|
185
|
-
/** How many voices in the list carry a
|
|
186
|
-
|
|
195
|
+
/** How many voices in the list carry a role; with none, a fold allocates nothing. */
|
|
196
|
+
roleVoices = 0;
|
|
197
|
+
/** The tags the mix's options declare roles. */
|
|
198
|
+
roleTags;
|
|
187
199
|
/** What every motion patch it plays asks for its voice's time, holding this mix weakly. */
|
|
188
200
|
owner = null;
|
|
189
201
|
/** How many voices in the list are anchored, so a sync with none skips placing them. */
|
|
@@ -218,9 +230,9 @@ export class Mixer {
|
|
|
218
230
|
lerpsInto;
|
|
219
231
|
/** By slot, a stock scalar channel's arithmetic, which a fold applies without calling the channel. */
|
|
220
232
|
scalars;
|
|
221
|
-
/** What a fold with a
|
|
222
|
-
|
|
223
|
-
|
|
233
|
+
/** What a fold with a role in play gathers into, one per depth of folds under way. */
|
|
234
|
+
roleScratch = [];
|
|
235
|
+
roleDepth = 0;
|
|
224
236
|
slotOf = new Map();
|
|
225
237
|
lanes;
|
|
226
238
|
handles = null;
|
|
@@ -236,6 +248,7 @@ export class Mixer {
|
|
|
236
248
|
keys = null;
|
|
237
249
|
/** With a history store, the voices it paged out whose handles are still held; null without one. */
|
|
238
250
|
outs = null;
|
|
251
|
+
pose;
|
|
239
252
|
constructor(kit, opts,
|
|
240
253
|
/** The lanes an entry was built with; null in one that leaves them out. */
|
|
241
254
|
lanesOf) {
|
|
@@ -246,6 +259,7 @@ export class Mixer {
|
|
|
246
259
|
this.channels = this.names.map((k) => kit[k]);
|
|
247
260
|
this.bounded = this.channels.flatMap((c, i) => (c.bounds ? [i] : []));
|
|
248
261
|
this.lerpsInto = this.channels.map((c) => lerpInto(c));
|
|
262
|
+
this.pose = blanks(this.names, this.channels);
|
|
249
263
|
this.scalars = this.channels.map((c) => scalarOp(c));
|
|
250
264
|
this.names.forEach((k, i) => {
|
|
251
265
|
this.slotOf.set(k, i);
|
|
@@ -255,6 +269,7 @@ export class Mixer {
|
|
|
255
269
|
this.lanes =
|
|
256
270
|
lanesOf !== null && (opts.lanes ?? defaults.lanes) ? new lanesOf(laneHost(this)) : null;
|
|
257
271
|
this.name = opts.name;
|
|
272
|
+
this.roleTags = roleTags(opts);
|
|
258
273
|
const shared = opts.transport;
|
|
259
274
|
if (shared !== undefined) {
|
|
260
275
|
if (opts.history !== undefined)
|
|
@@ -345,14 +360,14 @@ export class Mixer {
|
|
|
345
360
|
return cue(this, spec);
|
|
346
361
|
}
|
|
347
362
|
blend(members, by, spec = {}) {
|
|
348
|
-
const
|
|
363
|
+
const role = `blend:${this.nextId}`;
|
|
349
364
|
const of = blendOf(by, members.length - 1);
|
|
350
365
|
return members.map((member, i) => {
|
|
351
366
|
const own = {
|
|
352
367
|
...spec,
|
|
353
368
|
patch: member,
|
|
354
369
|
weight: by,
|
|
355
|
-
|
|
370
|
+
role,
|
|
356
371
|
};
|
|
357
372
|
if ('patch' in member) {
|
|
358
373
|
own.patch = member.patch;
|
|
@@ -421,6 +436,9 @@ export class Mixer {
|
|
|
421
436
|
project(at) {
|
|
422
437
|
return projectAll(this.transport, at).of(this);
|
|
423
438
|
}
|
|
439
|
+
trace(from, to, opts) {
|
|
440
|
+
return traceMix(this, from, to, opts);
|
|
441
|
+
}
|
|
424
442
|
announce(name, opts = {}) {
|
|
425
443
|
this.attached();
|
|
426
444
|
announce(this.transport, name, opts, this.slot, this.name);
|
|
@@ -433,38 +451,6 @@ export class Mixer {
|
|
|
433
451
|
marks(from, to) {
|
|
434
452
|
return listed(this, from, to).map(({ order: _, ...m }) => m);
|
|
435
453
|
}
|
|
436
|
-
atRest(subject) {
|
|
437
|
-
this.restStamps ??= new Store();
|
|
438
|
-
const head = this.linked(subject);
|
|
439
|
-
const laned = this.linkedLaned;
|
|
440
|
-
const lanes = this.lanes;
|
|
441
|
-
// Every voice on lanes and nothing to clamp: the pose a fold would make is the lanes' values.
|
|
442
|
-
if (laned && this.restsLaned()) {
|
|
443
|
-
const slot = head.slot;
|
|
444
|
-
if (!lanes.owes(slot))
|
|
445
|
-
return lanes.rests(slot);
|
|
446
|
-
}
|
|
447
|
-
// A probe this frame answers for the pose it gave the host.
|
|
448
|
-
const since = (this.restStamps.get(subject) ?? Number.NaN) - 2 * this.restsKey();
|
|
449
|
-
if (since >= 0)
|
|
450
|
-
return since === 1;
|
|
451
|
-
this.restScratch ??= {};
|
|
452
|
-
const pose = this.foldWith(subject, this.restScratch, head, laned, true);
|
|
453
|
-
return this.rests((this.bounded.length === 0 ? pose : this.clamp(pose)));
|
|
454
|
-
}
|
|
455
|
-
rests(pose) {
|
|
456
|
-
for (let i = 0; i < this.names.length; i++) {
|
|
457
|
-
const channel = this.channels[i];
|
|
458
|
-
const value = pose[this.names[i]];
|
|
459
|
-
if (channel.rest === undefined) {
|
|
460
|
-
if (value !== undefined)
|
|
461
|
-
return false;
|
|
462
|
-
}
|
|
463
|
-
else if (!near(value, channel.rest))
|
|
464
|
-
return false;
|
|
465
|
-
}
|
|
466
|
-
return true;
|
|
467
|
-
}
|
|
468
454
|
rebase() {
|
|
469
455
|
this.own('rebase').rebase();
|
|
470
456
|
}
|
|
@@ -486,16 +472,6 @@ export class Mixer {
|
|
|
486
472
|
this.asleep = true;
|
|
487
473
|
return inert;
|
|
488
474
|
}
|
|
489
|
-
restful() {
|
|
490
|
-
// Standing still, a voice changes no pose but by its weight signal, or by an anchor or start
|
|
491
|
-
// that host time may yet reach.
|
|
492
|
-
if (this.pace?.stopped(this.u))
|
|
493
|
-
return this.cued.every((v) => v.state === 'done' ||
|
|
494
|
-
(v.state !== 'pending' &&
|
|
495
|
-
typeof v.spec.weight !== 'function' &&
|
|
496
|
-
v.spec.anchor === undefined));
|
|
497
|
-
return this.cued.every((v) => this.still(v, this.now));
|
|
498
|
-
}
|
|
499
475
|
get rate() {
|
|
500
476
|
return this.transport.rate;
|
|
501
477
|
}
|
|
@@ -505,22 +481,6 @@ export class Mixer {
|
|
|
505
481
|
ramp(rate, over) {
|
|
506
482
|
this.own('ramp').ramp(rate, over);
|
|
507
483
|
}
|
|
508
|
-
/** Whether a voice will change no pose from `now` on, short of a change made to it. */
|
|
509
|
-
still(voice, now) {
|
|
510
|
-
if (voice.state === 'done')
|
|
511
|
-
return true;
|
|
512
|
-
if (voice.state !== 'frozen' && voice.state !== 'live')
|
|
513
|
-
return false;
|
|
514
|
-
if (typeof voice.spec.weight === 'function' || voice.parts !== null)
|
|
515
|
-
return false;
|
|
516
|
-
const fadeIn = this.reducedNow ? 0 : (voice.fade.in ?? 0);
|
|
517
|
-
if (fadeIn > 0 && now - this.sinceOf(voice, voice.latest) < fadeIn)
|
|
518
|
-
return false;
|
|
519
|
-
if (voice.state === 'frozen' || voice.holding !== null)
|
|
520
|
-
return true;
|
|
521
|
-
const motion = voice.motion;
|
|
522
|
-
return motion !== undefined && voice.elapsedAt(now) >= voice.latest && motion.landed();
|
|
523
|
-
}
|
|
524
484
|
close() {
|
|
525
485
|
unregister(this);
|
|
526
486
|
}
|
|
@@ -531,80 +491,6 @@ export class Mixer {
|
|
|
531
491
|
}
|
|
532
492
|
record(this, 'mute', (stage) => stage.mix(this)?.mute(opts));
|
|
533
493
|
}
|
|
534
|
-
drop(subject) {
|
|
535
|
-
this.frame = nextFrame();
|
|
536
|
-
const head = headOf(this, subject);
|
|
537
|
-
// Nothing that kept this head, such as `pull`'s remembered list, may take it as current again.
|
|
538
|
-
if (head !== undefined)
|
|
539
|
-
unlink(this, head);
|
|
540
|
-
// A number a seek carried over is released even where its chain is not linked since.
|
|
541
|
-
const slot = this.chains.get(subject)?.slot ?? -1;
|
|
542
|
-
if (slot >= 0 && this.lanes !== null)
|
|
543
|
-
this.lanes.release(slot);
|
|
544
|
-
// A read ahead's copy reads the live mix's poses, and so hides one where the mix deletes it.
|
|
545
|
-
if (this.projecting && !(this.pose instanceof Masked))
|
|
546
|
-
this.pose = new Masked(this.pose);
|
|
547
|
-
this.pose.delete(subject);
|
|
548
|
-
this.restStamps?.delete(subject);
|
|
549
|
-
this.chains.delete(subject);
|
|
550
|
-
this.stir();
|
|
551
|
-
// A record of it is only in a voice over every subject, one naming it, or one gone; a ramp out
|
|
552
|
-
// of a voice that does not name it is in `parters`, and a patch's own state in `motions`.
|
|
553
|
-
const kept = releasing(this);
|
|
554
|
-
for (const voice of this.general)
|
|
555
|
-
this.forgetIn(voice, subject, kept);
|
|
556
|
-
const named = this.named.get(subject);
|
|
557
|
-
if (named !== undefined)
|
|
558
|
-
for (const voice of [...named])
|
|
559
|
-
this.forgetIn(voice, subject, kept);
|
|
560
|
-
const gone = goneIndex(this);
|
|
561
|
-
for (const voice of gone.general)
|
|
562
|
-
this.forgetIn(voice, subject, kept);
|
|
563
|
-
const goneNaming = gone.named.get(subject);
|
|
564
|
-
if (goneNaming !== undefined)
|
|
565
|
-
for (const voice of goneNaming)
|
|
566
|
-
this.forgetIn(voice, subject, kept);
|
|
567
|
-
if (this.owners !== null)
|
|
568
|
-
for (const voice of this.owners)
|
|
569
|
-
this.forgetIn(voice, subject, kept);
|
|
570
|
-
for (const voice of this.parters) {
|
|
571
|
-
this.forgetIn(voice, subject, kept);
|
|
572
|
-
if (voice.parts?.size === 0)
|
|
573
|
-
voice.parts = null;
|
|
574
|
-
if (voice.parted?.size === 0)
|
|
575
|
-
voice.parted = null;
|
|
576
|
-
if (voice.parts === null && voice.parted === null)
|
|
577
|
-
this.parters.delete(voice);
|
|
578
|
-
}
|
|
579
|
-
const strays = this.strays.get(subject);
|
|
580
|
-
if (strays !== undefined)
|
|
581
|
-
for (const motion of strays)
|
|
582
|
-
this.releaseIn(motion, subject, kept);
|
|
583
|
-
this.strays.delete(subject);
|
|
584
|
-
for (const motion of this.strayAll)
|
|
585
|
-
this.releaseIn(motion, subject, kept);
|
|
586
|
-
this.recordDrop(subject);
|
|
587
|
-
}
|
|
588
|
-
/** Lets `voice` go of a dropped subject. Methods rather than closures, so a drop makes neither. */
|
|
589
|
-
forgetIn(voice, subject, kept) {
|
|
590
|
-
leaveVoice(this, voice, subject);
|
|
591
|
-
voice.subjects.delete(subject);
|
|
592
|
-
if (voice.motion !== undefined)
|
|
593
|
-
this.releaseIn(voice.motion, subject, kept);
|
|
594
|
-
voice.parts?.delete(subject);
|
|
595
|
-
voice.parted?.delete(subject);
|
|
596
|
-
voice.blend?.of.reads.delete(subject);
|
|
597
|
-
}
|
|
598
|
-
// A motion patch's state is the live mix's alone: a read ahead cannot start a subject afresh in it.
|
|
599
|
-
releaseIn(motion, subject, kept) {
|
|
600
|
-
if (!this.projecting)
|
|
601
|
-
motion.release(subject, kept[0], kept[1], kept[2]);
|
|
602
|
-
else if (motion.holds(subject))
|
|
603
|
-
unplayable('a drop of a subject a motion patch holds');
|
|
604
|
-
}
|
|
605
|
-
recordDrop(subject) {
|
|
606
|
-
record(this, 'drop', (stage) => stage.mix(this)?.drop(subject));
|
|
607
|
-
}
|
|
608
494
|
touch(subject) {
|
|
609
495
|
this.attached();
|
|
610
496
|
touch(this, subject);
|
|
@@ -641,22 +527,6 @@ export class Mixer {
|
|
|
641
527
|
restsStirs = -1;
|
|
642
528
|
/** The pose `atRest` folds into where no probe this frame answers. */
|
|
643
529
|
restScratch;
|
|
644
|
-
restsLaned() {
|
|
645
|
-
return this.lanes.whole && this.bounded.length === 0;
|
|
646
|
-
}
|
|
647
|
-
restsKey() {
|
|
648
|
-
if (this.frame !== this.restsFrame ||
|
|
649
|
-
this.version !== this.restsVersion ||
|
|
650
|
-
this.relinks !== this.restsRelinks ||
|
|
651
|
-
this.stirs !== this.restsStirs) {
|
|
652
|
-
this.restsEpoch++;
|
|
653
|
-
this.restsFrame = this.frame;
|
|
654
|
-
this.restsVersion = this.version;
|
|
655
|
-
this.restsRelinks = this.relinks;
|
|
656
|
-
this.restsStirs = this.stirs;
|
|
657
|
-
}
|
|
658
|
-
return this.restsEpoch;
|
|
659
|
-
}
|
|
660
530
|
}
|
|
661
531
|
// The probe's hot path is methods, installed here from the modules that own them: as functions
|
|
662
532
|
// called directly they made probes and fills up to 9% slower (bench/ab.sh on teitou, 2026-10-05).
|
|
@@ -666,7 +536,7 @@ const methods = {
|
|
|
666
536
|
linked,
|
|
667
537
|
foldWith,
|
|
668
538
|
owedBy,
|
|
669
|
-
|
|
539
|
+
foldRoles,
|
|
670
540
|
foldDetour,
|
|
671
541
|
foldSharers,
|
|
672
542
|
shared,
|
|
@@ -681,6 +551,7 @@ const methods = {
|
|
|
681
551
|
baseFor,
|
|
682
552
|
slopeFor,
|
|
683
553
|
prime,
|
|
554
|
+
primeLaned,
|
|
684
555
|
capped,
|
|
685
556
|
horizonFor,
|
|
686
557
|
weigh,
|
|
@@ -702,7 +573,22 @@ const methods = {
|
|
|
702
573
|
sinceOf,
|
|
703
574
|
shownOf,
|
|
704
575
|
keep,
|
|
705
|
-
|
|
576
|
+
foldRole,
|
|
577
|
+
atRest,
|
|
578
|
+
rests,
|
|
579
|
+
restful,
|
|
580
|
+
still,
|
|
581
|
+
restsLaned,
|
|
582
|
+
restsKey,
|
|
583
|
+
plot,
|
|
584
|
+
place,
|
|
585
|
+
moved,
|
|
586
|
+
put,
|
|
587
|
+
around,
|
|
588
|
+
drop,
|
|
589
|
+
forgetIn,
|
|
590
|
+
releaseIn,
|
|
591
|
+
recordDrop,
|
|
706
592
|
};
|
|
707
593
|
for (const [name, value] of Object.entries(methods))
|
|
708
594
|
Object.defineProperty(Mixer.prototype, name, { value, writable: true, configurable: true });
|
|
@@ -724,7 +610,7 @@ export function made(kit, opts, lanes) {
|
|
|
724
610
|
return m;
|
|
725
611
|
}
|
|
726
612
|
/**
|
|
727
|
-
* The
|
|
613
|
+
* The engine that ships, running every form on the CPU. It probes per subject on demand.
|
|
728
614
|
*
|
|
729
615
|
* @category engine
|
|
730
616
|
*/
|
|
@@ -736,7 +622,7 @@ export const mixer = {
|
|
|
736
622
|
},
|
|
737
623
|
};
|
|
738
624
|
/**
|
|
739
|
-
* Makes a mix over a kit
|
|
625
|
+
* Makes a mix over a kit. It runs on the engine the options name, or the stock one.
|
|
740
626
|
*
|
|
741
627
|
* @category mix
|
|
742
628
|
*/
|
package/dist/motion.d.ts
CHANGED
|
@@ -1,69 +1,11 @@
|
|
|
1
1
|
import { Motions } from './motions.js';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
* A number, or one number per axis.
|
|
5
|
-
*
|
|
6
|
-
* @category patch
|
|
7
|
-
*/
|
|
8
|
-
export type Value = number | readonly number[];
|
|
9
|
-
/**
|
|
10
|
-
* One value for every subject, or one per subject.
|
|
11
|
-
*
|
|
12
|
-
* @category patch
|
|
13
|
-
*/
|
|
14
|
-
export type PerSubject<I, V> = V | ((subject: I) => V);
|
|
15
|
-
/**
|
|
16
|
-
* Where a subject is and how fast it is moving, at one moment of voice time.
|
|
17
|
-
*
|
|
18
|
-
* @category patch
|
|
19
|
-
*/
|
|
20
|
-
export interface Motion<V extends Value = number> {
|
|
21
|
-
value: V;
|
|
22
|
-
/** Units per second. */
|
|
23
|
-
velocity: V;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* A patch whose motion is a closed form per subject, so it lands in the same place at any frame
|
|
27
|
-
* rate, and whose changes mid-flight start from where the subject is and how fast it moves.
|
|
28
|
-
*
|
|
29
|
-
* @category patch
|
|
30
|
-
*/
|
|
31
|
-
export type Moving<I, O, V extends Value> = Patch<I, O, void> & {
|
|
32
|
-
/**
|
|
33
|
-
* Where `subject` is and how fast it moves at voice time `at`, default the mix's latest frame,
|
|
34
|
-
* counting every change due by then. With no time given, undefined until a frame of its voice
|
|
35
|
-
* has met the subject, while the subject is still inside its stagger, and once that voice is gone.
|
|
36
|
-
* At any time, undefined for a subject the patch has never met or changed, or that the mix
|
|
37
|
-
* dropped.
|
|
38
|
-
*/
|
|
39
|
-
read(subject: I, at?: number): Motion<V> | undefined;
|
|
40
|
-
/**
|
|
41
|
-
* Sets `subject` moving at `velocity`, units per second, from voice time `at`, default the mix's
|
|
42
|
-
* latest frame; for a subject no frame of its voice has met yet, or still inside its stagger, its
|
|
43
|
-
* first read, after any change with a time due by then. A subject faded out of the voice comes
|
|
44
|
-
* back at the latest frame too, however long it is before it is next read.
|
|
45
|
-
*/
|
|
46
|
-
push(subject: I, velocity: V, at?: number): void;
|
|
47
|
-
/**
|
|
48
|
-
* Puts `subject` at `value` from voice time `at`, keeping its velocity, with `at` defaulting as
|
|
49
|
-
* `push`'s does: a spring or tween heads for its target from there, a glide coasts on from there.
|
|
50
|
-
*/
|
|
51
|
-
set(subject: I, value: V, at?: number): void;
|
|
52
|
-
};
|
|
2
|
+
import type { Glide, GlideOptions, Spring, SpringOptions, Tween, TweenOptions, Value } from './types/motion.js';
|
|
3
|
+
export type { Glide, GlideOptions, Motion, MotionOptions, Moving, PerSubject, Spring, SpringOptions, Tween, TweenOptions, Value, } from './types/motion.js';
|
|
53
4
|
/**
|
|
54
5
|
* The state behind a `'motion'` patch, for an engine that reads it directly; a patch another copy
|
|
55
6
|
* of the same release made counts.
|
|
56
7
|
*/
|
|
57
8
|
export declare function motionOf<I>(p: object): Motions<I> | undefined;
|
|
58
|
-
interface Common<I, V extends Value> {
|
|
59
|
-
/** Units per second each subject starts moving at. Default 0. */
|
|
60
|
-
velocity?: PerSubject<I, V>;
|
|
61
|
-
/**
|
|
62
|
-
* Within this distance of where it heads, and this slow, a subject lands there exactly, so a mix
|
|
63
|
-
* can see it at rest. Default 1e-4; 0 keeps the curve exact.
|
|
64
|
-
*/
|
|
65
|
-
settle?: number;
|
|
66
|
-
}
|
|
67
9
|
/**
|
|
68
10
|
* A damped spring toward a target, solved in closed form. `to(subject, target)` retargets one
|
|
69
11
|
* subject mid-flight, and the new stretch starts from where it is and how fast it moves, so there is
|
|
@@ -72,28 +14,12 @@ interface Common<I, V extends Value> {
|
|
|
72
14
|
*
|
|
73
15
|
* @category patch
|
|
74
16
|
*/
|
|
75
|
-
export declare function spring<I, O, V extends Value = number>(writes: keyof O, opts:
|
|
76
|
-
to: PerSubject<I, V>;
|
|
77
|
-
/** Where each subject starts. Default: `to`, at rest. */
|
|
78
|
-
from?: PerSubject<I, V>;
|
|
79
|
-
/** Per second squared. Default 170. */
|
|
80
|
-
stiffness?: number;
|
|
81
|
-
/** Per second. Default 26, just short of critical at the default stiffness. */
|
|
82
|
-
damping?: number;
|
|
83
|
-
mass?: number;
|
|
84
|
-
}): Moving<I, O, V> & {
|
|
85
|
-
/**
|
|
86
|
-
* Heads `subject` for `target` from voice time `at`, keeping its velocity: by default the mix's
|
|
87
|
-
* latest frame, or for a subject no frame of its voice has met yet, or still inside its stagger,
|
|
88
|
-
* its first read, after any change with a time due by then. A subject faded out of the voice
|
|
89
|
-
* comes back at the latest frame too, however long it is before it is next read.
|
|
90
|
-
*/
|
|
91
|
-
to(subject: I, target: V, at?: number): void;
|
|
92
|
-
};
|
|
17
|
+
export declare function spring<I, O, V extends Value = number>(writes: keyof O, opts: SpringOptions<I, V>): Spring<I, O, V>;
|
|
93
18
|
/**
|
|
94
|
-
*
|
|
95
|
-
* `ms`, and comes to rest `velocity · ms / 1000` past
|
|
96
|
-
* again from wherever it is. Closed form, so frame
|
|
19
|
+
* A patch that coasts each subject to a stop under friction, as after a fling. A subject keeps its
|
|
20
|
+
* velocity, which falls by a factor of e every `ms`, and comes to rest `velocity · ms / 1000` past
|
|
21
|
+
* where it was released. `push` sets it moving again from wherever it is. Closed form, so frame
|
|
22
|
+
* rate does not change where it stops.
|
|
97
23
|
*
|
|
98
24
|
* With `bounds`, a coast that would stop past an edge springs back to it from where it crosses, at
|
|
99
25
|
* the speed it crosses at, on a critically damped spring of `stiffness`; one let go past an edge
|
|
@@ -102,44 +28,14 @@ export declare function spring<I, O, V extends Value = number>(writes: keyof O,
|
|
|
102
28
|
*
|
|
103
29
|
* @category patch
|
|
104
30
|
*/
|
|
105
|
-
export declare function glide<I, O, V extends Value = number>(writes: keyof O, opts:
|
|
106
|
-
/** Where each subject starts. */
|
|
107
|
-
from: PerSubject<I, V>;
|
|
108
|
-
/** The friction's time constant, ms. Default 325, a touch scroll's. */
|
|
109
|
-
ms?: number;
|
|
110
|
-
/** The least and greatest value a coast comes to rest at, per axis. Default none. */
|
|
111
|
-
bounds?: PerSubject<I, readonly [min: V, max: V]>;
|
|
112
|
-
/** The spring back's, per second squared, with `bounds`. Default 170, as a spring's. */
|
|
113
|
-
stiffness?: number;
|
|
114
|
-
}): Moving<I, O, V> & {
|
|
115
|
-
/** `subject`'s bounds, undefined for a glide without them. */
|
|
116
|
-
bounds(subject: I): readonly [min: V, max: V] | undefined;
|
|
117
|
-
};
|
|
31
|
+
export declare function glide<I, O, V extends Value = number>(writes: keyof O, opts: GlideOptions<I, V>): Glide<I, O, V>;
|
|
118
32
|
/**
|
|
119
|
-
* From one value to another over `ms` along an easing
|
|
120
|
-
* change where a subject is. `to(subject, target)` retargets one subject mid-flight: the new
|
|
121
|
-
* starts from where it is and takes the full `ms` again, so its velocity jumps where a
|
|
122
|
-
* would not. Time is the voice's, so `rate` and `seek` apply, and a voice's `loop` does
|
|
123
|
-
* it. Cue each tween on one voice. Every subject moves on the same number of axes.
|
|
33
|
+
* From one value to another over `ms` along an easing. Solved in closed form, so frame rate does
|
|
34
|
+
* not change where a subject is. `to(subject, target)` retargets one subject mid-flight: the new
|
|
35
|
+
* stretch starts from where it is and takes the full `ms` again, so its velocity jumps where a
|
|
36
|
+
* spring's would not. Time is the voice's, so `rate` and `seek` apply, and a voice's `loop` does
|
|
37
|
+
* not repeat it. Cue each tween on one voice. Every subject moves on the same number of axes.
|
|
124
38
|
*
|
|
125
39
|
* @category patch
|
|
126
40
|
*/
|
|
127
|
-
export declare function tween<I, O, V extends Value = number>(writes: keyof O, opts:
|
|
128
|
-
/** Where each subject starts. */
|
|
129
|
-
from: PerSubject<I, V>;
|
|
130
|
-
/** Where each subject ends. */
|
|
131
|
-
to: PerSubject<I, V>;
|
|
132
|
-
/** How long a stretch takes, ms: asked per subject each time one of its stretches starts. */
|
|
133
|
-
ms: PerSubject<I, number>;
|
|
134
|
-
/** The curve from `from` to `to`. Default `'ease'`, as CSS's. */
|
|
135
|
-
ease?: Easing;
|
|
136
|
-
}): Omit<Moving<I, O, V>, 'push'> & {
|
|
137
|
-
/**
|
|
138
|
-
* Heads `subject` for `target` from voice time `at`, over a full `ms` from where it is: by default
|
|
139
|
-
* the mix's latest frame, or for a subject no frame of its voice has met yet, or still inside its
|
|
140
|
-
* stagger, its first read, after any change with a time due by then. A subject faded out of the
|
|
141
|
-
* voice comes back at the latest frame too, however long it is before it is next read.
|
|
142
|
-
*/
|
|
143
|
-
to(subject: I, target: V, at?: number): void;
|
|
144
|
-
};
|
|
145
|
-
export {};
|
|
41
|
+
export declare function tween<I, O, V extends Value = number>(writes: keyof O, opts: TweenOptions<I, V>): Tween<I, O, V>;
|
package/dist/motion.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { BOUND, COAST, CRITICAL, EASED, OVER, UNDER } from './closed.js';
|
|
2
2
|
import { curve } from './easing.js';
|
|
3
3
|
import { Motions } from './motions.js';
|
|
4
|
+
import { reading } from './reading.js';
|
|
4
5
|
import { release } from './shared.js';
|
|
6
|
+
import { sampleThen } from './then.js';
|
|
5
7
|
const axes = (v) => (typeof v === 'number' ? [v] : [...v]);
|
|
6
8
|
/** Zero on every axis `x` has: a motion's velocity where its options give none. */
|
|
7
9
|
const still = (x) => new Array(x.length).fill(0);
|
|
@@ -40,6 +42,11 @@ class MotionPatch {
|
|
|
40
42
|
}
|
|
41
43
|
at(_phase, subject, setting) {
|
|
42
44
|
const state = this.motions;
|
|
45
|
+
const back = reading.back;
|
|
46
|
+
if (back !== null) {
|
|
47
|
+
const flags = sampleThen(state, subject, setting.elapsed, back);
|
|
48
|
+
return { [this.writes[0]]: state.valueOf(flags, state.xs) };
|
|
49
|
+
}
|
|
43
50
|
const s = state.slot(subject);
|
|
44
51
|
state.sample(s, setting.elapsed, state.xs, state.vs);
|
|
45
52
|
return { [this.writes[0]]: state.value(s, state.xs) };
|
|
@@ -252,9 +259,10 @@ export function spring(writes, opts) {
|
|
|
252
259
|
return new SpringPatch(writes, new Motions(new SpringShape(law, motion, opts)));
|
|
253
260
|
}
|
|
254
261
|
/**
|
|
255
|
-
*
|
|
256
|
-
* `ms`, and comes to rest `velocity · ms / 1000` past
|
|
257
|
-
* again from wherever it is. Closed form, so frame
|
|
262
|
+
* A patch that coasts each subject to a stop under friction, as after a fling. A subject keeps its
|
|
263
|
+
* velocity, which falls by a factor of e every `ms`, and comes to rest `velocity · ms / 1000` past
|
|
264
|
+
* where it was released. `push` sets it moving again from wherever it is. Closed form, so frame
|
|
265
|
+
* rate does not change where it stops.
|
|
258
266
|
*
|
|
259
267
|
* With `bounds`, a coast that would stop past an edge springs back to it from where it crosses, at
|
|
260
268
|
* the speed it crosses at, on a critically damped spring of `stiffness`; one let go past an edge
|
|
@@ -277,11 +285,11 @@ export function glide(writes, opts) {
|
|
|
277
285
|
return new GlidePatch(writes, new Motions(shape), opts.bounds);
|
|
278
286
|
}
|
|
279
287
|
/**
|
|
280
|
-
* From one value to another over `ms` along an easing
|
|
281
|
-
* change where a subject is. `to(subject, target)` retargets one subject mid-flight: the new
|
|
282
|
-
* starts from where it is and takes the full `ms` again, so its velocity jumps where a
|
|
283
|
-
* would not. Time is the voice's, so `rate` and `seek` apply, and a voice's `loop` does
|
|
284
|
-
* it. Cue each tween on one voice. Every subject moves on the same number of axes.
|
|
288
|
+
* From one value to another over `ms` along an easing. Solved in closed form, so frame rate does
|
|
289
|
+
* not change where a subject is. `to(subject, target)` retargets one subject mid-flight: the new
|
|
290
|
+
* stretch starts from where it is and takes the full `ms` again, so its velocity jumps where a
|
|
291
|
+
* spring's would not. Time is the voice's, so `rate` and `seek` apply, and a voice's `loop` does
|
|
292
|
+
* not repeat it. Cue each tween on one voice. Every subject moves on the same number of axes.
|
|
285
293
|
*
|
|
286
294
|
* @category patch
|
|
287
295
|
*/
|