@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/revive.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { playable } from './cue.js';
|
|
2
2
|
import { VoiceHandle } from './handle.js';
|
|
3
3
|
import { handle } from './hosts.js';
|
|
4
|
+
import { Leavings } from './leavings.js';
|
|
4
5
|
import { packHeld, unpackHeld } from './pack.js';
|
|
5
6
|
import { pageOut } from './paging.js';
|
|
6
7
|
import { Voice } from './voice.js';
|
|
@@ -47,7 +48,7 @@ export function pageVoice(mix, voice, reach) {
|
|
|
47
48
|
return false;
|
|
48
49
|
const keys = mix.keys;
|
|
49
50
|
const data = packVoice(voice, keys);
|
|
50
|
-
pageOut(mix, 'voice', voice.id, undefined, [{ at: voice.doneAt }], () => data, reach);
|
|
51
|
+
pageOut(mix, 'voice', voice.id, undefined, [{ at: voice.doneAt, seq: voice.doneSeq }], () => data, reach);
|
|
51
52
|
const h = voice.handle;
|
|
52
53
|
VoiceHandle.page(h, { weight: voice.weight, played: voice.settled.played === true });
|
|
53
54
|
mix.outs.add(voice.id, voice.doneAt, h);
|
|
@@ -81,8 +82,13 @@ function packVoice(voice, keys) {
|
|
|
81
82
|
outAt: voice.outAt,
|
|
82
83
|
outOver: voice.outOver,
|
|
83
84
|
outSet: voice.outSet,
|
|
85
|
+
rebuilds: voice.rebuilds,
|
|
86
|
+
past: voice.clocks?.length ?? 0,
|
|
87
|
+
clocks: voice.clocks,
|
|
84
88
|
cuedAt: voice.cuedAt,
|
|
89
|
+
cuedSeq: voice.cuedSeq,
|
|
85
90
|
doneAt: voice.doneAt,
|
|
91
|
+
doneSeq: voice.doneSeq,
|
|
86
92
|
opened: voice.opened,
|
|
87
93
|
pinned: voice.pinned,
|
|
88
94
|
latest: voice.latest,
|
|
@@ -91,11 +97,18 @@ function packVoice(voice, keys) {
|
|
|
91
97
|
log: voice.log,
|
|
92
98
|
played: settled.played,
|
|
93
99
|
playedAt: settled.at,
|
|
100
|
+
playedSeq: settled.seq,
|
|
94
101
|
records,
|
|
95
102
|
runs,
|
|
96
|
-
left: (voice.left ?? []).map((e) => [
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
left: (voice.left?.all() ?? []).map((e) => [
|
|
104
|
+
keys.key(e.subject),
|
|
105
|
+
e.at,
|
|
106
|
+
e.seq,
|
|
107
|
+
packHeld(voice, e.held),
|
|
108
|
+
e.sync,
|
|
109
|
+
]),
|
|
110
|
+
parts: [...(voice.parts ?? [])].map(([s, r]) => [keys.key(s), r.at, r.over, r.seq]),
|
|
111
|
+
parted: [...(voice.parted ?? [])].map(([s, p]) => [keys.key(s), p.at, p.seq]),
|
|
99
112
|
};
|
|
100
113
|
}
|
|
101
114
|
/** A voice a history store paged out, rebuilt from its descriptor and put back as it left. */
|
|
@@ -106,18 +119,12 @@ export function reviveVoice(mix, id, d) {
|
|
|
106
119
|
const spec = { ...revive(d.as), as: d.as };
|
|
107
120
|
playable(mix, spec);
|
|
108
121
|
const voice = new Voice(id, spec, spec.patch, spec.fade ?? {}, Number.NEGATIVE_INFINITY, d.start, mix.slotOf, mix.channels, mix.opts.host, mix.send, null);
|
|
109
|
-
voice.
|
|
110
|
-
voice.
|
|
111
|
-
voice.rate = d.rate;
|
|
112
|
-
voice.ramp = d.ramp;
|
|
113
|
-
voice.weight = d.weight;
|
|
114
|
-
voice.out = d.out;
|
|
115
|
-
voice.back = d.back;
|
|
116
|
-
voice.outAt = d.outAt;
|
|
117
|
-
voice.outOver = d.outOver;
|
|
118
|
-
voice.outSet = d.outSet;
|
|
122
|
+
voice.clocks = d.clocks;
|
|
123
|
+
voice.take(d);
|
|
119
124
|
voice.cuedAt = d.cuedAt;
|
|
125
|
+
voice.cuedSeq = d.cuedSeq;
|
|
120
126
|
voice.doneAt = d.doneAt;
|
|
127
|
+
voice.doneSeq = d.doneSeq;
|
|
121
128
|
voice.opened = d.opened;
|
|
122
129
|
voice.pinned = d.pinned;
|
|
123
130
|
voice.latest = d.latest;
|
|
@@ -126,7 +133,7 @@ export function reviveVoice(mix, id, d) {
|
|
|
126
133
|
voice.log = d.log;
|
|
127
134
|
voice.state = 'done';
|
|
128
135
|
if (d.played !== undefined)
|
|
129
|
-
voice.play(d.played, d.playedAt);
|
|
136
|
+
voice.play(d.played, d.playedAt, d.playedSeq);
|
|
130
137
|
voice.resolve();
|
|
131
138
|
const keys = mix.keys;
|
|
132
139
|
const subjectOf = (key) => keys.subject(key);
|
|
@@ -137,16 +144,17 @@ export function reviveVoice(mix, id, d) {
|
|
|
137
144
|
}
|
|
138
145
|
for (const [key, run] of d.runs)
|
|
139
146
|
voice.motion?.unpack(subjectOf(key), run);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
voice.left = Leavings.from(d.left.map(([key, at, seq, p, sync]) => ({
|
|
148
|
+
subject: subjectOf(key),
|
|
149
|
+
at,
|
|
150
|
+
seq,
|
|
151
|
+
sync,
|
|
152
|
+
held: unpackHeld(voice, p),
|
|
153
|
+
})));
|
|
146
154
|
if (d.parts.length > 0)
|
|
147
|
-
voice.parts = new Map(d.parts.map(([key, at, over]) => [subjectOf(key), { at, over }]));
|
|
155
|
+
voice.parts = new Map(d.parts.map(([key, at, over, seq]) => [subjectOf(key), { at, over, seq }]));
|
|
148
156
|
if (d.parted.length > 0)
|
|
149
|
-
voice.parted = new Map(d.parted.map(([key, at]) => [subjectOf(key), at]));
|
|
157
|
+
voice.parted = new Map(d.parted.map(([key, at, seq]) => [subjectOf(key), { at, seq }]));
|
|
150
158
|
const h = mix.outs?.take(id);
|
|
151
159
|
if (h === undefined)
|
|
152
160
|
voice.handle = handle(mix, voice);
|
package/dist/roster.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Mixer } from './mixer.js';
|
|
2
|
+
import type { Voice } from './voice.js';
|
|
3
|
+
/** Counts a voice just put in the list into everything a sync and a fold skip work by. */
|
|
4
|
+
export declare function enlist<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>): void;
|
|
5
|
+
/**
|
|
6
|
+
* Counts a voice leaving the list back out. A voice naming no subject stays in `general` and
|
|
7
|
+
* `sharers`, which the caller filters once for every voice leaving together.
|
|
8
|
+
*/
|
|
9
|
+
export declare function delist<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>): void;
|
|
10
|
+
/** Counts the list over from nothing, for a seek or a projection's copy. `owners` is the caller's. */
|
|
11
|
+
export declare function recount<I, O>(mix: Mixer<I, O>): void;
|
package/dist/roster.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { index, unindex } from './chain.js';
|
|
2
|
+
import { detour } from './everyone.js';
|
|
3
|
+
import { Store } from './store.js';
|
|
4
|
+
function tally(mix, voice, by) {
|
|
5
|
+
if (voice.spec.locus !== undefined)
|
|
6
|
+
mix.loci += by;
|
|
7
|
+
if (voice.spec.anchor !== undefined)
|
|
8
|
+
mix.anchored += by;
|
|
9
|
+
}
|
|
10
|
+
/** Counts a voice just put in the list into everything a sync and a fold skip work by. */
|
|
11
|
+
export function enlist(mix, voice) {
|
|
12
|
+
if (voice.holding !== null) {
|
|
13
|
+
mix.owners ??= [];
|
|
14
|
+
mix.owners.push(voice);
|
|
15
|
+
}
|
|
16
|
+
index(mix, voice);
|
|
17
|
+
tally(mix, voice, 1);
|
|
18
|
+
detour(mix);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Counts a voice leaving the list back out. A voice naming no subject stays in `general` and
|
|
22
|
+
* `sharers`, which the caller filters once for every voice leaving together.
|
|
23
|
+
*/
|
|
24
|
+
export function delist(mix, voice) {
|
|
25
|
+
if (voice.named !== null)
|
|
26
|
+
unindex(mix, voice);
|
|
27
|
+
if (voice.holding !== null && mix.owners !== null)
|
|
28
|
+
mix.owners = mix.owners.filter((v) => v !== voice);
|
|
29
|
+
tally(mix, voice, -1);
|
|
30
|
+
detour(mix);
|
|
31
|
+
}
|
|
32
|
+
/** Counts the list over from nothing, for a seek or a projection's copy. `owners` is the caller's. */
|
|
33
|
+
export function recount(mix) {
|
|
34
|
+
mix.named = new Store();
|
|
35
|
+
mix.naming = 0;
|
|
36
|
+
mix.general = [];
|
|
37
|
+
mix.sharers = [];
|
|
38
|
+
mix.loci = 0;
|
|
39
|
+
mix.anchored = 0;
|
|
40
|
+
for (const voice of mix.cued) {
|
|
41
|
+
index(mix, voice);
|
|
42
|
+
tally(mix, voice, 1);
|
|
43
|
+
}
|
|
44
|
+
detour(mix);
|
|
45
|
+
mix.steps.push(null, ++mix.version);
|
|
46
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type Vec } from './channels.js';
|
|
2
|
+
import type { Channel } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* What `angle` takes.
|
|
5
|
+
*
|
|
6
|
+
* @category channel
|
|
7
|
+
*/
|
|
8
|
+
export interface AngleOptions {
|
|
9
|
+
/** One full turn in the channel's unit. Default 360, for degrees; `2 * Math.PI` for radians. */
|
|
10
|
+
turn?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A rotation about one axis, which adds as `sum` does and interpolates the short way round: from
|
|
14
|
+
* 350 to 10 it passes 0, not 180. A weight below 1 fades it the short way to rest too. Its values
|
|
15
|
+
* are angles, so two a whole number of turns apart are the same value, and a fold may answer with
|
|
16
|
+
* either.
|
|
17
|
+
*
|
|
18
|
+
* @category channel
|
|
19
|
+
*/
|
|
20
|
+
export declare function angle(opts?: AngleOptions): Channel<number>;
|
|
21
|
+
/**
|
|
22
|
+
* A rotation in space, as a unit quaternion `[x, y, z, w]`. Contributions compose by the Hamilton
|
|
23
|
+
* product in the order their voices were cued, which matters: rotations do not commute. A weight
|
|
24
|
+
* turns a contribution part of the way from no rotation, along the short arc, and `lerp` takes the
|
|
25
|
+
* short arc between two.
|
|
26
|
+
*
|
|
27
|
+
* @category channel
|
|
28
|
+
*/
|
|
29
|
+
export declare function quat(): Channel<Vec<4>>;
|
package/dist/rotation.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { doubles, vouch } from './channels.js';
|
|
2
|
+
import { shortWay } from './turns.js';
|
|
3
|
+
/**
|
|
4
|
+
* A rotation about one axis, which adds as `sum` does and interpolates the short way round: from
|
|
5
|
+
* 350 to 10 it passes 0, not 180. A weight below 1 fades it the short way to rest too. Its values
|
|
6
|
+
* are angles, so two a whole number of turns apart are the same value, and a fold may answer with
|
|
7
|
+
* either.
|
|
8
|
+
*
|
|
9
|
+
* @category channel
|
|
10
|
+
*/
|
|
11
|
+
export function angle(opts) {
|
|
12
|
+
const turn = opts?.turn ?? 360;
|
|
13
|
+
if (!(turn > 0))
|
|
14
|
+
throw new RangeError('blits: an angle takes a positive turn');
|
|
15
|
+
const channel = {
|
|
16
|
+
kind: `angle(${turn})`,
|
|
17
|
+
rest: 0,
|
|
18
|
+
merge: (a, b) => a + b,
|
|
19
|
+
scale: (v, w) => shortWay(v, turn) * w,
|
|
20
|
+
lerp: (a, b, u) => a + shortWay(b - a, turn) * u,
|
|
21
|
+
};
|
|
22
|
+
vouch(channel, { op: 'sum', axes: 1, turn });
|
|
23
|
+
return channel;
|
|
24
|
+
}
|
|
25
|
+
/** `a` then `b`, written into `out`, which may be either. */
|
|
26
|
+
function multiply(out, a, b) {
|
|
27
|
+
const ax = a[0];
|
|
28
|
+
const ay = a[1];
|
|
29
|
+
const az = a[2];
|
|
30
|
+
const aw = a[3];
|
|
31
|
+
const bx = b[0];
|
|
32
|
+
const by = b[1];
|
|
33
|
+
const bz = b[2];
|
|
34
|
+
const bw = b[3];
|
|
35
|
+
out[0] = aw * bx + ax * bw + ay * bz - az * by;
|
|
36
|
+
out[1] = aw * by - ax * bz + ay * bw + az * bx;
|
|
37
|
+
out[2] = aw * bz + ax * by - ay * bx + az * bw;
|
|
38
|
+
out[3] = aw * bw - ax * bx - ay * by - az * bz;
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
/** The short arc from `a` to `b` at `u`, a unit quaternion, written into `out`. */
|
|
42
|
+
function slerp(out, a, b, u) {
|
|
43
|
+
let dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
|
|
44
|
+
// `q` and `-q` are one rotation; the nearer of the two is the short way.
|
|
45
|
+
const sign = dot < 0 ? -1 : 1;
|
|
46
|
+
dot *= sign;
|
|
47
|
+
let p = 1 - u;
|
|
48
|
+
let q = u;
|
|
49
|
+
// Nearly parallel, the arc's sine is too small to divide by, and a straight line is as good.
|
|
50
|
+
if (dot < 1 - 1e-9) {
|
|
51
|
+
const theta = Math.acos(dot);
|
|
52
|
+
const s = Math.sin(theta);
|
|
53
|
+
p = Math.sin((1 - u) * theta) / s;
|
|
54
|
+
q = Math.sin(u * theta) / s;
|
|
55
|
+
}
|
|
56
|
+
q *= sign;
|
|
57
|
+
const x = p * a[0] + q * b[0];
|
|
58
|
+
const y = p * a[1] + q * b[1];
|
|
59
|
+
const z = p * a[2] + q * b[2];
|
|
60
|
+
const w = p * a[3] + q * b[3];
|
|
61
|
+
const n = Math.sqrt(x * x + y * y + z * z + w * w) || 1;
|
|
62
|
+
out[0] = x / n;
|
|
63
|
+
out[1] = y / n;
|
|
64
|
+
out[2] = z / n;
|
|
65
|
+
out[3] = w / n;
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
const IDENTITY = [0, 0, 0, 1];
|
|
69
|
+
const scratch = doubles(4, 0);
|
|
70
|
+
/**
|
|
71
|
+
* A rotation in space, as a unit quaternion `[x, y, z, w]`. Contributions compose by the Hamilton
|
|
72
|
+
* product in the order their voices were cued, which matters: rotations do not commute. A weight
|
|
73
|
+
* turns a contribution part of the way from no rotation, along the short arc, and `lerp` takes the
|
|
74
|
+
* short arc between two.
|
|
75
|
+
*
|
|
76
|
+
* @category channel
|
|
77
|
+
*/
|
|
78
|
+
export function quat() {
|
|
79
|
+
const rest = doubles(4, 0);
|
|
80
|
+
rest[3] = 1;
|
|
81
|
+
const channel = {
|
|
82
|
+
kind: 'quat',
|
|
83
|
+
rest: rest,
|
|
84
|
+
merge: (a, b) => multiply(doubles(4, 0), a, b),
|
|
85
|
+
scale: (v, w) => slerp(doubles(4, 0), IDENTITY, v, w),
|
|
86
|
+
fold: (into, v, w) => multiply(into, into, slerp(scratch, IDENTITY, v, w)),
|
|
87
|
+
lerp: (a, b, u) => slerp(doubles(4, 0), a, b, u),
|
|
88
|
+
};
|
|
89
|
+
vouch(channel, { op: 'own', axes: 4 });
|
|
90
|
+
return channel;
|
|
91
|
+
}
|
package/dist/rows.d.ts
CHANGED
|
@@ -15,19 +15,19 @@ export declare function sameCrowds<I, O>(lanes: Lanes<I, O>, members: readonly V
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function regroup<I, O>(lanes: Lanes<I, O>, members: Voice<I, O>[]): void;
|
|
17
17
|
/**
|
|
18
|
-
* Gives a voice the next row of its
|
|
18
|
+
* Gives a voice the next row of its channels' crowd, made if there is none: a copy of the row it
|
|
19
19
|
* had in `from` at `at`, or a new one. `old` holds the crowds being replaced, whose idle state a
|
|
20
|
-
* new crowd on the same
|
|
20
|
+
* new crowd on the same channels keeps. Rows stay in voice order only because voices join in it.
|
|
21
21
|
*/
|
|
22
22
|
export declare function join<I, O>(lanes: Lanes<I, O>, v: Voice<I, O>, from: Crowd<I, O> | undefined, at: number | undefined, old: readonly Crowd<I, O>[]): void;
|
|
23
23
|
/** A crowd row takes up its voice as it now stands: opened once it starts, its fields copied again. */
|
|
24
24
|
export declare function retouchRow<I, O>(lanes: Lanes<I, O>, c: Crowd<I, O>, p: number, v: Voice<I, O>): void;
|
|
25
25
|
/**
|
|
26
|
-
* Compacts every crowd a quarter or more empty rows: each fill walks every row,
|
|
27
|
-
* crowd replacing a voice a frame carried as many empty rows as live ones.
|
|
26
|
+
* Compacts every crowd a quarter or more empty rows, past 64 of them: each fill walks every row,
|
|
27
|
+
* and at half a crowd replacing a voice a frame carried as many empty rows as live ones.
|
|
28
28
|
*/
|
|
29
29
|
export declare function compactSparse<I, O>(lanes: Lanes<I, O>): void;
|
|
30
|
-
/** A crowd voice left: its row stays, empty, until the
|
|
30
|
+
/** A crowd voice left: its row stays, empty, until the crowd is compacted or rebuilt. */
|
|
31
31
|
export declare function bury<I, O>(lanes: Lanes<I, O>, c: Crowd<I, O>, p: number): void;
|
|
32
32
|
/** A crowd row's weight as `reported` reads a lane position's. */
|
|
33
33
|
export declare function reportedRow<I, O>(lanes: Lanes<I, O>, c: Crowd<I, O>, p: number, slot: number): number | undefined;
|
package/dist/rows.js
CHANGED
|
@@ -75,9 +75,9 @@ export function regroup(lanes, members) {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
78
|
-
* Gives a voice the next row of its
|
|
78
|
+
* Gives a voice the next row of its channels' crowd, made if there is none: a copy of the row it
|
|
79
79
|
* had in `from` at `at`, or a new one. `old` holds the crowds being replaced, whose idle state a
|
|
80
|
-
* new crowd on the same
|
|
80
|
+
* new crowd on the same channels keeps. Rows stay in voice order only because voices join in it.
|
|
81
81
|
*/
|
|
82
82
|
export function join(lanes, v, from, at, old) {
|
|
83
83
|
const chans = v.slots.map((s) => lanes.bySlot[s]);
|
|
@@ -113,8 +113,8 @@ export function retouchRow(lanes, c, p, v) {
|
|
|
113
113
|
c.hot[h + 0 /* Hot.FLAGS */] = c.hot[h + 0 /* Hot.FLAGS */] | 64 /* Flag.VOICE */;
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
|
-
* Compacts every crowd a quarter or more empty rows: each fill walks every row,
|
|
117
|
-
* crowd replacing a voice a frame carried as many empty rows as live ones.
|
|
116
|
+
* Compacts every crowd a quarter or more empty rows, past 64 of them: each fill walks every row,
|
|
117
|
+
* and at half a crowd replacing a voice a frame carried as many empty rows as live ones.
|
|
118
118
|
*/
|
|
119
119
|
export function compactSparse(lanes) {
|
|
120
120
|
for (const c of lanes.crowds)
|
|
@@ -154,7 +154,7 @@ function compact(c) {
|
|
|
154
154
|
c.laws.length = q;
|
|
155
155
|
c.dead = 0;
|
|
156
156
|
}
|
|
157
|
-
/** A crowd voice left: its row stays, empty, until the
|
|
157
|
+
/** A crowd voice left: its row stays, empty, until the crowd is compacted or rebuilt. */
|
|
158
158
|
export function bury(lanes, c, p) {
|
|
159
159
|
const v = c.voices[p];
|
|
160
160
|
leaveCrowd(lanes, c, p);
|
package/dist/sample.d.ts
CHANGED
|
@@ -11,9 +11,10 @@ export declare function runMotion<I, O>(lanes: Lanes<I, O>, lane: Lane<I, O>, ru
|
|
|
11
11
|
* A motion voice's value for a subject, sampled from the patch's state as its `at` would, but only
|
|
12
12
|
* where that sample changes nothing: one with a change to stamp, commit or let go of goes to the
|
|
13
13
|
* general path, which samples it if and when a probe asks, as it would with no lanes. A probe
|
|
14
|
-
* this frame already read keeps the value it read, as the general path's record would.
|
|
14
|
+
* this frame already read keeps the value it read, as the general path's record would. The
|
|
15
|
+
* subject's voice time, delay and weight are in `Arg`.
|
|
15
16
|
*/
|
|
16
|
-
export declare function move<I, O>(lanes: Lanes<I, O>, lane: Positions<I, O>, run: Motions<I>, p: number, slot: number, held: Subject<unknown
|
|
17
|
+
export declare function move<I, O>(lanes: Lanes<I, O>, lane: Positions<I, O>, run: Motions<I>, p: number, slot: number, held: Subject<unknown>): void;
|
|
17
18
|
/**
|
|
18
19
|
* A probe this frame read a motion voice's value for the subject from an earlier fill: write onto
|
|
19
20
|
* its record what the general path's sample would have, so a later read this frame reuses it.
|
package/dist/sample.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { unbareLane } from './bare.js';
|
|
2
2
|
import { foldNumber } from './channels.js';
|
|
3
|
-
import { clampWeight, passAt, weighed } from './clock.js';
|
|
3
|
+
import { clampWeight, passAt, same, weighed } from './clock.js';
|
|
4
4
|
import { absent } from './numbers.js';
|
|
5
5
|
import { reading } from './reading.js';
|
|
6
6
|
import { between, left, progress } from './tweened.js';
|
|
@@ -26,6 +26,7 @@ export function runMotion(lanes, lane, run) {
|
|
|
26
26
|
// On a frame's first fill no probe has read a subject yet, so none needs `move` for that.
|
|
27
27
|
const probed = lanes.probes !== from;
|
|
28
28
|
const whole = clampWeight(voice.weight);
|
|
29
|
+
const arg = lanes.arg;
|
|
29
30
|
const n = run.n;
|
|
30
31
|
const op = ch.op;
|
|
31
32
|
if (n > 0) {
|
|
@@ -48,7 +49,7 @@ export function runMotion(lanes, lane, run) {
|
|
|
48
49
|
run.watchId = voice.id;
|
|
49
50
|
}
|
|
50
51
|
const own = ease !== undefined && !signal && run.watcher === lanes && run.watchId === voice.id;
|
|
51
|
-
const folds = n === ch.axes;
|
|
52
|
+
const folds = n === ch.axes && ch.plain;
|
|
52
53
|
for (let p = 0; p < list.length; p++) {
|
|
53
54
|
// Its signal just made kept state: no further call this fill, the general path makes them.
|
|
54
55
|
if (signal && voice.keeping)
|
|
@@ -64,14 +65,14 @@ export function runMotion(lanes, lane, run) {
|
|
|
64
65
|
}
|
|
65
66
|
const delay = data[o + 0 /* Row.DELAY */];
|
|
66
67
|
const elapsed = elapsedNow - delay;
|
|
67
|
-
if (elapsed
|
|
68
|
+
if (!(elapsed >= 0)) {
|
|
68
69
|
unbareLane(lane, p);
|
|
69
70
|
data[o + 2 /* Row.WEIGHT */] = 0;
|
|
70
71
|
continue;
|
|
71
72
|
}
|
|
72
73
|
if (!flat) {
|
|
73
74
|
const since = data[o + 1 /* Row.SINCE */];
|
|
74
|
-
if (!lane.weighed || !
|
|
75
|
+
if (!lane.weighed || !same(since, lane.weighedSince)) {
|
|
75
76
|
lane.fade = lanes.host.envelope(voice, since);
|
|
76
77
|
lane.weighed = true;
|
|
77
78
|
lane.weighedSince = since;
|
|
@@ -79,11 +80,14 @@ export function runMotion(lanes, lane, run) {
|
|
|
79
80
|
}
|
|
80
81
|
let w;
|
|
81
82
|
if (signal) {
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
arg[1 /* Arg.ELAPSED */] = elapsed;
|
|
84
|
+
arg[3 /* Arg.PASS */] = passAt(elapsed, voice.duration, voice.passes);
|
|
85
|
+
arg[5 /* Arg.FADE */] = lane.fade;
|
|
86
|
+
if (!lanes.signalled(voice, slot, records[p])) {
|
|
84
87
|
data[o + 2 /* Row.WEIGHT */] = 0;
|
|
85
88
|
continue;
|
|
86
89
|
}
|
|
90
|
+
w = arg[0 /* Arg.WEIGHT */];
|
|
87
91
|
}
|
|
88
92
|
else
|
|
89
93
|
w = flat && !parts ? whole : weighed(voice.weight, lane.fade, lanes.parting(voice, slot));
|
|
@@ -102,7 +106,10 @@ export function runMotion(lanes, lane, run) {
|
|
|
102
106
|
(probed &&
|
|
103
107
|
(per[q + 3 /* Per.LANE_PROBE */] > from ||
|
|
104
108
|
per[q + 4 /* Per.GENERAL_PROBE */] > from))) {
|
|
105
|
-
|
|
109
|
+
arg[1 /* Arg.ELAPSED */] = elapsed;
|
|
110
|
+
arg[4 /* Arg.DELAY */] = delay;
|
|
111
|
+
arg[0 /* Arg.WEIGHT */] = w;
|
|
112
|
+
move(lanes, lane, run, p, slot, records[p]);
|
|
106
113
|
continue;
|
|
107
114
|
}
|
|
108
115
|
const runs = run.runs;
|
|
@@ -123,7 +130,7 @@ export function runMotion(lanes, lane, run) {
|
|
|
123
130
|
continue;
|
|
124
131
|
}
|
|
125
132
|
if (ease !== undefined) {
|
|
126
|
-
// A tween's closed form, read straight from its run: release time,
|
|
133
|
+
// A tween's closed form, read straight from its run: release time, length, `x0`, `to`.
|
|
127
134
|
const share = left(ease, progress(elapsed, runs[b], runs[b + 2]));
|
|
128
135
|
const x = b + 3;
|
|
129
136
|
const g = x + 2 * n;
|
|
@@ -146,8 +153,10 @@ export function runMotion(lanes, lane, run) {
|
|
|
146
153
|
for (let a = 0; a < n; a++)
|
|
147
154
|
values[base + a] = foldNumber(op, values[base + a], xs[a], w);
|
|
148
155
|
}
|
|
149
|
-
else
|
|
150
|
-
|
|
156
|
+
else {
|
|
157
|
+
arg[0 /* Arg.WEIGHT */] = w;
|
|
158
|
+
lanes.foldInto(ch, slot, run.value(ms, xs));
|
|
159
|
+
}
|
|
151
160
|
}
|
|
152
161
|
if (own) {
|
|
153
162
|
lane.bareFill = fills;
|
|
@@ -159,14 +168,22 @@ export function runMotion(lanes, lane, run) {
|
|
|
159
168
|
* A motion voice's value for a subject, sampled from the patch's state as its `at` would, but only
|
|
160
169
|
* where that sample changes nothing: one with a change to stamp, commit or let go of goes to the
|
|
161
170
|
* general path, which samples it if and when a probe asks, as it would with no lanes. A probe
|
|
162
|
-
* this frame already read keeps the value it read, as the general path's record would.
|
|
171
|
+
* this frame already read keeps the value it read, as the general path's record would. The
|
|
172
|
+
* subject's voice time, delay and weight are in `Arg`.
|
|
163
173
|
*/
|
|
164
|
-
export function move(lanes, lane, run, p, slot, held
|
|
174
|
+
export function move(lanes, lane, run, p, slot, held) {
|
|
175
|
+
const elapsed = lanes.arg[1 /* Arg.ELAPSED */];
|
|
176
|
+
const delay = lanes.arg[4 /* Arg.DELAY */];
|
|
177
|
+
const w = lanes.arg[0 /* Arg.WEIGHT */];
|
|
165
178
|
const voice = lane.voiceAt(p);
|
|
166
179
|
const data = lane.data;
|
|
167
180
|
const o = p * 8 /* Row.STRIDE */;
|
|
168
181
|
const ch = lane.chans[0];
|
|
169
182
|
settle(lanes, lane, p, slot, held);
|
|
183
|
+
// The general path never samples a voice at weight 0, so the motion neither numbers the subject
|
|
184
|
+
// nor runs on for it, and `inert` reads the same.
|
|
185
|
+
if (!(w > 0))
|
|
186
|
+
return;
|
|
170
187
|
const delta = held.delta;
|
|
171
188
|
if (delta === null ||
|
|
172
189
|
held.probed !== lanes.now ||
|
|
@@ -200,16 +217,16 @@ export function move(lanes, lane, run, p, slot, held, elapsed, delay, w) {
|
|
|
200
217
|
return;
|
|
201
218
|
// A sample of other axes than the channel's folds as the general path folds it.
|
|
202
219
|
if (n === ch.axes && run.scalar(ms) === ch.scalar)
|
|
203
|
-
lanes.foldRun(ch, slot, run.xs
|
|
220
|
+
lanes.foldRun(ch, slot, run.xs);
|
|
204
221
|
else
|
|
205
|
-
lanes.foldInto(ch, slot, run.value(ms, run.xs)
|
|
222
|
+
lanes.foldInto(ch, slot, run.value(ms, run.xs));
|
|
206
223
|
return;
|
|
207
224
|
}
|
|
208
225
|
lane.deltas[p] = delta;
|
|
209
226
|
data[o + 5 /* Row.SAMPLED */] = lanes.fills;
|
|
210
227
|
data[o + 6 /* Row.SEEKS */] = voice.seeks;
|
|
211
228
|
if (w > 0)
|
|
212
|
-
lanes.foldInto(ch, slot, delta[ch.name]
|
|
229
|
+
lanes.foldInto(ch, slot, delta[ch.name]);
|
|
213
230
|
}
|
|
214
231
|
/** The delta a motion voice's last sample for position `p` made, built from `samples`. */
|
|
215
232
|
function sampled(lane, p) {
|