@msb235/blits 0.15.1 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +184 -0
- package/README.md +1 -1
- package/dist/ahead.js +11 -13
- package/dist/chain.js +2 -3
- package/dist/clock.d.ts +11 -1
- package/dist/clock.js +28 -9
- package/dist/color.d.ts +36 -14
- package/dist/color.js +186 -58
- package/dist/columns.d.ts +1 -11
- package/dist/columns.js +1 -6
- package/dist/contribution.js +11 -4
- package/dist/crowd.d.ts +0 -6
- package/dist/crowd.js +0 -11
- package/dist/cue.js +19 -7
- package/dist/due.d.ts +18 -0
- package/dist/due.js +101 -2
- package/dist/everyone.d.ts +17 -6
- package/dist/everyone.js +17 -8
- package/dist/fade.d.ts +22 -1
- package/dist/fade.js +81 -12
- package/dist/fill.js +2 -1
- package/dist/fit.js +8 -0
- package/dist/fold.js +4 -7
- package/dist/gone.js +1 -0
- package/dist/handle.d.ts +1 -1
- package/dist/handle.js +3 -1
- package/dist/held.d.ts +2 -1
- package/dist/held.js +17 -10
- package/dist/hosts.d.ts +7 -0
- package/dist/hosts.js +23 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lane.d.ts +2 -0
- package/dist/lane.js +2 -0
- package/dist/lanes.d.ts +26 -1
- package/dist/lanes.js +9 -1
- package/dist/lch.d.ts +23 -0
- package/dist/lch.js +126 -0
- package/dist/meet.js +9 -0
- package/dist/mixer.d.ts +6 -1
- package/dist/mixer.js +5 -0
- package/dist/motion.js +6 -6
- package/dist/motions.d.ts +4 -1
- package/dist/motions.js +16 -2
- package/dist/move.js +311 -79
- package/dist/origin.d.ts +2 -0
- package/dist/origin.js +4 -0
- package/dist/owner.d.ts +7 -2
- package/dist/owner.js +17 -5
- package/dist/paging.d.ts +5 -1
- package/dist/paging.js +13 -3
- package/dist/patch.js +24 -4
- package/dist/place.js +67 -31
- package/dist/project.d.ts +5 -2
- package/dist/project.js +9 -11
- package/dist/pull.d.ts +11 -0
- package/dist/pull.js +10 -6
- package/dist/qualify.js +7 -2
- package/dist/rests.js +9 -1
- package/dist/revive.d.ts +11 -1
- package/dist/revive.js +7 -0
- package/dist/roles.js +6 -5
- package/dist/roster.d.ts +6 -0
- package/dist/roster.js +8 -1
- package/dist/rows.js +4 -1
- package/dist/sample.js +2 -1
- package/dist/seat.d.ts +5 -1
- package/dist/seat.js +5 -1
- package/dist/seek.js +6 -16
- package/dist/shared.d.ts +1 -1
- package/dist/shared.js +1 -1
- package/dist/spans.d.ts +13 -4
- package/dist/spans.js +125 -32
- package/dist/touch.js +1 -2
- package/dist/trace.js +7 -2
- package/dist/turns.js +2 -1
- package/dist/types/transport.d.ts +2 -1
- package/dist/types/voice.d.ts +3 -2
- package/dist/voice.d.ts +59 -2
- package/dist/voice.js +76 -2
- package/dist/weigh.js +1 -1
- package/docs/schema.html +38 -12
- package/package.json +3 -1
package/dist/place.js
CHANGED
|
@@ -56,39 +56,75 @@ export function checkPlacement(mix, spec, anchor, owner) {
|
|
|
56
56
|
throw new Error('blits: a placement anchors out or end, not both');
|
|
57
57
|
if (spec.start !== undefined && (anchor.start !== undefined || anchor.in !== undefined))
|
|
58
58
|
throw new Error('blits: a voice takes start or an anchored start, not both');
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
const self = {
|
|
60
|
+
id: mix.nextId,
|
|
61
|
+
spec,
|
|
62
|
+
owner,
|
|
63
|
+
slot: mix.slot,
|
|
64
|
+
writes: spec.patch?.writes ?? none,
|
|
65
|
+
};
|
|
66
|
+
const voices = [self];
|
|
67
|
+
for (const m of mix.transport.members)
|
|
68
|
+
for (const list of [m.gone, m.cued])
|
|
69
|
+
for (const v of list)
|
|
70
|
+
voices.push({
|
|
71
|
+
id: v.id,
|
|
72
|
+
spec: v.spec,
|
|
73
|
+
owner: v.owner,
|
|
74
|
+
slot: m.slot,
|
|
75
|
+
writes: v.patch.writes,
|
|
76
|
+
});
|
|
77
|
+
const refuse = () => {
|
|
78
|
+
throw new Error(`blits: ${spec.name ?? 'a voice'}'s placement waits on itself`);
|
|
79
|
+
};
|
|
80
|
+
// Where the marks a query asks for are fixed: a voice's start, in, coast and inner marks by its
|
|
81
|
+
// start's anchors, its out and end by its out's anchors and its start.
|
|
82
|
+
const targets = (asker, a) => {
|
|
66
83
|
if ('all' in a)
|
|
67
|
-
return a.all.flatMap((m) =>
|
|
84
|
+
return a.all.flatMap((m) => targets(asker, m));
|
|
68
85
|
if ('any' in a)
|
|
69
|
-
return a.any.flatMap((m) =>
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
86
|
+
return a.any.flatMap((m) => targets(asker, m));
|
|
87
|
+
const given = 'of' in a ? a.of : 'after' in a ? a.after : 'with' in a ? a.with : a.before;
|
|
88
|
+
const mark = 'of' in a ? a.mark : 'after' in a ? 'end' : 'start';
|
|
89
|
+
const q = typeof given === 'string' ? { name: given } : given;
|
|
90
|
+
const score = q.score ?? asker.spec.score;
|
|
91
|
+
const anywhere = q.score !== undefined;
|
|
92
|
+
if (asker === self && q.name !== undefined && q.name === spec.name && score === spec.score)
|
|
93
|
+
refuse();
|
|
94
|
+
const met = voices.filter((v) => v !== asker &&
|
|
95
|
+
v.spec.score === score &&
|
|
96
|
+
(anywhere || (v.owner === asker.owner && v.slot === asker.slot)) &&
|
|
97
|
+
(q.name === undefined || v.spec.name === q.name) &&
|
|
98
|
+
(q.tag === undefined || (v.spec.tags ?? none).includes(q.tag)) &&
|
|
99
|
+
(q.writes === undefined || v.writes.includes(q.writes)));
|
|
100
|
+
const resolver = q.resolver ?? 'last';
|
|
101
|
+
const picked = met.length > 1 && (resolver === 'first' || resolver === 'last')
|
|
102
|
+
? [met.reduce((p, v) => ((resolver === 'last' ? v.id > p.id : v.id < p.id) ? v : p))]
|
|
103
|
+
: met;
|
|
104
|
+
const side = mark === 'out' || mark === 'end' ? 'out' : 'start';
|
|
105
|
+
return picked.map((v) => ({ voice: v, side }));
|
|
74
106
|
};
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
seen
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
107
|
+
const waitsOf = (p, side) => {
|
|
108
|
+
const a = p.spec.anchor;
|
|
109
|
+
const by = side === 'start' ? [a?.start, a?.in] : [a?.out, a?.end];
|
|
110
|
+
const out = side === 'out' ? [{ voice: p, side: 'start' }] : [];
|
|
111
|
+
for (const b of by)
|
|
112
|
+
if (b !== undefined && typeof b !== 'number')
|
|
113
|
+
out.push(...targets(p, b));
|
|
114
|
+
return out;
|
|
115
|
+
};
|
|
116
|
+
for (const from of ['start', 'out']) {
|
|
117
|
+
const seen = { start: new Set(), out: new Set() };
|
|
118
|
+
const stack = waitsOf(self, from);
|
|
119
|
+
while (stack.length > 0) {
|
|
120
|
+
const { voice, side } = stack.pop();
|
|
121
|
+
if (voice === self && side === from)
|
|
122
|
+
refuse();
|
|
123
|
+
if (seen[side].has(voice))
|
|
124
|
+
continue;
|
|
125
|
+
seen[side].add(voice);
|
|
126
|
+
stack.push(...waitsOf(voice, side));
|
|
127
|
+
}
|
|
92
128
|
}
|
|
93
129
|
}
|
|
94
130
|
/**
|
|
@@ -158,7 +194,7 @@ export function place(mix) {
|
|
|
158
194
|
export function resolve(mix, a, self, before) {
|
|
159
195
|
const o = self.owner;
|
|
160
196
|
if (typeof a === 'number')
|
|
161
|
-
return o === null ? mixAt(mix, a -
|
|
197
|
+
return o === null ? mixAt(mix, a - self.offset) : a;
|
|
162
198
|
if ('all' in a) {
|
|
163
199
|
let latest = Number.NEGATIVE_INFINITY;
|
|
164
200
|
for (const m of a.all) {
|
package/dist/project.d.ts
CHANGED
|
@@ -12,8 +12,11 @@ import type { Voice } from './voice.js';
|
|
|
12
12
|
export declare function projectAll(transport: Transport, at: number | {
|
|
13
13
|
readonly frame: number;
|
|
14
14
|
}): TransportProjection;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Sets each copied voice's state to what its clock and fade make it at `t`; with `cut`, the frames
|
|
17
|
+
* up to which history says which had started.
|
|
18
|
+
*/
|
|
19
|
+
export declare function stateAt<I, O>(c: Mixer<I, O>, t: number, cut?: Cut): void;
|
|
17
20
|
/**
|
|
18
21
|
* A projection back starts each subject from the latest copy kept at or before `t`, else from its
|
|
19
22
|
* voice's start with fresh state, which is exact for a voice stepped at a fixed interval.
|
package/dist/project.js
CHANGED
|
@@ -7,7 +7,7 @@ import { fadesAt } from './fade.js';
|
|
|
7
7
|
import { meet, origin } from './held.js';
|
|
8
8
|
import { copyHeld, last, lastWithin } from './history.js';
|
|
9
9
|
import { Mixer } from './mixer.js';
|
|
10
|
-
import { heldByInput,
|
|
10
|
+
import { heldByInput, relink } from './owner.js';
|
|
11
11
|
import { reading } from './reading.js';
|
|
12
12
|
import { record } from './record.js';
|
|
13
13
|
import { recount } from './roster.js';
|
|
@@ -72,6 +72,7 @@ export function projectAll(transport, at) {
|
|
|
72
72
|
}, null);
|
|
73
73
|
copy.slot = mix.slot;
|
|
74
74
|
copy.projecting = true;
|
|
75
|
+
copy.share = mix.share;
|
|
75
76
|
copy.places = mix.places;
|
|
76
77
|
copies.set(mix, copy);
|
|
77
78
|
if (ahead)
|
|
@@ -177,19 +178,16 @@ function copyBack(mix, c, t, cut) {
|
|
|
177
178
|
ownBlends(c.cued);
|
|
178
179
|
if (mix.owners !== null)
|
|
179
180
|
relink(c.cued, cut.seq);
|
|
180
|
-
stateAt(c, t);
|
|
181
|
+
stateAt(c, t, cut);
|
|
181
182
|
recount(c);
|
|
182
183
|
}
|
|
183
|
-
/**
|
|
184
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Sets each copied voice's state to what its clock and fade make it at `t`; with `cut`, the frames
|
|
186
|
+
* up to which history says which had started.
|
|
187
|
+
*/
|
|
188
|
+
export function stateAt(c, t, cut) {
|
|
185
189
|
for (const copy of c.cued)
|
|
186
|
-
copy.state = copy.
|
|
187
|
-
? 'fading'
|
|
188
|
-
: (copy.owner === null ? t : ownerReading(copy.owner, t)) < copy.start
|
|
189
|
-
? 'pending'
|
|
190
|
-
: copy.freezesAfter && copy.elapsedAt(t) >= copy.span + copy.latest
|
|
191
|
-
? 'frozen'
|
|
192
|
-
: 'live';
|
|
190
|
+
copy.state = copy.stateAt(t, cut);
|
|
193
191
|
}
|
|
194
192
|
/**
|
|
195
193
|
* A projection back starts each subject from the latest copy kept at or before `t`, else from its
|
package/dist/pull.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { Mixer } from './mixer.js';
|
|
2
2
|
import type { Columns } from './types.js';
|
|
3
|
+
/** One channel `pull` writes: where in the kit, how many numbers a subject, and its rest. */
|
|
4
|
+
export interface Column {
|
|
5
|
+
key: string;
|
|
6
|
+
slot: number;
|
|
7
|
+
axes: number;
|
|
8
|
+
out: Float64Array;
|
|
9
|
+
/** The rest, clamped, or NaN for a channel with none. */
|
|
10
|
+
rest: Float64Array;
|
|
11
|
+
bounds: readonly [number, number] | undefined;
|
|
12
|
+
}
|
|
13
|
+
export declare function clampRun(out: Float64Array, at: number, n: number, [lo, hi]: readonly [number, number]): void;
|
|
3
14
|
/** After a probe, keeps the pose a retarget from `'current'` reads as the subject's last. */
|
|
4
15
|
export declare function keep<I, O>(this: Mixer<I, O>, subject: I, pose: O, out: O | undefined): void;
|
|
5
16
|
export declare function pull<I, O>(mix: Mixer<I, O>, subjects: Iterable<I>, into: Columns<O>): void;
|
package/dist/pull.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { axesOf } from './channels.js';
|
|
2
2
|
import { copy } from './clone.js';
|
|
3
|
-
import { clampRun, flush, pullRun, writeLater } from './columns.js';
|
|
4
|
-
import { renumber } from './renumber.js';
|
|
5
3
|
/** What `pull` remembers at a position it has read no subject at. */
|
|
6
4
|
const UNREAD = Symbol('unread');
|
|
5
|
+
export function clampRun(out, at, n, [lo, hi]) {
|
|
6
|
+
for (let i = at; i < at + n; i++) {
|
|
7
|
+
const x = out[i];
|
|
8
|
+
out[i] = x < lo ? lo : x > hi ? hi : x;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
7
11
|
/** Writes a folded pose's value into subject `n`'s places in a column. */
|
|
8
12
|
function writeValue(c, v, n) {
|
|
9
13
|
const at = n * c.axes;
|
|
@@ -112,7 +116,7 @@ export function pull(mix, subjects, into) {
|
|
|
112
116
|
}
|
|
113
117
|
finally {
|
|
114
118
|
if (lanes !== null)
|
|
115
|
-
flush(lanes);
|
|
119
|
+
lanes.pulls.flush(lanes);
|
|
116
120
|
}
|
|
117
121
|
// Every head is current only if nothing relinked or changed version while they were read.
|
|
118
122
|
const unchanged = live && mix.version === version && mix.relinks === relinks;
|
|
@@ -136,7 +140,7 @@ function readAll(mix, list, columns, live, current, since, whole) {
|
|
|
136
140
|
const runs = live && whole;
|
|
137
141
|
for (let n = 0; n < list.length; n++) {
|
|
138
142
|
if (runs) {
|
|
139
|
-
n = pullRun(lanes, slots, list, was, since, n, columns, now, mix.version);
|
|
143
|
+
n = lanes.pulls.pullRun(lanes, slots, list, was, since, n, columns, now, mix.version);
|
|
140
144
|
if (n === list.length)
|
|
141
145
|
break;
|
|
142
146
|
}
|
|
@@ -156,7 +160,7 @@ function readAll(mix, list, columns, live, current, since, whole) {
|
|
|
156
160
|
// Numbered out of the list's order, as swap-remove leaves a subject: renumbered into it.
|
|
157
161
|
const to = n === 0 ? 0 : slots[n - 1] + 1;
|
|
158
162
|
if (runs && slot >= 0 && slot !== to && to >= 0) {
|
|
159
|
-
if (renumber(mix, subject, head, to)) {
|
|
163
|
+
if (lanes.pulls.renumber(mix, subject, head, to)) {
|
|
160
164
|
for (let j = was.indexOf(subject); j >= 0; j = was.indexOf(subject, j + 1))
|
|
161
165
|
slots[j] = to;
|
|
162
166
|
slot = to;
|
|
@@ -167,7 +171,7 @@ function readAll(mix, list, columns, live, current, since, whole) {
|
|
|
167
171
|
}
|
|
168
172
|
const laned = live && lanes?.prepare(slot, subject, mix.version, heads[n] ?? null) === true;
|
|
169
173
|
if (laned && whole && lanes.whole && !lanes.owes(slot)) {
|
|
170
|
-
writeLater(lanes, slot, columns, n, slots);
|
|
174
|
+
lanes.pulls.writeLater(lanes, slot, columns, n, slots);
|
|
171
175
|
continue;
|
|
172
176
|
}
|
|
173
177
|
const head = live ? heads[n] : null;
|
package/dist/qualify.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { numericOf } from './channels.js';
|
|
2
2
|
import { flush } from './columns.js';
|
|
3
|
-
import { crowdable } from './crowd.js';
|
|
4
3
|
import { byId } from './due.js';
|
|
5
4
|
import { weighAt } from './everyone.js';
|
|
6
5
|
import { wake } from './fill.js';
|
|
6
|
+
import { crowdable } from './hosts.js';
|
|
7
7
|
import { Lane } from './lane.js';
|
|
8
8
|
import { reach } from './meet.js';
|
|
9
9
|
import { bury, compactSparse, join, regroup, retouchRow, sameCrowds } from './rows.js';
|
|
@@ -96,7 +96,11 @@ export function requalify(lanes, version) {
|
|
|
96
96
|
crowded++;
|
|
97
97
|
continue;
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
let lane = lanes.byId.get(v.id);
|
|
100
|
+
if (lane === undefined) {
|
|
101
|
+
lane = new Lane(v);
|
|
102
|
+
lane.made = lanes.probes;
|
|
103
|
+
}
|
|
100
104
|
v.laned = true;
|
|
101
105
|
if (lane.epoch === 0 && v.state !== 'pending')
|
|
102
106
|
opened(lanes, lane);
|
|
@@ -395,6 +399,7 @@ function placeAll(lanes, lane) {
|
|
|
395
399
|
*/
|
|
396
400
|
function enlane(lanes, v) {
|
|
397
401
|
const lane = new Lane(v);
|
|
402
|
+
lane.made = lanes.probes;
|
|
398
403
|
v.laned = true;
|
|
399
404
|
if (v.state !== 'pending')
|
|
400
405
|
opened(lanes, lane);
|
package/dist/rests.js
CHANGED
|
@@ -56,7 +56,15 @@ export function still(voice, now) {
|
|
|
56
56
|
if (voice.state === 'frozen' || voice.holding !== null)
|
|
57
57
|
return true;
|
|
58
58
|
const motion = voice.motion;
|
|
59
|
-
|
|
59
|
+
if (motion === undefined || !(voice.elapsedAt(now) >= voice.latest))
|
|
60
|
+
return false;
|
|
61
|
+
// A subject met inside its stagger and not read since has no run yet, and moves once it is.
|
|
62
|
+
const early = voice.early;
|
|
63
|
+
if (early !== null)
|
|
64
|
+
for (const h of early)
|
|
65
|
+
if (h.since <= now && !(h.probed >= h.since))
|
|
66
|
+
return false;
|
|
67
|
+
return motion.landed();
|
|
60
68
|
}
|
|
61
69
|
export function restsLaned() {
|
|
62
70
|
return this.lanes.whole && this.bounded.length === 0;
|
package/dist/revive.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { type Key } from './paging.js';
|
|
|
5
5
|
import type { Run } from './stretch.js';
|
|
6
6
|
import type { Parted, Parting } from './subject.js';
|
|
7
7
|
import type { Described } from './types.js';
|
|
8
|
-
import { type Controls, type Ramp, type Rise, Voice } from './voice.js';
|
|
8
|
+
import { type Controls, type Earlier, type Ramp, type Rise, Voice } from './voice.js';
|
|
9
9
|
/** A voice that has left, as plain data: the descriptor it was cued with, its controls and its records. */
|
|
10
10
|
interface PackedVoice {
|
|
11
11
|
as: Described;
|
|
@@ -21,6 +21,8 @@ interface PackedVoice {
|
|
|
21
21
|
weight: number;
|
|
22
22
|
out: Ramp | null;
|
|
23
23
|
back: Rise | null;
|
|
24
|
+
/** Absent from a store written before a voice kept them. */
|
|
25
|
+
stalls?: readonly number[] | null;
|
|
24
26
|
outAt: number;
|
|
25
27
|
outOver: number;
|
|
26
28
|
outSet: boolean;
|
|
@@ -28,12 +30,20 @@ interface PackedVoice {
|
|
|
28
30
|
hold: number;
|
|
29
31
|
past: number;
|
|
30
32
|
clocks: Past[] | null;
|
|
33
|
+
/** Absent from a store written before a voice kept it. */
|
|
34
|
+
earlier?: Earlier | null;
|
|
35
|
+
/** Absent from a store written before a voice kept it. */
|
|
36
|
+
later?: Earlier | null;
|
|
31
37
|
cuedAt: number;
|
|
32
38
|
cuedSeq: number;
|
|
39
|
+
/** Absent from a store written before a voice kept it. */
|
|
40
|
+
begunSeq?: number;
|
|
33
41
|
doneAt: number;
|
|
34
42
|
doneSeq: number;
|
|
35
43
|
opened: number;
|
|
36
44
|
pinned: number;
|
|
45
|
+
/** Absent from a store written before a voice kept it. */
|
|
46
|
+
offset?: number;
|
|
37
47
|
latest: number;
|
|
38
48
|
/** Absent from a store written before a voice kept it. */
|
|
39
49
|
soonest?: number;
|
package/dist/revive.js
CHANGED
|
@@ -79,19 +79,24 @@ function packVoice(voice, keys) {
|
|
|
79
79
|
weight: voice.weight,
|
|
80
80
|
out: voice.out,
|
|
81
81
|
back: voice.back,
|
|
82
|
+
stalls: voice.stalls,
|
|
82
83
|
outAt: voice.outAt,
|
|
83
84
|
outOver: voice.outOver,
|
|
84
85
|
outSet: voice.outSet,
|
|
85
86
|
rebuilds: voice.rebuilds,
|
|
86
87
|
hold: voice.hold,
|
|
87
88
|
past: voice.clocks?.length ?? 0,
|
|
89
|
+
earlier: voice.earlier,
|
|
90
|
+
later: voice.later,
|
|
88
91
|
clocks: voice.clocks,
|
|
89
92
|
cuedAt: voice.cuedAt,
|
|
90
93
|
cuedSeq: voice.cuedSeq,
|
|
94
|
+
begunSeq: voice.begunSeq,
|
|
91
95
|
doneAt: voice.doneAt,
|
|
92
96
|
doneSeq: voice.doneSeq,
|
|
93
97
|
opened: voice.opened,
|
|
94
98
|
pinned: voice.pinned,
|
|
99
|
+
offset: voice.offset,
|
|
95
100
|
latest: voice.latest,
|
|
96
101
|
soonest: voice.soonest,
|
|
97
102
|
keeping: voice.keeping,
|
|
@@ -127,10 +132,12 @@ export function reviveVoice(mix, id, d) {
|
|
|
127
132
|
voice.take(d);
|
|
128
133
|
voice.cuedAt = d.cuedAt;
|
|
129
134
|
voice.cuedSeq = d.cuedSeq;
|
|
135
|
+
voice.begunSeq = d.begunSeq ?? Number.POSITIVE_INFINITY;
|
|
130
136
|
voice.doneAt = d.doneAt;
|
|
131
137
|
voice.doneSeq = d.doneSeq;
|
|
132
138
|
voice.opened = d.opened;
|
|
133
139
|
voice.pinned = d.pinned;
|
|
140
|
+
voice.offset = d.offset ?? 0;
|
|
134
141
|
voice.latest = d.latest;
|
|
135
142
|
voice.soonest = d.soonest ?? 0;
|
|
136
143
|
voice.keeping = d.keeping;
|
package/dist/roles.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { first } from './clone.js';
|
|
2
|
-
import { open as openRecord } from './everyone.js';
|
|
3
2
|
import { merged, unband } from './fold.js';
|
|
4
3
|
import { roleScratch } from './role.js';
|
|
5
4
|
// V8 reads a local const as a constant, where it reads an import from its module on every call.
|
|
6
|
-
const open = openRecord;
|
|
7
5
|
/**
|
|
8
6
|
* Whether a fold's next voice is its chain's next record, `held`, and not the next voice sharing
|
|
9
7
|
* one record, `sharers[q]`: the two lists are each in voice order, and a fold takes them as one.
|
|
@@ -54,15 +52,18 @@ export function foldRoles(subject, pose, head, laned, dry, except, owed) {
|
|
|
54
52
|
continue;
|
|
55
53
|
const held = rec;
|
|
56
54
|
if (!mine)
|
|
57
|
-
open(voice, held, head.slot);
|
|
55
|
+
this.share.open(voice, held, head.slot);
|
|
58
56
|
const delta = this.read(voice, subject, now, dry, held);
|
|
59
57
|
if (owed >= 0 && voice.laned)
|
|
60
58
|
this.lanes.paid(voice.id, owed, held.weight);
|
|
61
59
|
if (!mine)
|
|
62
60
|
q = this.shared(voice, head.slot, held, q);
|
|
63
|
-
if (delta === null)
|
|
64
|
-
continue;
|
|
65
61
|
const role = voice.spec.role;
|
|
62
|
+
if (delta === null) {
|
|
63
|
+
if (role === undefined && !(held.weight > 0))
|
|
64
|
+
unband(held);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
66
67
|
let group = -1;
|
|
67
68
|
if (role !== undefined) {
|
|
68
69
|
group = k.names.indexOf(role);
|
package/dist/roster.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { Mixer } from './mixer.js';
|
|
2
2
|
import type { Voice } from './voice.js';
|
|
3
|
+
/**
|
|
4
|
+
* Counts what makes a mix's fold more than a walk of each chain: a role, a voice sharing one
|
|
5
|
+
* record, a voice that stopped sharing this frame. Called wherever one of the three changes, so
|
|
6
|
+
* `foldWith` asks one number.
|
|
7
|
+
*/
|
|
8
|
+
export declare function detour<I, O>(mix: Mixer<I, O>): void;
|
|
3
9
|
/** Counts a voice just put in the list into everything a sync and a fold skip work by. */
|
|
4
10
|
export declare function enlist<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>): void;
|
|
5
11
|
/**
|
package/dist/roster.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { index, unindex } from './chain.js';
|
|
2
|
-
import { detour } from './everyone.js';
|
|
3
2
|
import { Store } from './store.js';
|
|
3
|
+
/**
|
|
4
|
+
* Counts what makes a mix's fold more than a walk of each chain: a role, a voice sharing one
|
|
5
|
+
* record, a voice that stopped sharing this frame. Called wherever one of the three changes, so
|
|
6
|
+
* `foldWith` asks one number.
|
|
7
|
+
*/
|
|
8
|
+
export function detour(mix) {
|
|
9
|
+
mix.detours = mix.roleVoices + mix.sharers.length + (mix.unshared ? 1 : 0);
|
|
10
|
+
}
|
|
4
11
|
function tally(mix, voice, by) {
|
|
5
12
|
if (voice.spec.role !== undefined)
|
|
6
13
|
mix.roleVoices += by;
|
package/dist/rows.js
CHANGED
|
@@ -106,7 +106,7 @@ export function join(lanes, v, from, at, old) {
|
|
|
106
106
|
newRow(lanes, c, p, v);
|
|
107
107
|
if (c.hot[p * c.stride + 6 /* Hot.EPOCH */] === 0 && v.state !== 'pending')
|
|
108
108
|
c.hot[p * c.stride + 6 /* Hot.EPOCH */] = open(lanes, v);
|
|
109
|
-
const seat = new Seat(lanes, c, p);
|
|
109
|
+
const seat = new Seat(lanes, c, p, from === undefined ? lanes.probes : 0);
|
|
110
110
|
lanes.seats.set(v.id, seat);
|
|
111
111
|
v.seat = seat;
|
|
112
112
|
v.laned = true;
|
|
@@ -298,5 +298,8 @@ export function reportedRow(lanes, c, p, slot) {
|
|
|
298
298
|
return undefined;
|
|
299
299
|
if (c.list[p] !== slot)
|
|
300
300
|
return undefined;
|
|
301
|
+
const made = seatOf(lanes, c.voices[p])?.made ?? 0;
|
|
302
|
+
if (!(lanes.per[o + 3 /* Per.LANE_PROBE */] > made))
|
|
303
|
+
return undefined;
|
|
301
304
|
return c.data[p * 8 /* Row.STRIDE */ + (lanes.per[o + 5 /* Per.LANE_FILL */] === lanes.fills ? 2 /* Row.WEIGHT */ : 3 /* Row.PROBED */)];
|
|
302
305
|
}
|
package/dist/sample.js
CHANGED
|
@@ -43,7 +43,8 @@ export function runMotion(lanes, lane, run) {
|
|
|
43
43
|
}
|
|
44
44
|
const samples = lane.samples;
|
|
45
45
|
const xs = run.xs;
|
|
46
|
-
|
|
46
|
+
// A tween round the hue is no straight line between its ends: `sampleBare` reads it round the hue.
|
|
47
|
+
const ease = run.round ? undefined : run.ease;
|
|
47
48
|
// A tween whose stretches tell the lane before they change keeps no sample: see `unbareLane`.
|
|
48
49
|
if (run.watcher === null) {
|
|
49
50
|
run.watcher = lanes;
|
package/dist/seat.d.ts
CHANGED
|
@@ -9,7 +9,11 @@ export declare class Seat<I, O> {
|
|
|
9
9
|
lanes: object | null;
|
|
10
10
|
readonly crowd: Crowd<I, O>;
|
|
11
11
|
row: number;
|
|
12
|
-
|
|
12
|
+
/** The lanes' probe count when its row was made new, 0 for a row copied from another crowd. */
|
|
13
|
+
readonly made: number;
|
|
14
|
+
constructor(lanes: object | null, crowd: Crowd<I, O>, row: number,
|
|
15
|
+
/** The lanes' probe count when its row was made new, 0 for a row copied from another crowd. */
|
|
16
|
+
made?: number);
|
|
13
17
|
}
|
|
14
18
|
/** `voice`'s seat in `lanes`, null where it has none there. */
|
|
15
19
|
export declare function seatOf<I, O>(lanes: object, voice: Voice<I, O>): Seat<I, O> | null;
|
package/dist/seat.js
CHANGED
|
@@ -7,10 +7,14 @@ export class Seat {
|
|
|
7
7
|
lanes;
|
|
8
8
|
crowd;
|
|
9
9
|
row;
|
|
10
|
-
|
|
10
|
+
made;
|
|
11
|
+
constructor(lanes, crowd, row,
|
|
12
|
+
/** The lanes' probe count when its row was made new, 0 for a row copied from another crowd. */
|
|
13
|
+
made = 0) {
|
|
11
14
|
this.lanes = lanes;
|
|
12
15
|
this.crowd = crowd;
|
|
13
16
|
this.row = row;
|
|
17
|
+
this.made = made;
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
20
|
/** `voice`'s seat in `lanes`, null where it has none there. */
|
package/dist/seek.js
CHANGED
|
@@ -6,13 +6,11 @@ import { apart, copyHeld, copyHeldInto, lastIndex, lastWithin, unread } from './
|
|
|
6
6
|
import { laneHost } from './hosts.js';
|
|
7
7
|
import { Leavings } from './leavings.js';
|
|
8
8
|
import { move, nextFrame } from './move.js';
|
|
9
|
-
import { ownerReading } from './owner.js';
|
|
10
9
|
import { place } from './place.js';
|
|
11
10
|
import { unpull } from './pull.js';
|
|
12
11
|
import { isRested } from './record.js';
|
|
13
12
|
import { Restored } from './restored.js';
|
|
14
13
|
import { recount } from './roster.js';
|
|
15
|
-
import { refitAll } from './spans.js';
|
|
16
14
|
import { Store } from './store.js';
|
|
17
15
|
import { hostAhead, hostAt, replay } from './tape.js';
|
|
18
16
|
import { cover, coverFrame, cut } from './unpage.js';
|
|
@@ -209,17 +207,6 @@ function restoreVoice(mix, voice, t, seq) {
|
|
|
209
207
|
}
|
|
210
208
|
records.back(t, cut, future);
|
|
211
209
|
}
|
|
212
|
-
/** Each voice's state at mix time `t`, once every clock above it is back where it was. */
|
|
213
|
-
function stateAt(voice, t) {
|
|
214
|
-
// A fade begins at once, even one whose ramp starts later, at the voice's start.
|
|
215
|
-
if (voice.out !== null)
|
|
216
|
-
return 'fading';
|
|
217
|
-
if ((voice.owner === null ? t : ownerReading(voice.owner, t)) < voice.start)
|
|
218
|
-
return 'pending';
|
|
219
|
-
if (voice.freezesAfter && voice.elapsedAt(t) >= voice.span + voice.latest)
|
|
220
|
-
return 'frozen';
|
|
221
|
-
return 'live';
|
|
222
|
-
}
|
|
223
210
|
/**
|
|
224
211
|
* Moves every mix on the transport to mix time `to`, as it stood at the end of that frame, or to
|
|
225
212
|
* the end of the frame numbered `to.frame`.
|
|
@@ -333,8 +320,12 @@ function back(mix, t, seq, on) {
|
|
|
333
320
|
kept.push(voice);
|
|
334
321
|
for (const voice of kept)
|
|
335
322
|
restoreVoice(mix, voice, t, seq);
|
|
336
|
-
|
|
337
|
-
|
|
323
|
+
const cut = { seq, strict: false };
|
|
324
|
+
for (const voice of kept) {
|
|
325
|
+
voice.state = voice.stateAt(t, cut);
|
|
326
|
+
if (voice.begunSeq > seq)
|
|
327
|
+
voice.begunSeq = Number.POSITIVE_INFINITY;
|
|
328
|
+
}
|
|
338
329
|
mix.cued = kept;
|
|
339
330
|
mix.gone = gone;
|
|
340
331
|
mix.retired = [];
|
|
@@ -400,7 +391,6 @@ function back(mix, t, seq, on) {
|
|
|
400
391
|
mix.pins ??= new Map();
|
|
401
392
|
mix.pins.set(voice, voice.pinned);
|
|
402
393
|
}
|
|
403
|
-
refitAll(mix);
|
|
404
394
|
mix.due.clear();
|
|
405
395
|
for (const voice of kept)
|
|
406
396
|
schedule(mix, voice);
|
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.16.1";
|
|
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.16.1';
|
|
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/spans.d.ts
CHANGED
|
@@ -15,11 +15,17 @@ export declare class Fitting {
|
|
|
15
15
|
}
|
|
16
16
|
/** Refuses a voice a span cannot fit: one it would not own the timing of, or one with no end. */
|
|
17
17
|
export declare function checkChild<I, O>(spec: VoiceSpec<I, O>, child: Voice<I, O>): void;
|
|
18
|
+
/**
|
|
19
|
+
* Puts a child whose owner's clock ran back to before a fit changed its rate, or skipped it, back
|
|
20
|
+
* on the clock it ran on before, so it reads, run back over, what it read going forward; and once
|
|
21
|
+
* the owner's clock reaches that change again, takes the change again, as the layout stands.
|
|
22
|
+
*/
|
|
23
|
+
export declare function unfit<I, O>(mix: Mixer<I, O>, child: Voice<I, O>, now: number): void;
|
|
18
24
|
/**
|
|
19
25
|
* Lays out a span's children and fits them into what is left of its budget, from its clock at mix
|
|
20
26
|
* time `from`, default now. Only what is still to come moves: a playing child keeps its place and
|
|
21
27
|
* may change rate, a pending one is placed. A span held by a span is fitted again by its own span
|
|
22
|
-
* after.
|
|
28
|
+
* after. A span its clock ran back over keeps the layout it made going forward.
|
|
23
29
|
*/
|
|
24
30
|
export declare function refit<I, O>(mix: Mixer<I, O>, span: Voice<I, O>, from?: number): void;
|
|
25
31
|
/**
|
|
@@ -29,7 +35,10 @@ export declare function refit<I, O>(mix: Mixer<I, O>, span: Voice<I, O>, from?:
|
|
|
29
35
|
export declare function refloor<I, O>(mix: Mixer<I, O>): void;
|
|
30
36
|
/** Whether a span whose last child just left at mix time `at` stays, its budget not yet out. */
|
|
31
37
|
export declare function lingers<I, O>(span: Voice<I, O>, at: number): boolean;
|
|
32
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Lets the spans out of budget that hold no child still playing leave, at the moment their budget
|
|
40
|
+
* ran out, or, under history, stay quiet with an owner holding them.
|
|
41
|
+
*/
|
|
33
42
|
export declare function lapse<I, O>(mix: Mixer<I, O>, now: number): void;
|
|
34
|
-
/**
|
|
35
|
-
export declare function
|
|
43
|
+
/** Whether a span's budget is out by `now` with no child of it still playing. */
|
|
44
|
+
export declare function lapses<I, O>(span: Voice<I, O>, now: number): boolean;
|