@msb235/blits 0.13.0 → 0.15.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 +183 -0
- package/README.md +20 -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 +15 -7
- 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/closed.d.ts +1 -0
- package/dist/closed.js +45 -1
- package/dist/color.d.ts +12 -10
- package/dist/color.js +25 -25
- package/dist/columns.js +7 -3
- 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 +8 -2
- package/dist/crowd.js +4 -5
- package/dist/cue.d.ts +8 -1
- package/dist/cue.js +47 -14
- package/dist/cut.d.ts +8 -0
- package/dist/cut.js +4 -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 +113 -33
- package/dist/easing.d.ts +4 -4
- package/dist/easing.js +3 -3
- package/dist/everyone.d.ts +3 -2
- package/dist/everyone.js +3 -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 +51 -19
- package/dist/fit.d.ts +44 -26
- package/dist/fit.js +10 -9
- package/dist/fling.d.ts +66 -0
- package/dist/fling.js +162 -0
- package/dist/fold.d.ts +4 -37
- package/dist/fold.js +5 -512
- 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 +3 -0
- package/dist/handle.js +19 -8
- package/dist/held.d.ts +2 -1
- package/dist/history.d.ts +6 -5
- package/dist/history.js +9 -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 +36 -6
- package/dist/lane.js +32 -1
- package/dist/lanes.d.ts +23 -8
- package/dist/lanes.js +29 -8
- 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 +90 -4
- package/dist/mixer.d.ts +61 -35
- package/dist/mixer.js +64 -169
- package/dist/motion.d.ts +19 -106
- package/dist/motion.js +60 -13
- package/dist/motions.d.ts +62 -150
- package/dist/motions.js +57 -369
- package/dist/move.js +24 -1
- package/dist/moved.d.ts +1 -1
- package/dist/moved.js +16 -7
- package/dist/named.d.ts +0 -1
- package/dist/named.js +20 -2
- package/dist/numbers.d.ts +2 -0
- package/dist/numbers.js +4 -0
- package/dist/owed.d.ts +2 -0
- package/dist/owed.js +4 -0
- package/dist/pack.d.ts +3 -1
- package/dist/pack.js +4 -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 -211
- package/dist/pull.js +11 -8
- package/dist/qualify.js +84 -21
- package/dist/reading.d.ts +6 -0
- package/dist/reading.js +5 -0
- package/dist/record.d.ts +5 -1
- package/dist/record.js +4 -2
- package/dist/relink.d.ts +1 -1
- 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 +1 -1
- package/dist/sample.d.ts +2 -2
- package/dist/sample.js +33 -7
- package/dist/seek.js +13 -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 +21 -14
- 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/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 +222 -161
- package/dist/types/motion.d.ts +151 -0
- package/dist/types/motion.js +1 -0
- package/dist/types/patch.d.ts +69 -34
- package/dist/types/place.d.ts +51 -36
- package/dist/types/transport.d.ts +20 -18
- package/dist/types/voice.d.ts +145 -72
- package/dist/types/watch.d.ts +88 -40
- package/dist/types.d.ts +1 -0
- package/dist/voice.d.ts +9 -141
- package/dist/voice.js +30 -79
- 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 -37
- package/package.json +6 -2
package/dist/roles.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { first } from './clone.js';
|
|
2
|
+
import { open as openRecord } from './everyone.js';
|
|
3
|
+
import { merged, unband } from './fold.js';
|
|
4
|
+
import { roleScratch } from './role.js';
|
|
5
|
+
// V8 reads a local const as a constant, where it reads an import from its module on every call.
|
|
6
|
+
const open = openRecord;
|
|
7
|
+
/**
|
|
8
|
+
* Whether a fold's next voice is its chain's next record, `held`, and not the next voice sharing
|
|
9
|
+
* one record, `sharers[q]`: the two lists are each in voice order, and a fold takes them as one.
|
|
10
|
+
*/
|
|
11
|
+
export function chainFirst(held, sharers, q) {
|
|
12
|
+
if (held === null)
|
|
13
|
+
return false;
|
|
14
|
+
if (q >= sharers.length || held.voice === null)
|
|
15
|
+
return true;
|
|
16
|
+
const next = sharers[q];
|
|
17
|
+
return next.id > held.voice.id;
|
|
18
|
+
}
|
|
19
|
+
/** `foldWith`'s voices with a role in play: each role folds at its first member's place. */
|
|
20
|
+
export function foldRoles(subject, pose, head, laned, dry, except, owed) {
|
|
21
|
+
const now = this.now;
|
|
22
|
+
// A patch reading the pose can fold again from inside this one, so each depth has its own.
|
|
23
|
+
let k = this.roleScratch[this.roleDepth];
|
|
24
|
+
if (k === undefined) {
|
|
25
|
+
k = roleScratch(this.channels.length);
|
|
26
|
+
this.roleScratch[this.roleDepth] = k;
|
|
27
|
+
}
|
|
28
|
+
this.roleDepth++;
|
|
29
|
+
try {
|
|
30
|
+
k.n = 0;
|
|
31
|
+
k.m = 0;
|
|
32
|
+
k.names.length = 0;
|
|
33
|
+
const sharers = this.sharers;
|
|
34
|
+
let q = 0;
|
|
35
|
+
let at = head;
|
|
36
|
+
while (at !== null || q < sharers.length) {
|
|
37
|
+
const mine = chainFirst(at, sharers, q);
|
|
38
|
+
let voice;
|
|
39
|
+
let rec;
|
|
40
|
+
if (mine) {
|
|
41
|
+
rec = at;
|
|
42
|
+
voice = rec.voice;
|
|
43
|
+
at = rec.next;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
voice = sharers[q++];
|
|
47
|
+
rec = voice.state === 'pending' ? null : voice.everyone;
|
|
48
|
+
}
|
|
49
|
+
if (voice === null || rec === null)
|
|
50
|
+
continue;
|
|
51
|
+
if (laned && voice.laned && !this.owedBy(owed, voice))
|
|
52
|
+
continue;
|
|
53
|
+
if (voice.id === except || voice.state === 'done')
|
|
54
|
+
continue;
|
|
55
|
+
const held = rec;
|
|
56
|
+
if (!mine)
|
|
57
|
+
open(voice, held, head.slot);
|
|
58
|
+
const delta = this.read(voice, subject, now, dry, held);
|
|
59
|
+
if (owed >= 0 && voice.laned)
|
|
60
|
+
this.lanes.paid(voice.id, owed, held.weight);
|
|
61
|
+
if (!mine)
|
|
62
|
+
q = this.shared(voice, head.slot, held, q);
|
|
63
|
+
if (delta === null)
|
|
64
|
+
continue;
|
|
65
|
+
const role = voice.spec.role;
|
|
66
|
+
let group = -1;
|
|
67
|
+
if (role !== undefined) {
|
|
68
|
+
group = k.names.indexOf(role);
|
|
69
|
+
const m = k.m++;
|
|
70
|
+
k.mVoices[m] = voice;
|
|
71
|
+
k.mDeltas[m] = delta;
|
|
72
|
+
k.mWeights[m] = this.w;
|
|
73
|
+
if (group >= 0) {
|
|
74
|
+
k.mGroups[m] = group;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
group = k.names.length;
|
|
78
|
+
k.names.push(role);
|
|
79
|
+
k.mGroups[m] = group;
|
|
80
|
+
}
|
|
81
|
+
const n = k.n++;
|
|
82
|
+
k.voices[n] = voice;
|
|
83
|
+
k.helds[n] = held;
|
|
84
|
+
k.deltas[n] = delta;
|
|
85
|
+
k.weights[n] = role === undefined ? this.w : 0;
|
|
86
|
+
k.groups[n] = group;
|
|
87
|
+
}
|
|
88
|
+
let bands = head.roles;
|
|
89
|
+
if (bands === null) {
|
|
90
|
+
bands = new Map();
|
|
91
|
+
head.roles = bands;
|
|
92
|
+
}
|
|
93
|
+
for (let n = 0; n < k.n; n++) {
|
|
94
|
+
const group = k.groups[n];
|
|
95
|
+
if (group < 0) {
|
|
96
|
+
const weight = k.weights[n];
|
|
97
|
+
if (weight > 0)
|
|
98
|
+
this.apply(pose, k.voices[n], k.helds[n], k.deltas[n], weight);
|
|
99
|
+
else
|
|
100
|
+
unband(k.helds[n]);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const weight = this.foldRole(k, group);
|
|
104
|
+
const name = k.names[group];
|
|
105
|
+
if (!(weight > 0)) {
|
|
106
|
+
bands.get(name)?.fill(2);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
let on = bands.get(name);
|
|
110
|
+
if (on === undefined) {
|
|
111
|
+
on = new Uint8Array(this.channels.length);
|
|
112
|
+
bands.set(name, on);
|
|
113
|
+
}
|
|
114
|
+
for (let t = 0; t < k.touched.length; t++) {
|
|
115
|
+
const slot = k.touched[t];
|
|
116
|
+
const value = k.values[slot];
|
|
117
|
+
k.values[slot] = undefined;
|
|
118
|
+
const key = this.names[slot];
|
|
119
|
+
const channel = this.channels[slot];
|
|
120
|
+
// A channel folds at the weight of the members that wrote it, not the whole role.
|
|
121
|
+
const taken = k.taken[slot];
|
|
122
|
+
const w = taken > 1 ? 1 : taken;
|
|
123
|
+
if (channel.rest !== undefined && channel.scale) {
|
|
124
|
+
// pose[key] is the copy of rest this fold made, so it is ours to write into.
|
|
125
|
+
pose[key] = channel.fold
|
|
126
|
+
? channel.fold(pose[key], value, w)
|
|
127
|
+
: merged(channel, pose[key], channel.scale(value, w));
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const band = on[slot];
|
|
131
|
+
const passes = this.passes(band === 0 ? undefined : band === 1, w);
|
|
132
|
+
on[slot] = passes ? 1 : 2;
|
|
133
|
+
if (passes)
|
|
134
|
+
pose[key] = pose[key] === undefined ? first(value) : merged(channel, pose[key], value);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return pose;
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
for (let n = 0; n < k.n; n++) {
|
|
141
|
+
k.voices[n] = null;
|
|
142
|
+
k.helds[n] = null;
|
|
143
|
+
k.deltas[n] = null;
|
|
144
|
+
}
|
|
145
|
+
for (let m = 0; m < k.m; m++) {
|
|
146
|
+
k.mVoices[m] = null;
|
|
147
|
+
k.mDeltas[m] = null;
|
|
148
|
+
}
|
|
149
|
+
// Left set only where a channel's lerp threw partway, which the next fold must not inherit.
|
|
150
|
+
for (let t = 0; t < k.touched.length; t++) {
|
|
151
|
+
const slot = k.touched[t];
|
|
152
|
+
k.met[slot] = 0;
|
|
153
|
+
k.values[slot] = undefined;
|
|
154
|
+
}
|
|
155
|
+
k.touched.length = 0;
|
|
156
|
+
this.roleDepth--;
|
|
157
|
+
}
|
|
158
|
+
}
|
package/dist/roster.js
CHANGED
|
@@ -2,8 +2,8 @@ import { index, unindex } from './chain.js';
|
|
|
2
2
|
import { detour } from './everyone.js';
|
|
3
3
|
import { Store } from './store.js';
|
|
4
4
|
function tally(mix, voice, by) {
|
|
5
|
-
if (voice.spec.
|
|
6
|
-
mix.
|
|
5
|
+
if (voice.spec.role !== undefined)
|
|
6
|
+
mix.roleVoices += by;
|
|
7
7
|
const e = voice.spec.earliest;
|
|
8
8
|
if (voice.spec.anchor !== undefined || (e !== undefined && typeof e !== 'number'))
|
|
9
9
|
mix.anchored += by;
|
|
@@ -36,7 +36,7 @@ export function recount(mix) {
|
|
|
36
36
|
mix.naming = 0;
|
|
37
37
|
mix.general = [];
|
|
38
38
|
mix.sharers = [];
|
|
39
|
-
mix.
|
|
39
|
+
mix.roleVoices = 0;
|
|
40
40
|
mix.anchored = 0;
|
|
41
41
|
for (const voice of mix.cued) {
|
|
42
42
|
index(mix, voice);
|
package/dist/rotation.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface AngleOptions {
|
|
|
10
10
|
turn?: number;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* A rotation about one axis
|
|
13
|
+
* A rotation about one axis that interpolates the short way round. It adds as `sum` does, and from
|
|
14
14
|
* 350 to 10 it passes 0, not 180. A weight below 1 fades it the short way to rest too. Its values
|
|
15
15
|
* are angles, so two a whole number of turns apart are the same value, and a fold may answer with
|
|
16
16
|
* either.
|
package/dist/rotation.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { doubles, vouch } from './channels.js';
|
|
2
2
|
import { shortWay } from './turns.js';
|
|
3
3
|
/**
|
|
4
|
-
* A rotation about one axis
|
|
4
|
+
* A rotation about one axis that interpolates the short way round. It adds as `sum` does, and from
|
|
5
5
|
* 350 to 10 it passes 0, not 180. A weight below 1 fades it the short way to rest too. Its values
|
|
6
6
|
* are angles, so two a whole number of turns apart are the same value, and a fold may answer with
|
|
7
7
|
* either.
|
package/dist/rows.js
CHANGED
|
@@ -25,7 +25,7 @@ export function unplace(lanes, c, p) {
|
|
|
25
25
|
c.records[p] = undefined;
|
|
26
26
|
c.deltas[p] = null;
|
|
27
27
|
const f = p * c.stride + 0 /* Hot.FLAGS */;
|
|
28
|
-
c.hot[f] = c.hot[f] & ~16 /* Flag.PLACED
|
|
28
|
+
c.hot[f] = c.hot[f] & ~(16 /* Flag.PLACED */ | 2048 /* Flag.READY */);
|
|
29
29
|
const o = p * 8 /* Row.STRIDE */;
|
|
30
30
|
c.data[o + 4 /* Row.MSLOT */] = -1;
|
|
31
31
|
c.data[o + 5 /* Row.SAMPLED */] = -1;
|
package/dist/sample.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Lane, type Positions } from './lane.js';
|
|
2
2
|
import type { Lanes } from './lanes.js';
|
|
3
|
-
import type
|
|
4
|
-
import type { Subject } from './
|
|
3
|
+
import { type Motions } from './motions.js';
|
|
4
|
+
import type { Subject } from './subject.js';
|
|
5
5
|
/**
|
|
6
6
|
* A motion voice's fill: what `one` and `move` do for each subject, in one loop for the common
|
|
7
7
|
* case, a subject not yet probed this frame with nothing pending, and through `move` for the rest.
|
package/dist/sample.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { unbareLane } from './bare.js';
|
|
2
2
|
import { foldNumber } from './channels.js';
|
|
3
3
|
import { clampWeight, passAt, same, weighed } from './clock.js';
|
|
4
|
+
import { keepProbed } from './lane.js';
|
|
4
5
|
import { absent } from './numbers.js';
|
|
5
6
|
import { reading } from './reading.js';
|
|
6
7
|
import { between, left, progress } from './tweened.js';
|
|
@@ -50,6 +51,11 @@ export function runMotion(lanes, lane, run) {
|
|
|
50
51
|
}
|
|
51
52
|
const own = ease !== undefined && !signal && run.watcher === lanes && run.watchId === voice.id;
|
|
52
53
|
const folds = n === ch.axes && ch.plain;
|
|
54
|
+
// The weight a voice with a fade and no subject ramps gives every subject at one fade: worked
|
|
55
|
+
// out again for a zero, whose sign a hit by `===` would not keep.
|
|
56
|
+
let fadeOf = Number.NaN;
|
|
57
|
+
let baseOf = Number.NaN;
|
|
58
|
+
let faded = 0;
|
|
53
59
|
for (let p = 0; p < list.length; p++) {
|
|
54
60
|
// Its signal just made kept state: no further call this fill, the general path makes them.
|
|
55
61
|
if (signal && voice.keeping)
|
|
@@ -57,8 +63,7 @@ export function runMotion(lanes, lane, run) {
|
|
|
57
63
|
const slot = list[p];
|
|
58
64
|
const o = p * 8 /* Row.STRIDE */;
|
|
59
65
|
const q = slot * 6 /* Per.SLOT */;
|
|
60
|
-
|
|
61
|
-
data[o + 3 /* Row.PROBED */] = data[o + 2 /* Row.WEIGHT */];
|
|
66
|
+
keepProbed(data, o, per, q, fills);
|
|
62
67
|
if (lately >= 0 && lanes.unread(slot)) {
|
|
63
68
|
unbareLane(lane, p);
|
|
64
69
|
continue;
|
|
@@ -89,8 +94,20 @@ export function runMotion(lanes, lane, run) {
|
|
|
89
94
|
}
|
|
90
95
|
w = arg[0 /* Arg.WEIGHT */];
|
|
91
96
|
}
|
|
92
|
-
else
|
|
93
|
-
w =
|
|
97
|
+
else if (parts)
|
|
98
|
+
w = weighed(voice.weight, lane.fade, lanes.parting(voice, slot));
|
|
99
|
+
else if (flat)
|
|
100
|
+
w = whole;
|
|
101
|
+
else {
|
|
102
|
+
const fade = lane.fade;
|
|
103
|
+
const base = voice.weight;
|
|
104
|
+
if (fade !== fadeOf || base !== baseOf || fade === 0 || base === 0) {
|
|
105
|
+
fadeOf = fade;
|
|
106
|
+
baseOf = base;
|
|
107
|
+
faded = weighed(base, fade, 1);
|
|
108
|
+
}
|
|
109
|
+
w = faded;
|
|
110
|
+
}
|
|
94
111
|
data[o + 2 /* Row.WEIGHT */] = w;
|
|
95
112
|
if (data[o + 7 /* Row.MET */] === 0) {
|
|
96
113
|
if (Number.isNaN(records[p].probed)) {
|
|
@@ -101,7 +118,16 @@ export function runMotion(lanes, lane, run) {
|
|
|
101
118
|
data[o + 7 /* Row.MET */] = 1;
|
|
102
119
|
}
|
|
103
120
|
const ms = data[o + 4 /* Row.MSLOT */];
|
|
104
|
-
|
|
121
|
+
// `bareAt` and `scalar` written out: V8 leaves them and `base` out of line here.
|
|
122
|
+
let b = -1;
|
|
123
|
+
let scalar = false;
|
|
124
|
+
if (ms >= 0) {
|
|
125
|
+
b = 5 /* Law.HEAD */ + ms * run.stride;
|
|
126
|
+
const f = run.runs[b + 1];
|
|
127
|
+
if ((f & (2 /* RunFlag.PENDING */ | 4 /* RunFlag.OLDER */)) !== 0)
|
|
128
|
+
b = -1;
|
|
129
|
+
scalar = (f & 1 /* RunFlag.SCALAR */) !== 0;
|
|
130
|
+
}
|
|
105
131
|
if (b < 0 ||
|
|
106
132
|
(probed &&
|
|
107
133
|
(per[q + 3 /* Per.LANE_PROBE */] > from ||
|
|
@@ -113,7 +139,7 @@ export function runMotion(lanes, lane, run) {
|
|
|
113
139
|
continue;
|
|
114
140
|
}
|
|
115
141
|
const runs = run.runs;
|
|
116
|
-
if (own && folds &&
|
|
142
|
+
if (own && folds && scalar === ch.scalar) {
|
|
117
143
|
if (data[o + 5 /* Row.SAMPLED */] !== -2 /* Sampled.BARE */) {
|
|
118
144
|
data[o + 5 /* Row.SAMPLED */] = -2 /* Sampled.BARE */;
|
|
119
145
|
lane.deltas[p] = null;
|
|
@@ -147,7 +173,7 @@ export function runMotion(lanes, lane, run) {
|
|
|
147
173
|
data[o + 6 /* Row.SEEKS */] = seeks;
|
|
148
174
|
if (w <= 0)
|
|
149
175
|
continue;
|
|
150
|
-
if (folds &&
|
|
176
|
+
if (folds && scalar === ch.scalar) {
|
|
151
177
|
const values = ch.values;
|
|
152
178
|
const base = slot * n;
|
|
153
179
|
for (let a = 0; a < n; a++)
|
package/dist/seek.js
CHANGED
|
@@ -9,6 +9,7 @@ import { move, nextFrame } from './move.js';
|
|
|
9
9
|
import { ownerReading } from './owner.js';
|
|
10
10
|
import { place } from './place.js';
|
|
11
11
|
import { unpull } from './pull.js';
|
|
12
|
+
import { isRested } from './record.js';
|
|
12
13
|
import { Restored } from './restored.js';
|
|
13
14
|
import { recount } from './roster.js';
|
|
14
15
|
import { refitAll } from './spans.js';
|
|
@@ -33,8 +34,7 @@ function restore(mix, voice, live, at, every, mine) {
|
|
|
33
34
|
const h = mine && live.reaches ? unread(live) : copyHeld(voice, live);
|
|
34
35
|
if (h.stepped > t)
|
|
35
36
|
h.stepped = t;
|
|
36
|
-
|
|
37
|
-
h.rested = false;
|
|
37
|
+
restedBy(h, live, t);
|
|
38
38
|
h.weight = 0;
|
|
39
39
|
h.inputs = inputs;
|
|
40
40
|
if (!(h.since <= t))
|
|
@@ -63,6 +63,7 @@ function restore(mix, voice, live, at, every, mine) {
|
|
|
63
63
|
else
|
|
64
64
|
h = copyHeld(voice, snap.held, true);
|
|
65
65
|
h.weight = 0;
|
|
66
|
+
restedBy(h, live, t);
|
|
66
67
|
if (snap.at < t)
|
|
67
68
|
h.copied = true;
|
|
68
69
|
const kept = i + 1;
|
|
@@ -108,6 +109,13 @@ function restore(mix, voice, live, at, every, mine) {
|
|
|
108
109
|
}
|
|
109
110
|
return h;
|
|
110
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Whether a record put back for mix time `t` had rested by then, from when the live one did: a
|
|
114
|
+
* subject may have rested and moved on since, so a probe at `t` would not find it at rest again.
|
|
115
|
+
*/
|
|
116
|
+
function restedBy(h, live, t) {
|
|
117
|
+
h.restedAt = live.restedAt <= t ? live.restedAt : Number.NaN;
|
|
118
|
+
}
|
|
111
119
|
/** Cuts a record's list of copies to its first `kept`, keeping those no other list holds as spares. */
|
|
112
120
|
function trim(voice, snaps, kept) {
|
|
113
121
|
while (snaps.length > kept) {
|
|
@@ -188,7 +196,7 @@ function restoreVoice(mix, voice, t, seq) {
|
|
|
188
196
|
return h;
|
|
189
197
|
if (h.reaches)
|
|
190
198
|
voice.seen++;
|
|
191
|
-
if (h
|
|
199
|
+
if (isRested(h))
|
|
192
200
|
voice.restedCount++;
|
|
193
201
|
if (!(h.since <= restored.top)) {
|
|
194
202
|
voice.early ??= [];
|
|
@@ -350,7 +358,7 @@ function back(mix, t, seq, on) {
|
|
|
350
358
|
if (voice.parts !== null || voice.parted !== null)
|
|
351
359
|
mix.parters.add(voice);
|
|
352
360
|
mix.relinks++;
|
|
353
|
-
mix.
|
|
361
|
+
mix.lastPoses = new Store();
|
|
354
362
|
if (mix.restStamps !== null)
|
|
355
363
|
mix.restStamps = new Store();
|
|
356
364
|
unpull(mix);
|
|
@@ -393,7 +401,7 @@ function back(mix, t, seq, on) {
|
|
|
393
401
|
mix.pins.set(voice, voice.pinned);
|
|
394
402
|
}
|
|
395
403
|
refitAll(mix);
|
|
396
|
-
mix.due
|
|
404
|
+
mix.due.clear();
|
|
397
405
|
for (const voice of kept)
|
|
398
406
|
schedule(mix, voice);
|
|
399
407
|
mix.stir();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Setting } from './types.js';
|
|
2
|
+
import type { Voice } from './voice.js';
|
|
3
|
+
/**
|
|
4
|
+
* A voice's `setting.keep`, one per voice: a setting is valid only during its call, so the state
|
|
5
|
+
* goes on the record of the subject being called for, `keepOn`, or on the voice before any is.
|
|
6
|
+
*/
|
|
7
|
+
export declare function keeping<I, O>(voice: Voice<I, O>): Setting['keep'];
|
|
8
|
+
/**
|
|
9
|
+
* A voice's setting. `keep` is made on first read: most patches keep no state, and a closure and
|
|
10
|
+
* its context per voice cost a one-subject tween voice about 100 bytes.
|
|
11
|
+
*/
|
|
12
|
+
export declare class VoiceSetting<I, O> implements Setting<unknown> {
|
|
13
|
+
host: unknown;
|
|
14
|
+
readonly send: (event: unknown) => void;
|
|
15
|
+
private readonly voice;
|
|
16
|
+
timestamp: number;
|
|
17
|
+
dt: number;
|
|
18
|
+
elapsed: number;
|
|
19
|
+
pass: number;
|
|
20
|
+
weight: number;
|
|
21
|
+
state: unknown;
|
|
22
|
+
/** The `Arg.MARK` a lane last filled `timestamp`, `elapsed` and `pass` under; 0 once anything else writes them. */
|
|
23
|
+
mark: number;
|
|
24
|
+
private kept;
|
|
25
|
+
constructor(host: unknown, send: (event: unknown) => void, voice: Voice<I, O>);
|
|
26
|
+
get keep(): Setting['keep'];
|
|
27
|
+
}
|
package/dist/setting.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { reading } from './reading.js';
|
|
2
|
+
/**
|
|
3
|
+
* A voice's `setting.keep`, one per voice: a setting is valid only during its call, so the state
|
|
4
|
+
* goes on the record of the subject being called for, `keepOn`, or on the voice before any is.
|
|
5
|
+
*/
|
|
6
|
+
export function keeping(voice) {
|
|
7
|
+
return function keep(owner, init) {
|
|
8
|
+
const held = voice.keepOn;
|
|
9
|
+
let kept = held === null ? voice.ownKept : held.kept;
|
|
10
|
+
if (kept === null) {
|
|
11
|
+
kept = new Map();
|
|
12
|
+
if (held === null)
|
|
13
|
+
voice.ownKept = kept;
|
|
14
|
+
else
|
|
15
|
+
held.kept = kept;
|
|
16
|
+
}
|
|
17
|
+
if (kept.has(owner))
|
|
18
|
+
return kept.get(owner);
|
|
19
|
+
const unkept = held?.unkept;
|
|
20
|
+
const made = unkept === undefined ? init() : unkept.shift();
|
|
21
|
+
if (unkept?.length === 0 && held !== null)
|
|
22
|
+
held.unkept = undefined;
|
|
23
|
+
kept.set(owner, made);
|
|
24
|
+
reading.kept++;
|
|
25
|
+
return made;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A voice's setting. `keep` is made on first read: most patches keep no state, and a closure and
|
|
30
|
+
* its context per voice cost a one-subject tween voice about 100 bytes.
|
|
31
|
+
*/
|
|
32
|
+
export class VoiceSetting {
|
|
33
|
+
host;
|
|
34
|
+
send;
|
|
35
|
+
voice;
|
|
36
|
+
timestamp = 0;
|
|
37
|
+
dt = 0;
|
|
38
|
+
elapsed = 0;
|
|
39
|
+
pass = 0;
|
|
40
|
+
weight = 0;
|
|
41
|
+
state = undefined;
|
|
42
|
+
/** The `Arg.MARK` a lane last filled `timestamp`, `elapsed` and `pass` under; 0 once anything else writes them. */
|
|
43
|
+
mark = 0;
|
|
44
|
+
kept = null;
|
|
45
|
+
constructor(host, send, voice) {
|
|
46
|
+
this.host = host;
|
|
47
|
+
this.send = send;
|
|
48
|
+
this.voice = voice;
|
|
49
|
+
}
|
|
50
|
+
get keep() {
|
|
51
|
+
if (this.kept === null)
|
|
52
|
+
this.kept = keeping(this.voice);
|
|
53
|
+
return this.kept;
|
|
54
|
+
}
|
|
55
|
+
}
|
package/dist/shared.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The package version, for a fact whose shape follows the code too closely to version by hand:
|
|
3
3
|
* copies of different releases keep apart. `test/copies.test.ts` holds it to `package.json`.
|
|
4
4
|
*/
|
|
5
|
-
export declare const release = "0.
|
|
5
|
+
export declare const release = "0.15.0";
|
|
6
6
|
/**
|
|
7
7
|
* A WeakMap every copy of blits loaded in one realm shares, so a fact one copy records about a
|
|
8
8
|
* patch or channel it made is read by another copy's mix. The name carries a version, bumped when
|
package/dist/shared.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The package version, for a fact whose shape follows the code too closely to version by hand:
|
|
3
3
|
* copies of different releases keep apart. `test/copies.test.ts` holds it to `package.json`.
|
|
4
4
|
*/
|
|
5
|
-
export const release = '0.
|
|
5
|
+
export const release = '0.15.0';
|
|
6
6
|
/**
|
|
7
7
|
* A WeakMap every copy of blits loaded in one realm shares, so a fact one copy records about a
|
|
8
8
|
* patch or channel it made is read by another copy's mix. The name carries a version, bumped when
|
package/dist/signals.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Setting, Signal } from './types.js';
|
|
1
|
+
import type { Band, Setting, Signal } from './types.js';
|
|
2
2
|
/** Whether a change to an input signal reaches `reading.inputs`, so a lane fill can see it. */
|
|
3
3
|
export declare const heard: (signal: object) => boolean;
|
|
4
4
|
/**
|
|
@@ -10,15 +10,24 @@ export declare function peak<I, H = unknown>(...signals: readonly Signal<I, H>[]
|
|
|
10
10
|
/** A blend member's share of its signal's read `k`: the members' stops sit evenly along 0..1. */
|
|
11
11
|
export declare function shareOf(k: number, i: number, stops: number): number;
|
|
12
12
|
/**
|
|
13
|
-
* Member `i` of `n`'s share of `by`, as `mix.blend` weighs it
|
|
14
|
-
* member's stop, the stops spaced evenly from 0 to 1. Weights a voice outside a blend as one of
|
|
15
|
-
*
|
|
13
|
+
* Member `i` of `n`'s share of `by`, as `mix.blend` weighs it. It is the hat of `by`'s read at the
|
|
14
|
+
* member's stop, the stops spaced evenly from 0 to 1. Weights a voice outside a blend as one of its
|
|
15
|
+
* members, such as one member played alone.
|
|
16
16
|
*
|
|
17
17
|
* @category signal
|
|
18
18
|
*/
|
|
19
19
|
export declare function share<I, H = unknown>(by: Signal<I, H>, i: number, n: number): Signal<I, H>;
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* The signal `input` returns, with `touch` to report a change.
|
|
22
|
+
*
|
|
23
|
+
* @category signal
|
|
24
|
+
*/
|
|
25
|
+
export interface Input<I, H = unknown> extends Signal<I, H> {
|
|
26
|
+
/** Reports a change to what the signal reads. */
|
|
27
|
+
touch(): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Marks `read` as a signal driven from outside the clock. A host's own signal has to be one for
|
|
22
31
|
* `assess` and a history's `inputs` to treat it as one. Two uses:
|
|
23
32
|
*
|
|
24
33
|
* `input(read)` is an input of the host's own: a pointer, a volume, a value in a store. The host
|
|
@@ -32,54 +41,77 @@ export declare function share<I, H = unknown>(by: Signal<I, H>, i: number, n: nu
|
|
|
32
41
|
*
|
|
33
42
|
* @category signal
|
|
34
43
|
*/
|
|
35
|
-
export declare function input<I, H = unknown>(read: (subject: I, setting: Setting<void, H>) => number, of?: readonly Signal<I, H>[]):
|
|
36
|
-
touch(): void;
|
|
37
|
-
};
|
|
44
|
+
export declare function input<I, H = unknown>(read: (subject: I, setting: Setting<void, H>) => number, of?: readonly Signal<I, H>[]): Input<I, H>;
|
|
38
45
|
/**
|
|
39
|
-
*
|
|
40
|
-
* `level`.
|
|
46
|
+
* The signal `level` returns, with `set` to write it.
|
|
41
47
|
*
|
|
42
48
|
* @category signal
|
|
43
49
|
*/
|
|
44
|
-
export
|
|
50
|
+
export interface Level<I, H = unknown> extends Signal<I, H> {
|
|
51
|
+
/** Writes the level, reporting the change; writing the value it holds already does nothing. */
|
|
45
52
|
set(v: number): void;
|
|
46
|
-
}
|
|
53
|
+
}
|
|
47
54
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
55
|
+
* A signal the host writes. It is `input` over one number, with `set` reporting each change.
|
|
56
|
+
* klieg's `level`.
|
|
57
|
+
*
|
|
58
|
+
* @category signal
|
|
59
|
+
*/
|
|
60
|
+
export declare function level<I, H = unknown>(initial?: number): Level<I, H>;
|
|
61
|
+
/**
|
|
62
|
+
* What `slew` takes.
|
|
52
63
|
*
|
|
53
64
|
* @category signal
|
|
54
65
|
*/
|
|
55
|
-
export
|
|
66
|
+
export interface SlewOptions {
|
|
67
|
+
/** Ms per unit climbing; 0 follows at once. Default 0. */
|
|
56
68
|
riseMs?: number;
|
|
69
|
+
/** Ms per unit draining; 0 follows at once. Default 0. */
|
|
57
70
|
fallMs?: number;
|
|
71
|
+
/** Where a subject starts, unless `dt` is infinite. Default: on its input. */
|
|
58
72
|
from?: number;
|
|
59
|
-
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Follows its input at a rate limit, the package's linear decay primitive. No faster than `riseMs`
|
|
76
|
+
* per unit climbing or `fallMs` draining. The mix keeps its state per voice and subject, so two
|
|
77
|
+
* voices handed the same slew each follow on their own. A subject starts on its input, or at `from`
|
|
78
|
+
* unless `dt` is infinite.
|
|
79
|
+
*
|
|
80
|
+
* @category signal
|
|
81
|
+
*/
|
|
82
|
+
export declare function slew<I, H = unknown>(of: Signal<I, H>, { riseMs, fallMs, from }: SlewOptions): Signal<I, H>;
|
|
60
83
|
/**
|
|
61
|
-
*
|
|
62
|
-
* every equal stretch of time, `1 − exp(−gap / ms)`, so it reads the same however the frames that
|
|
63
|
-
* sample it are spaced while the input holds still. `riseMs` and `fallMs` are time constants: after
|
|
64
|
-
* one, 63% of the way is covered. 0 follows at once. Within `floor` of its input it lands on it, so a
|
|
65
|
-
* subject can reach rest; pass 0 to keep the curve exact. The mix keeps its state per voice and subject.
|
|
66
|
-
* A subject starts on its input, or at `from` unless `dt` is infinite.
|
|
84
|
+
* What `lag` takes.
|
|
67
85
|
*
|
|
68
86
|
* @category signal
|
|
69
87
|
*/
|
|
70
|
-
export
|
|
88
|
+
export interface LagOptions {
|
|
89
|
+
/** The time constant climbing, ms; 0 follows at once. Default 0. */
|
|
71
90
|
riseMs?: number;
|
|
91
|
+
/** The time constant draining, ms; 0 follows at once. Default 0. */
|
|
72
92
|
fallMs?: number;
|
|
93
|
+
/** Within this of its input it lands on it; 0 keeps the curve exact. Default 1e-6. */
|
|
73
94
|
floor?: number;
|
|
95
|
+
/** Where a subject starts, unless `dt` is infinite. Default: on its input. */
|
|
74
96
|
from?: number;
|
|
75
|
-
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Closes the same fraction of the distance to its input in every equal stretch of time. The
|
|
100
|
+
* exponential counterpart to `slew`: the fraction is `1 − exp(−gap / ms)`, so it reads the same
|
|
101
|
+
* however the frames that sample it are spaced while the input holds still. `riseMs` and `fallMs`
|
|
102
|
+
* are time constants: after one, 63% of the way is covered. 0 follows at once. Within `floor` of
|
|
103
|
+
* its input it lands on it, so a subject can reach rest; pass 0 to keep the curve exact. The mix
|
|
104
|
+
* keeps its state per voice and subject. A subject starts on its input, or at `from` unless `dt` is
|
|
105
|
+
* infinite.
|
|
106
|
+
*
|
|
107
|
+
* @category signal
|
|
108
|
+
*/
|
|
109
|
+
export declare function lag<I, H = unknown>(of: Signal<I, H>, { riseMs, fallMs, floor, from }: LagOptions): Signal<I, H>;
|
|
76
110
|
/**
|
|
77
|
-
*
|
|
78
|
-
* the two it holds whatever it last did, so an input resting on
|
|
111
|
+
* Passes or drops its input across a band, not an edge. The other half of the pair. It drops at
|
|
112
|
+
* `off`, passes at `on`, and between the two it holds whatever it last did, so an input resting on
|
|
113
|
+
* a threshold cannot chatter.
|
|
79
114
|
*
|
|
80
115
|
* @category signal
|
|
81
116
|
*/
|
|
82
|
-
export declare function gate<I, H = unknown>(of: Signal<I, H>, band:
|
|
83
|
-
on: number;
|
|
84
|
-
off: number;
|
|
85
|
-
} | number): Signal<I, H>;
|
|
117
|
+
export declare function gate<I, H = unknown>(of: Signal<I, H>, band: Band | number): Signal<I, H>;
|