@msb235/blits 0.7.1 → 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.
- package/CHANGELOG.md +180 -0
- package/README.md +22 -4
- package/dist/book.js +4 -4
- package/dist/chain.d.ts +1 -1
- package/dist/chain.js +57 -54
- package/dist/channels.d.ts +26 -5
- package/dist/channels.js +12 -8
- package/dist/clock.d.ts +8 -1
- package/dist/clock.js +14 -3
- package/dist/clone.d.ts +3 -0
- package/dist/clone.js +16 -1
- package/dist/closed.d.ts +1 -1
- package/dist/closed.js +3 -2
- package/dist/color.d.ts +0 -11
- package/dist/color.js +4 -24
- package/dist/columns.js +0 -1
- package/dist/copyout.d.ts +6 -0
- package/dist/copyout.js +38 -0
- package/dist/crowd.d.ts +7 -5
- package/dist/crowd.js +32 -18
- package/dist/cue.d.ts +3 -1
- package/dist/cue.js +31 -20
- package/dist/departed.d.ts +34 -0
- package/dist/departed.js +73 -0
- package/dist/easing.d.ts +5 -0
- package/dist/easing.js +31 -2
- package/dist/everyone.d.ts +56 -0
- package/dist/everyone.js +221 -0
- package/dist/fade.d.ts +8 -1
- package/dist/fade.js +34 -6
- package/dist/fill.d.ts +22 -13
- package/dist/fill.js +104 -41
- package/dist/fit.js +2 -1
- package/dist/fold.d.ts +37 -0
- package/dist/fold.js +213 -28
- package/dist/gather.d.ts +15 -9
- package/dist/gather.js +60 -25
- package/dist/gone.js +10 -0
- package/dist/handle.d.ts +16 -5
- package/dist/handle.js +56 -6
- package/dist/held.d.ts +8 -5
- package/dist/held.js +56 -58
- package/dist/history.d.ts +17 -13
- package/dist/history.js +47 -28
- package/dist/hosts.js +55 -8
- package/dist/index.d.ts +9 -4
- package/dist/index.js +5 -2
- package/dist/keyfill.d.ts +7 -0
- package/dist/keyfill.js +124 -0
- package/dist/keyrows.d.ts +1 -0
- package/dist/keyrows.js +1 -1
- package/dist/lane.d.ts +32 -2
- package/dist/lane.js +5 -0
- package/dist/lanes.d.ts +32 -8
- package/dist/lanes.js +69 -37
- package/dist/leavings.d.ts +26 -0
- package/dist/leavings.js +70 -0
- package/dist/meet.js +14 -8
- package/dist/mixer.d.ts +39 -7
- package/dist/mixer.js +50 -10
- package/dist/motion.d.ts +2 -0
- package/dist/motion.js +4 -1
- package/dist/motions.d.ts +22 -15
- package/dist/motions.js +40 -34
- package/dist/move.js +23 -16
- package/dist/moved.d.ts +11 -0
- package/dist/moved.js +29 -0
- package/dist/origin.d.ts +19 -0
- package/dist/origin.js +68 -0
- package/dist/owed.d.ts +4 -4
- package/dist/owed.js +8 -8
- package/dist/owner.d.ts +1 -1
- package/dist/owner.js +2 -2
- package/dist/pace.d.ts +13 -5
- package/dist/pace.js +21 -8
- package/dist/pack.d.ts +3 -1
- package/dist/pack.js +15 -24
- package/dist/paging.d.ts +8 -2
- package/dist/paging.js +44 -4
- package/dist/patch.d.ts +14 -9
- package/dist/patch.js +83 -21
- package/dist/place.js +18 -3
- package/dist/project.d.ts +12 -1
- package/dist/project.js +101 -83
- package/dist/pull.d.ts +2 -0
- package/dist/pull.js +8 -0
- package/dist/qualify.js +10 -2
- package/dist/reading.d.ts +5 -0
- package/dist/reading.js +5 -0
- package/dist/record.d.ts +9 -0
- package/dist/record.js +42 -0
- package/dist/relink.d.ts +11 -5
- package/dist/relink.js +7 -5
- package/dist/restored.d.ts +41 -0
- package/dist/restored.js +91 -0
- package/dist/revive.d.ts +10 -3
- package/dist/revive.js +31 -23
- package/dist/roster.d.ts +11 -0
- package/dist/roster.js +46 -0
- package/dist/rotation.d.ts +29 -0
- package/dist/rotation.js +91 -0
- package/dist/rows.d.ts +5 -5
- package/dist/rows.js +5 -5
- package/dist/sample.d.ts +3 -2
- package/dist/sample.js +32 -15
- package/dist/seek.js +97 -114
- package/dist/shared.d.ts +6 -0
- package/dist/shared.js +15 -0
- package/dist/signals.d.ts +24 -3
- package/dist/signals.js +50 -11
- package/dist/spans.js +7 -0
- package/dist/stack.d.ts +11 -0
- package/dist/stack.js +47 -0
- package/dist/standing.d.ts +10 -0
- package/dist/standing.js +79 -0
- package/dist/store.d.ts +3 -3
- package/dist/store.js +3 -3
- package/dist/strays.js +3 -0
- package/dist/tape.d.ts +8 -5
- package/dist/tape.js +21 -13
- package/dist/testing.d.ts +35 -0
- package/dist/testing.js +116 -0
- package/dist/touch.d.ts +6 -0
- package/dist/touch.js +28 -0
- package/dist/transport.d.ts +49 -6
- package/dist/transport.js +89 -19
- package/dist/turns.d.ts +18 -0
- package/dist/turns.js +72 -0
- package/dist/tweened.js +1 -1
- package/dist/types/channel.d.ts +46 -0
- package/dist/types/channel.js +1 -0
- package/dist/types/history.d.ts +139 -0
- package/dist/types/history.js +1 -0
- package/dist/types/mix.d.ts +336 -0
- package/dist/types/mix.js +1 -0
- package/dist/types/patch.d.ts +187 -0
- package/dist/types/patch.js +1 -0
- package/dist/types/place.d.ts +157 -0
- package/dist/types/place.js +1 -0
- package/dist/types/transport.d.ts +71 -0
- package/dist/types/transport.js +1 -0
- package/dist/types/voice.d.ts +323 -0
- package/dist/types/voice.js +1 -0
- package/dist/types.d.ts +7 -1162
- package/dist/unpage.d.ts +2 -2
- package/dist/unpage.js +53 -25
- package/dist/voice.d.ts +90 -22
- package/dist/voice.js +105 -43
- package/dist/wave.d.ts +42 -0
- package/dist/wave.js +62 -0
- package/dist/weigh.js +1 -1
- package/docs/schema.html +42 -36
- package/package.json +8 -3
package/dist/meet.js
CHANGED
|
@@ -8,21 +8,27 @@ export function owable(lanes, slot) {
|
|
|
8
8
|
if (lanes.metCrowd || lanes.owes(slot))
|
|
9
9
|
return false;
|
|
10
10
|
// Subjects meeting the same lanes in one fill get the same answer, and a list is kept only once true.
|
|
11
|
-
if (lanes.owed.last(lanes.met))
|
|
12
|
-
return true;
|
|
13
11
|
const met = lanes.met;
|
|
12
|
+
const n = lanes.metN;
|
|
13
|
+
if (lanes.owed.last(met, n))
|
|
14
|
+
return true;
|
|
14
15
|
let other = Number.NEGATIVE_INFINITY;
|
|
15
16
|
for (const lane of lanes.lanes) {
|
|
16
17
|
const id = lane.voice.id;
|
|
17
|
-
if (id
|
|
18
|
+
if (id <= other)
|
|
19
|
+
continue;
|
|
20
|
+
const at = met.indexOf(id);
|
|
21
|
+
if (at < 0 || at >= n)
|
|
18
22
|
other = id;
|
|
19
23
|
}
|
|
20
24
|
for (const c of lanes.crowds)
|
|
21
25
|
if (c.size > 0)
|
|
22
26
|
other = Math.max(other, c.hot[(c.size - 1) * c.stride + 7 /* Hot.ID */]);
|
|
23
|
-
for (
|
|
27
|
+
for (let i = 0; i < n; i++) {
|
|
28
|
+
const id = met[i];
|
|
24
29
|
if (id <= other || lanes.byId.get(id).group !== null)
|
|
25
30
|
return false;
|
|
31
|
+
}
|
|
26
32
|
return true;
|
|
27
33
|
}
|
|
28
34
|
/**
|
|
@@ -35,7 +41,7 @@ export function meet(lanes, slot, subject, head, lane) {
|
|
|
35
41
|
const from = seen < 0 ? -1 - seen : seen;
|
|
36
42
|
lanes.per[slot * 6 /* Per.SLOT */ + 1 /* Per.SEEN */] = lanes.epochs;
|
|
37
43
|
let met = false;
|
|
38
|
-
lanes.
|
|
44
|
+
lanes.metN = 0;
|
|
39
45
|
lanes.metCrowd = false;
|
|
40
46
|
const dense = lanes.dense;
|
|
41
47
|
for (let i = dense.length - 1; i >= 0; i--) {
|
|
@@ -50,7 +56,7 @@ export function meet(lanes, slot, subject, head, lane) {
|
|
|
50
56
|
lane.add(slot, held);
|
|
51
57
|
if (lane.idle)
|
|
52
58
|
reach(lanes, slot, 1);
|
|
53
|
-
lanes.met.
|
|
59
|
+
lanes.met[lanes.metN++] = lane.voice.id;
|
|
54
60
|
met = true;
|
|
55
61
|
}
|
|
56
62
|
// `open` marks every subject a voice naming it starts on, so an unmarked one has none to meet.
|
|
@@ -73,7 +79,7 @@ export function meet(lanes, slot, subject, head, lane) {
|
|
|
73
79
|
lane.add(slot, held);
|
|
74
80
|
if (lane.idle)
|
|
75
81
|
reach(lanes, slot, 1);
|
|
76
|
-
lanes.met.
|
|
82
|
+
lanes.met[lanes.metN++] = voice.id;
|
|
77
83
|
met = true;
|
|
78
84
|
}
|
|
79
85
|
if (!met)
|
|
@@ -83,7 +89,7 @@ export function meet(lanes, slot, subject, head, lane) {
|
|
|
83
89
|
// otherwise it reads the general path all frame.
|
|
84
90
|
const o = slot * 6 /* Per.SLOT */;
|
|
85
91
|
if (lane && lanes.per[o + 2 /* Per.IDLE */] === 0 && owable(lanes, slot)) {
|
|
86
|
-
lanes.owed.owe(slot, lanes.met);
|
|
92
|
+
lanes.owed.owe(slot, lanes.met, lanes.metN);
|
|
87
93
|
return true;
|
|
88
94
|
}
|
|
89
95
|
lanes.per[o + 0 /* Per.FILLED */] = lanes.fills;
|
package/dist/mixer.d.ts
CHANGED
|
@@ -2,9 +2,10 @@ import { blended, laneRead, shareKept } from './blend.js';
|
|
|
2
2
|
import type { Book } from './book.js';
|
|
3
3
|
import { aims, chain, linkable, relink } from './chain.js';
|
|
4
4
|
import { type LerpInto } from './channels.js';
|
|
5
|
+
import { DepartedIndex } from './departed.js';
|
|
5
6
|
import type { Due } from './due.js';
|
|
6
7
|
import { parting } from './fade.js';
|
|
7
|
-
import { apply, baseFor, clamp, contribution, fold, folded, foldLoci, foldWith, isRest, type Key, keyed, linked, owedBy, passes, read, slopeFor, tick } from './fold.js';
|
|
8
|
+
import { apply, baseFor, clamp, contribution, fold, foldDetour, folded, foldLoci, foldSharers, foldWith, isRest, type Key, keyed, linked, owedBy, passes, read, shared, slopeFor, tick } from './fold.js';
|
|
8
9
|
import { GoneIndex } from './gone.js';
|
|
9
10
|
import type { HandleHost } from './handle.js';
|
|
10
11
|
import { held, shownOf, sinceOf, unreachedOf } from './held.js';
|
|
@@ -23,6 +24,13 @@ import { type Announced, Transport } from './transport.js';
|
|
|
23
24
|
import type { Booker, BookOptions, Channel, Columns, Engine, Handle, Kit, Marked, Mix, MixOptions, OwnerSpec, Patch, Projection, Sent, Signal, SpanHandle, SpanSpec, Tape, VoiceSpec } from './types.js';
|
|
24
25
|
import { type Subject, type Voice } from './voice.js';
|
|
25
26
|
import { base, capped, fadeOf, horizonFor, ownedBy, ownerBase, prime, weigh, weighOwned } from './weigh.js';
|
|
27
|
+
/**
|
|
28
|
+
* What a mix takes where its options say nothing. Not exported from the package: the suite turns
|
|
29
|
+
* `lanes` off to run every test on the general path, which is what makes each one an equivalence check.
|
|
30
|
+
*/
|
|
31
|
+
export declare const defaults: {
|
|
32
|
+
lanes: boolean;
|
|
33
|
+
};
|
|
26
34
|
export declare class Mixer<I, O> implements Mix<I, O> {
|
|
27
35
|
readonly kit: Kit<O>;
|
|
28
36
|
readonly opts: MixOptions;
|
|
@@ -37,12 +45,18 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
37
45
|
backward: boolean;
|
|
38
46
|
/** True during a sync, so a control change it makes is recorded as showing in that frame. */
|
|
39
47
|
moving: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Whether a probe or pull has read the mix since its clock last moved. A control change made
|
|
50
|
+
* before that shows in this frame live, so it is recorded as showing in it.
|
|
51
|
+
*/
|
|
52
|
+
looked: boolean;
|
|
40
53
|
/**
|
|
41
54
|
* Under `history` with `inputs`, the host fields patches read, copied each frame they changed. In
|
|
42
55
|
* a projection reading back, the copy in force then.
|
|
43
56
|
*/
|
|
44
57
|
hostLog: {
|
|
45
58
|
at: number;
|
|
59
|
+
seq: number;
|
|
46
60
|
fields: Record<string, unknown>;
|
|
47
61
|
}[];
|
|
48
62
|
hostThen: {
|
|
@@ -62,20 +76,23 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
62
76
|
/** Taken off its transport, so it takes no more calls until a seek puts it back. */
|
|
63
77
|
dropped: boolean;
|
|
64
78
|
readonly name: string | undefined;
|
|
65
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* This mix's frame among every mix's: moved by a sync or seek, and by a control change, drop,
|
|
81
|
+
* or touch within one.
|
|
82
|
+
*/
|
|
66
83
|
frame: number;
|
|
67
84
|
/** Pending voices whose start the host gave, by its host time, kept where the rate puts it. */
|
|
68
85
|
pins: Map<Voice<I, O>, number> | null;
|
|
69
86
|
wantsPose: boolean;
|
|
70
87
|
/** The pose `pull` folds a subject into where it cannot read straight from the lanes. */
|
|
71
88
|
scratch: O | undefined;
|
|
72
|
-
/** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
|
|
73
89
|
/** Live voices by the earliest mix time `moveTo` would change each, a binary heap. */
|
|
74
90
|
due: Due<I, O>[];
|
|
75
91
|
/** Voices retired since `moveTo` last pruned them, in the order they retired. */
|
|
76
92
|
retired: Voice<I, O>[];
|
|
77
93
|
/** Visit every voice each sync, as before the due queue; for tests that compare the two. */
|
|
78
94
|
walkAll: boolean;
|
|
95
|
+
/** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
|
|
79
96
|
pulled: I[];
|
|
80
97
|
pulledHeads: (Subject<unknown> | undefined)[];
|
|
81
98
|
/** Each remembered head's lane slot, and the `version` and `relinks` they were all current at. */
|
|
@@ -97,16 +114,18 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
97
114
|
onWake(fn: () => void): () => void;
|
|
98
115
|
/**
|
|
99
116
|
* Per subject, the first record of the chain through every live voice that reaches it, or a stub
|
|
100
|
-
* where none does. Relinked when `version` moves,
|
|
101
|
-
*
|
|
117
|
+
* where none does. Relinked when `version` moves, or when a voice naming the subject marks its
|
|
118
|
+
* head stale: see `changed` in `chain.ts`.
|
|
102
119
|
*/
|
|
103
120
|
chains: Store<I, Subject<unknown>>;
|
|
104
121
|
version: number;
|
|
105
|
-
readonly steps: Steps<Voice<I, O
|
|
122
|
+
readonly steps: Steps<Voice<I, O>, I>;
|
|
106
123
|
/** Per subject, the voices whose `subjects` name it, in voice order. */
|
|
107
124
|
named: Store<I, Voice<I, O>[]>;
|
|
108
125
|
/** Voices a subject has been faded out of, which `drop` looks in besides those that reach it. */
|
|
109
126
|
readonly parters: Set<Voice<I, O>>;
|
|
127
|
+
/** What an anchor can still find of voices that left without history, or past its reach. */
|
|
128
|
+
readonly departed: DepartedIndex;
|
|
110
129
|
/**
|
|
111
130
|
* Motion patches that may hold state for a subject no voice still reaching it plays, which `drop`
|
|
112
131
|
* frees besides those voices' own: per subject, a patch a voice naming it left while another
|
|
@@ -120,6 +139,15 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
120
139
|
naming: number;
|
|
121
140
|
/** The voices in the list that name no subjects, in voice order. */
|
|
122
141
|
general: Voice<I, O>[];
|
|
142
|
+
/** Those of `general` that keep one record for every subject, in voice order: see `everyone.ts`. */
|
|
143
|
+
sharers: Voice<I, O>[];
|
|
144
|
+
/**
|
|
145
|
+
* Whether a voice stopped sharing this frame: a probe or pull under way then holds chains linked
|
|
146
|
+
* before it joined them, and takes each again.
|
|
147
|
+
*/
|
|
148
|
+
unshared: boolean;
|
|
149
|
+
/** 0 where a fold is a walk of the chain: see `detour` in `everyone.ts`. */
|
|
150
|
+
detours: number;
|
|
123
151
|
/** How many voices in the list carry a locus; with none, a fold allocates nothing. */
|
|
124
152
|
loci: number;
|
|
125
153
|
/** What every motion patch it plays asks for its voice's time, holding this mix weakly. */
|
|
@@ -216,6 +244,7 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
216
244
|
over?: number;
|
|
217
245
|
}): void;
|
|
218
246
|
drop(subject: I): void;
|
|
247
|
+
touch(subject?: I): void;
|
|
219
248
|
drain<E = unknown>(tag?: string): Sent<I, E>[];
|
|
220
249
|
/** Voices whose stop 0 is mid-computation, so a fold for one cannot re-enter itself. */
|
|
221
250
|
readonly folding: Set<number>;
|
|
@@ -225,7 +254,7 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
225
254
|
* is first asked, when probes start writing it.
|
|
226
255
|
*/
|
|
227
256
|
restStamps: Store<I, number> | null;
|
|
228
|
-
/** What a probe's record of rest is good for: moved by a new frame, version or
|
|
257
|
+
/** What a probe's record of rest is good for: moved by a new frame, version, relink, or stir. */
|
|
229
258
|
private restsEpoch;
|
|
230
259
|
private restsFrame;
|
|
231
260
|
private restsVersion;
|
|
@@ -243,6 +272,9 @@ declare const methods: {
|
|
|
243
272
|
foldWith: typeof foldWith;
|
|
244
273
|
owedBy: typeof owedBy;
|
|
245
274
|
foldLoci: typeof foldLoci;
|
|
275
|
+
foldDetour: typeof foldDetour;
|
|
276
|
+
foldSharers: typeof foldSharers;
|
|
277
|
+
shared: typeof shared;
|
|
246
278
|
read: typeof read;
|
|
247
279
|
contribution: typeof contribution;
|
|
248
280
|
keyed: typeof keyed;
|
package/dist/mixer.js
CHANGED
|
@@ -2,8 +2,9 @@ import { blended, blendOf, laneRead, shareKept } from './blend.js';
|
|
|
2
2
|
import { aims, chain, linkable, relink } from './chain.js';
|
|
3
3
|
import { lerpInto } from './channels.js';
|
|
4
4
|
import { cue } from './cue.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { DepartedIndex } from './departed.js';
|
|
6
|
+
import { beginFade, leftWith, parting } from './fade.js';
|
|
7
|
+
import { apply, baseFor, clamp, contribution, fold, foldDetour, folded, foldLoci, foldSharers, foldWith, isRest, keyed, linked, near, owedBy, passes, read, shared, slopeFor, tick, } from './fold.js';
|
|
7
8
|
import { GoneIndex, goneIndex } from './gone.js';
|
|
8
9
|
import { held, shownOf, sinceOf, unreachedOf } from './held.js';
|
|
9
10
|
import { leave, releasing } from './history.js';
|
|
@@ -23,9 +24,15 @@ import { seek } from './seek.js';
|
|
|
23
24
|
import { Fitting, refit } from './spans.js';
|
|
24
25
|
import { Store } from './store.js';
|
|
25
26
|
import { record } from './tape.js';
|
|
27
|
+
import { touch } from './touch.js';
|
|
26
28
|
import { announce, Transport } from './transport.js';
|
|
27
29
|
import { none } from './voice.js';
|
|
28
30
|
import { base, capped, fadeOf, horizonFor, ownedBy, ownerBase, prime, weigh, weighOwned, } from './weigh.js';
|
|
31
|
+
/**
|
|
32
|
+
* What a mix takes where its options say nothing. Not exported from the package: the suite turns
|
|
33
|
+
* `lanes` off to run every test on the general path, which is what makes each one an equivalence check.
|
|
34
|
+
*/
|
|
35
|
+
export const defaults = { lanes: true };
|
|
29
36
|
// biome-ignore lint/suspicious/noUnsafeDeclarationMerging: every member of `Methods` is installed below
|
|
30
37
|
export class Mixer {
|
|
31
38
|
kit;
|
|
@@ -41,6 +48,11 @@ export class Mixer {
|
|
|
41
48
|
backward = false;
|
|
42
49
|
/** True during a sync, so a control change it makes is recorded as showing in that frame. */
|
|
43
50
|
moving = false;
|
|
51
|
+
/**
|
|
52
|
+
* Whether a probe or pull has read the mix since its clock last moved. A control change made
|
|
53
|
+
* before that shows in this frame live, so it is recorded as showing in it.
|
|
54
|
+
*/
|
|
55
|
+
looked = false;
|
|
44
56
|
/**
|
|
45
57
|
* Under `history` with `inputs`, the host fields patches read, copied each frame they changed. In
|
|
46
58
|
* a projection reading back, the copy in force then.
|
|
@@ -56,20 +68,23 @@ export class Mixer {
|
|
|
56
68
|
/** Taken off its transport, so it takes no more calls until a seek puts it back. */
|
|
57
69
|
dropped = false;
|
|
58
70
|
name;
|
|
59
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* This mix's frame among every mix's: moved by a sync or seek, and by a control change, drop,
|
|
73
|
+
* or touch within one.
|
|
74
|
+
*/
|
|
60
75
|
frame = nextFrame();
|
|
61
76
|
/** Pending voices whose start the host gave, by its host time, kept where the rate puts it. */
|
|
62
77
|
pins = null;
|
|
63
78
|
wantsPose = false;
|
|
64
79
|
/** The pose `pull` folds a subject into where it cannot read straight from the lanes. */
|
|
65
80
|
scratch;
|
|
66
|
-
/** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
|
|
67
81
|
/** Live voices by the earliest mix time `moveTo` would change each, a binary heap. */
|
|
68
82
|
due = [];
|
|
69
83
|
/** Voices retired since `moveTo` last pruned them, in the order they retired. */
|
|
70
84
|
retired = [];
|
|
71
85
|
/** Visit every voice each sync, as before the due queue; for tests that compare the two. */
|
|
72
86
|
walkAll = false;
|
|
87
|
+
/** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
|
|
73
88
|
pulled = [];
|
|
74
89
|
pulledHeads = [];
|
|
75
90
|
/** Each remembered head's lane slot, and the `version` and `relinks` they were all current at. */
|
|
@@ -89,6 +104,9 @@ export class Mixer {
|
|
|
89
104
|
/** Records a change to the mix's voices or controls. */
|
|
90
105
|
stir() {
|
|
91
106
|
this.stirs++;
|
|
107
|
+
// A change a sync makes follows from the clock; one a host makes does not.
|
|
108
|
+
if (!this.moving)
|
|
109
|
+
this.transport.settle();
|
|
92
110
|
if (this.stirred)
|
|
93
111
|
return;
|
|
94
112
|
this.stirred = true;
|
|
@@ -113,8 +131,8 @@ export class Mixer {
|
|
|
113
131
|
}
|
|
114
132
|
/**
|
|
115
133
|
* Per subject, the first record of the chain through every live voice that reaches it, or a stub
|
|
116
|
-
* where none does. Relinked when `version` moves,
|
|
117
|
-
*
|
|
134
|
+
* where none does. Relinked when `version` moves, or when a voice naming the subject marks its
|
|
135
|
+
* head stale: see `changed` in `chain.ts`.
|
|
118
136
|
*/
|
|
119
137
|
chains = new Store();
|
|
120
138
|
version = 0;
|
|
@@ -123,6 +141,8 @@ export class Mixer {
|
|
|
123
141
|
named = new Store();
|
|
124
142
|
/** Voices a subject has been faded out of, which `drop` looks in besides those that reach it. */
|
|
125
143
|
parters = new Set();
|
|
144
|
+
/** What an anchor can still find of voices that left without history, or past its reach. */
|
|
145
|
+
departed = new DepartedIndex();
|
|
126
146
|
/**
|
|
127
147
|
* Motion patches that may hold state for a subject no voice still reaching it plays, which `drop`
|
|
128
148
|
* frees besides those voices' own: per subject, a patch a voice naming it left while another
|
|
@@ -136,6 +156,15 @@ export class Mixer {
|
|
|
136
156
|
naming = 0;
|
|
137
157
|
/** The voices in the list that name no subjects, in voice order. */
|
|
138
158
|
general = [];
|
|
159
|
+
/** Those of `general` that keep one record for every subject, in voice order: see `everyone.ts`. */
|
|
160
|
+
sharers = [];
|
|
161
|
+
/**
|
|
162
|
+
* Whether a voice stopped sharing this frame: a probe or pull under way then holds chains linked
|
|
163
|
+
* before it joined them, and takes each again.
|
|
164
|
+
*/
|
|
165
|
+
unshared = false;
|
|
166
|
+
/** 0 where a fold is a walk of the chain: see `detour` in `everyone.ts`. */
|
|
167
|
+
detours = 0;
|
|
139
168
|
/** How many voices in the list carry a locus; with none, a fold allocates nothing. */
|
|
140
169
|
loci = 0;
|
|
141
170
|
/** What every motion patch it plays asks for its voice's time, holding this mix weakly. */
|
|
@@ -196,7 +225,7 @@ export class Mixer {
|
|
|
196
225
|
this.names.forEach((k, i) => {
|
|
197
226
|
this.slotOf.set(k, i);
|
|
198
227
|
});
|
|
199
|
-
this.lanes = opts.lanes
|
|
228
|
+
this.lanes = (opts.lanes ?? defaults.lanes) ? new Lanes(laneHost(this)) : null;
|
|
200
229
|
this.name = opts.name;
|
|
201
230
|
const shared = opts.transport;
|
|
202
231
|
if (shared !== undefined) {
|
|
@@ -315,6 +344,7 @@ export class Mixer {
|
|
|
315
344
|
return book(this, opts);
|
|
316
345
|
}
|
|
317
346
|
probe(subject, out) {
|
|
347
|
+
this.looked = true;
|
|
318
348
|
const pose = this.fold(subject, out);
|
|
319
349
|
this.keep(subject, pose, out);
|
|
320
350
|
// Where the lanes answer `atRest` from their own values, there is nothing to keep.
|
|
@@ -323,6 +353,7 @@ export class Mixer {
|
|
|
323
353
|
return pose;
|
|
324
354
|
}
|
|
325
355
|
pull(subjects, into) {
|
|
356
|
+
this.looked = true;
|
|
326
357
|
pull(this, subjects, into);
|
|
327
358
|
}
|
|
328
359
|
seek(time) {
|
|
@@ -431,8 +462,10 @@ export class Mixer {
|
|
|
431
462
|
return motion !== undefined && voice.elapsedAt(now) >= voice.latest && motion.landed();
|
|
432
463
|
}
|
|
433
464
|
mute(opts) {
|
|
434
|
-
for (const voice of this.cued)
|
|
465
|
+
for (const voice of this.cued) {
|
|
466
|
+
voice.written = true;
|
|
435
467
|
beginFade(this, voice, { over: opts?.over });
|
|
468
|
+
}
|
|
436
469
|
record(this, 'mute', () => this.mute(opts));
|
|
437
470
|
}
|
|
438
471
|
drop(subject) {
|
|
@@ -453,7 +486,7 @@ export class Mixer {
|
|
|
453
486
|
// of a voice that does not name it is in `parters`, and a patch's own state in `motions`.
|
|
454
487
|
const kept = releasing(this);
|
|
455
488
|
const forget = (voice) => {
|
|
456
|
-
leave(this, voice, subject, voice
|
|
489
|
+
leave(this, voice, subject, leftWith(this, voice, subject));
|
|
457
490
|
voice.subjects.delete(subject);
|
|
458
491
|
voice.motion?.release(subject, ...kept);
|
|
459
492
|
voice.parts?.delete(subject);
|
|
@@ -494,6 +527,10 @@ export class Mixer {
|
|
|
494
527
|
motion.release(subject, ...kept);
|
|
495
528
|
record(this, 'drop', () => this.drop(subject));
|
|
496
529
|
}
|
|
530
|
+
touch(subject) {
|
|
531
|
+
this.attached();
|
|
532
|
+
touch(this, subject);
|
|
533
|
+
}
|
|
497
534
|
drain(tag) {
|
|
498
535
|
const all = this.sent;
|
|
499
536
|
if (all.length === 0)
|
|
@@ -518,7 +555,7 @@ export class Mixer {
|
|
|
518
555
|
* is first asked, when probes start writing it.
|
|
519
556
|
*/
|
|
520
557
|
restStamps = null;
|
|
521
|
-
/** What a probe's record of rest is good for: moved by a new frame, version or
|
|
558
|
+
/** What a probe's record of rest is good for: moved by a new frame, version, relink, or stir. */
|
|
522
559
|
restsEpoch = 0;
|
|
523
560
|
restsFrame = Number.NaN;
|
|
524
561
|
restsVersion = Number.NaN;
|
|
@@ -552,6 +589,9 @@ const methods = {
|
|
|
552
589
|
foldWith,
|
|
553
590
|
owedBy,
|
|
554
591
|
foldLoci,
|
|
592
|
+
foldDetour,
|
|
593
|
+
foldSharers,
|
|
594
|
+
shared,
|
|
555
595
|
read,
|
|
556
596
|
contribution,
|
|
557
597
|
keyed,
|
package/dist/motion.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export type Moving<I, O, V extends Value> = Patch<I, O, void> & {
|
|
|
33
33
|
* Where `subject` is and how fast it moves at voice time `at`, default the mix's latest frame,
|
|
34
34
|
* counting every change due by then. With no time given, undefined until a frame of its voice
|
|
35
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.
|
|
36
38
|
*/
|
|
37
39
|
read(subject: I, at?: number): Motion<V> | undefined;
|
|
38
40
|
/**
|
package/dist/motion.js
CHANGED
|
@@ -26,7 +26,6 @@ class MotionPatch {
|
|
|
26
26
|
}
|
|
27
27
|
form = 'motion';
|
|
28
28
|
duration = 0;
|
|
29
|
-
period = 0;
|
|
30
29
|
get motion() {
|
|
31
30
|
return this.motions.spec();
|
|
32
31
|
}
|
|
@@ -191,6 +190,8 @@ export function spring(writes, opts) {
|
|
|
191
190
|
const k = opts.stiffness ?? 170;
|
|
192
191
|
const c = opts.damping ?? 26;
|
|
193
192
|
const m = opts.mass ?? 1;
|
|
193
|
+
if (!(k > 0) || !(m > 0) || !(c >= 0))
|
|
194
|
+
throw new RangeError('blits: a spring takes a positive stiffness and mass, and damping of 0 or more');
|
|
194
195
|
const settle = opts.settle ?? 1e-4;
|
|
195
196
|
const w0 = Math.sqrt(k / m);
|
|
196
197
|
const zeta = c / (2 * Math.sqrt(k * m));
|
|
@@ -215,6 +216,8 @@ export function spring(writes, opts) {
|
|
|
215
216
|
*/
|
|
216
217
|
export function glide(writes, opts) {
|
|
217
218
|
const ms = opts.ms ?? 325;
|
|
219
|
+
if (!(ms > 0))
|
|
220
|
+
throw new RangeError('blits: a glide takes a positive ms');
|
|
218
221
|
const tau = ms / 1000;
|
|
219
222
|
const settle = opts.settle ?? 1e-4;
|
|
220
223
|
const shape = new GlideShape([COAST, settle, tau, 0, 0], { kind: 'glide', ms, settle }, opts, tau);
|
package/dist/motions.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface Change {
|
|
|
23
23
|
v?: number[];
|
|
24
24
|
/** The mix clock when it was made, NaN where no mix was playing the patch. */
|
|
25
25
|
made?: number;
|
|
26
|
+
/** The frame it was made in, which a rewind partitions by; NaN where no mix was playing the patch. */
|
|
27
|
+
seq?: number;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* The mix playing a patch, asked with its voice's id: an owner and an id, where a pair of closures
|
|
@@ -35,6 +37,8 @@ export interface MotionOwner {
|
|
|
35
37
|
revive(id: number, subject: unknown): void;
|
|
36
38
|
/** The mix clock at its latest frame; NaN before the first. */
|
|
37
39
|
now(): number;
|
|
40
|
+
/** The number of the frame the mix is playing. */
|
|
41
|
+
seq(): number;
|
|
38
42
|
/**
|
|
39
43
|
* The host made a change, already given its time, which a seek makes again on the patch its
|
|
40
44
|
* voice plays then: a voice a history store paged out comes back with a patch of its own.
|
|
@@ -43,9 +47,10 @@ export interface MotionOwner {
|
|
|
43
47
|
/** History leaving memory for a subject, which a mix with a history store pages out. */
|
|
44
48
|
page(id: number, stream: 'released' | 'stretch', subject: unknown, out: Paging[]): void;
|
|
45
49
|
}
|
|
46
|
-
/** A record of a motion patch's history leaving memory, at a mix time. */
|
|
50
|
+
/** A record of a motion patch's history leaving memory, at a mix time and frame. */
|
|
47
51
|
export interface Paging {
|
|
48
52
|
at: number;
|
|
53
|
+
seq: number;
|
|
49
54
|
data: unknown;
|
|
50
55
|
}
|
|
51
56
|
/** A subject's run as plain data: its flags, its stretches oldest first, and changes still to apply. */
|
|
@@ -75,7 +80,7 @@ export interface Shape<I> {
|
|
|
75
80
|
scalarEvery(): boolean | undefined;
|
|
76
81
|
/** A tween's easing, which its law cannot hold; undefined, but present, on every other shape. */
|
|
77
82
|
ease: Curve | undefined;
|
|
78
|
-
/** A tween's
|
|
83
|
+
/** A tween's ms for a stretch the subject starts now; undefined, but present, on the rest. */
|
|
79
84
|
ms: ((subject: I) => number) | undefined;
|
|
80
85
|
/** The patch's kind and constants, as `Patch.motion` reports them. */
|
|
81
86
|
spec(): MotionSpec;
|
|
@@ -86,7 +91,7 @@ export interface Shape<I> {
|
|
|
86
91
|
* The one copy, read by `at` and by a mix's lane alike.
|
|
87
92
|
*
|
|
88
93
|
* After the law, each subject's run of `stride` numbers is its release time, its flags, a tween's
|
|
89
|
-
*
|
|
94
|
+
* ms for the stretch, then `x0`, `v0` and `to` per axis. A live sample reads this one buffer and nothing else the patch owns: at
|
|
90
95
|
* 10k springs of one subject each, a buffer per field, a map lookup per sample and the law in an
|
|
91
96
|
* object of its own took a call from 130 ns to 490.
|
|
92
97
|
*/
|
|
@@ -95,6 +100,8 @@ export declare class Motions<I> {
|
|
|
95
100
|
private readonly numbers;
|
|
96
101
|
/** Numbers by subject once a second is numbered: till then the one subject is found by `numbers`. */
|
|
97
102
|
private readonly slots;
|
|
103
|
+
/** How many numbers have been given up, so a number kept elsewhere can tell it is stale. */
|
|
104
|
+
freed: number;
|
|
98
105
|
/** Axes per subject; -1 until the first subject sets it. */
|
|
99
106
|
n: number;
|
|
100
107
|
private cap;
|
|
@@ -149,11 +156,11 @@ export declare class Motions<I> {
|
|
|
149
156
|
*/
|
|
150
157
|
private released;
|
|
151
158
|
/**
|
|
152
|
-
* Forgets a subject, so a later ask starts it afresh from `from`. Given the mix time `at
|
|
153
|
-
* history, its run is kept for a rewind before then, until `reach` passes it.
|
|
159
|
+
* Forgets a subject, so a later ask starts it afresh from `from`. Given the mix time `at` and frame
|
|
160
|
+
* `seq`, under history, its run is kept for a rewind before then, until `reach` passes it.
|
|
154
161
|
*/
|
|
155
|
-
release(subject: I, at?: number, reach?: number): void;
|
|
156
|
-
/** Puts back each subject released after
|
|
162
|
+
release(subject: I, at?: number, reach?: number, seq?: number): void;
|
|
163
|
+
/** Puts back each subject released after frame `seq`, as it stood when released. */
|
|
157
164
|
private unrelease;
|
|
158
165
|
/** Subject `s`'s run as it stands. */
|
|
159
166
|
private runAt;
|
|
@@ -162,9 +169,9 @@ export declare class Motions<I> {
|
|
|
162
169
|
/** Puts a subject's run back as `pack` or a release left it, replacing any it has now. */
|
|
163
170
|
unpack(subject: I, run: Run): void;
|
|
164
171
|
/** A released run a history store gave back, for a rewind to before its release. */
|
|
165
|
-
reclaim(subject: I, at: number, run: Run): void;
|
|
172
|
+
reclaim(subject: I, at: number, seq: number, run: Run): void;
|
|
166
173
|
/**
|
|
167
|
-
* Stretches a history store gave back, each by the
|
|
174
|
+
* Stretches a history store gave back, each by the frame it was in force by: each life of the
|
|
168
175
|
* subject, ended by a release, takes those from its own, ahead of the earliest it still keeps.
|
|
169
176
|
*/
|
|
170
177
|
restretch(subject: I, back: readonly Paging[]): void;
|
|
@@ -184,7 +191,7 @@ export declare class Motions<I> {
|
|
|
184
191
|
/** Whether `law` holds this patch's law, number for number, as `Object.is` compares them. */
|
|
185
192
|
hasLaw(law: Float64Array): boolean;
|
|
186
193
|
/**
|
|
187
|
-
* Copies subject `s`'s current stretch into `out` from `o` as its release time, its
|
|
194
|
+
* Copies subject `s`'s current stretch into `out` from `o` as its release time, its ms, then
|
|
188
195
|
* `x0`, `v0` and `to` per axis; false, copying nothing, while it has a change pending or an
|
|
189
196
|
* earlier stretch kept, which only `sample` handles.
|
|
190
197
|
*/
|
|
@@ -200,7 +207,7 @@ export declare class Motions<I> {
|
|
|
200
207
|
*/
|
|
201
208
|
sample(s: number, t: number, xo: Float64Array, vo: Float64Array): void;
|
|
202
209
|
/**
|
|
203
|
-
* Where subject `s`'s run starts in `runs` (its release time, then flags,
|
|
210
|
+
* Where subject `s`'s run starts in `runs` (its release time, then flags, ms, `x0`, `v0`
|
|
204
211
|
* and `to`) while it has nothing pending and no earlier stretch kept; -1 for any other.
|
|
205
212
|
*/
|
|
206
213
|
bareAt(s: number): number;
|
|
@@ -238,10 +245,10 @@ export declare class Motions<I> {
|
|
|
238
245
|
private flag;
|
|
239
246
|
forget(s: number): void;
|
|
240
247
|
/**
|
|
241
|
-
* Takes back every change made after
|
|
248
|
+
* Takes back every change made after frame `seq`: each subject plays from its earliest stretch
|
|
242
249
|
* kept, with the changes made by then queued to be applied again.
|
|
243
250
|
*/
|
|
244
|
-
rewind(
|
|
251
|
+
rewind(seq: number): void;
|
|
245
252
|
private cut;
|
|
246
253
|
/** Where subject `s`'s run starts in `runs`. */
|
|
247
254
|
base(s: number): number;
|
|
@@ -255,8 +262,8 @@ export declare class Motions<I> {
|
|
|
255
262
|
private commit;
|
|
256
263
|
private insert;
|
|
257
264
|
/**
|
|
258
|
-
* The mix time a stretch was in force by, which a store keys it under: when the change
|
|
259
|
-
* ended it was made, which falls in the same life of the subject.
|
|
265
|
+
* The mix time and frame a stretch was in force by, which a store keys it under: when the change
|
|
266
|
+
* that ended it was made, which falls in the same life of the subject.
|
|
260
267
|
*/
|
|
261
268
|
private made;
|
|
262
269
|
/** Lets go of stretches older than the one in force at `reading.horizon`. */
|