@msb235/blits 0.15.1 → 0.16.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 +35 -0
- package/README.md +1 -1
- package/dist/ahead.js +5 -4
- package/dist/chain.js +2 -3
- 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/crowd.d.ts +0 -6
- package/dist/crowd.js +0 -11
- package/dist/cue.js +7 -4
- package/dist/everyone.d.ts +17 -6
- package/dist/everyone.js +17 -8
- package/dist/fade.d.ts +11 -0
- package/dist/fade.js +44 -8
- package/dist/fold.js +4 -7
- package/dist/held.js +3 -4
- package/dist/hosts.d.ts +7 -0
- package/dist/hosts.js +18 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lanes.d.ts +26 -1
- package/dist/lanes.js +7 -0
- package/dist/lch.d.ts +23 -0
- package/dist/lch.js +126 -0
- package/dist/mixer.d.ts +4 -1
- package/dist/mixer.js +3 -0
- package/dist/motions.d.ts +4 -1
- package/dist/motions.js +16 -2
- package/dist/move.js +15 -10
- package/dist/owner.d.ts +7 -2
- package/dist/owner.js +13 -3
- package/dist/project.js +3 -8
- package/dist/pull.d.ts +11 -0
- package/dist/pull.js +10 -6
- package/dist/qualify.js +1 -1
- package/dist/roles.js +1 -3
- package/dist/roster.d.ts +6 -0
- package/dist/roster.js +8 -1
- package/dist/sample.js +2 -1
- package/dist/seek.js +1 -13
- package/dist/shared.d.ts +1 -1
- package/dist/shared.js +1 -1
- package/dist/spans.d.ts +4 -1
- package/dist/spans.js +6 -3
- package/dist/touch.js +1 -2
- package/dist/turns.js +2 -1
- package/dist/types/voice.d.ts +3 -2
- package/dist/voice.d.ts +19 -0
- package/dist/voice.js +35 -1
- package/docs/schema.html +37 -11
- package/package.json +1 -1
package/dist/motions.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { applied, change, commit, cut, dueTo, insert, peek, queue, rewind } from './changes.js';
|
|
2
|
-
import { closed } from './closed.js';
|
|
2
|
+
import { BOUND, closed } from './closed.js';
|
|
3
|
+
import { closedLch } from './lch.js';
|
|
3
4
|
import { made, pack, prune, reclaim, release, restretch, runAt, runThen, unpack, unrelease, } from './lives.js';
|
|
4
5
|
import { absent, Numbers } from './numbers.js';
|
|
5
6
|
import { reading } from './reading.js';
|
|
@@ -16,6 +17,7 @@ const PENDING = 2 /* RunFlag.PENDING */;
|
|
|
16
17
|
const OLDER = 4 /* RunFlag.OLDER */;
|
|
17
18
|
const LANDED = 8 /* RunFlag.LANDED */;
|
|
18
19
|
const wrongKind = (channel, holdsNumber) => new Error(`blits: channel ${channel} holds ${holdsNumber ? 'a number' : 'an array'}, and this motion patch gives a subject ${holdsNumber ? 'an array' : 'a number'}`);
|
|
20
|
+
const notOklab = (channel) => new Error(`blits: channel ${channel} goes round the hue, and a motion on it moves oklab() values, four numbers each`);
|
|
19
21
|
/**
|
|
20
22
|
* A motion patch's subjects: the stretch each is playing, in one flat array by a number the patch
|
|
21
23
|
* gives it, with earlier stretches a read back may reach and changes not yet applied beside them.
|
|
@@ -68,11 +70,18 @@ export class Motions {
|
|
|
68
70
|
/** Whether the channel it was cued on holds a number; undefined until it is cued. */
|
|
69
71
|
holdsNumber = undefined;
|
|
70
72
|
channel = '';
|
|
73
|
+
/** Whether the channel it was cued on travels round the hue, as `ink` does, and its stretches too. */
|
|
74
|
+
round = false;
|
|
71
75
|
/**
|
|
72
76
|
* Records what the channel the patch is cued on holds, refusing a value of the other kind: at once
|
|
73
77
|
* where every subject's value is one kind, else on the first sample of a subject whose value is not.
|
|
78
|
+
* `round` for a channel that travels round the hue, as `ink` does.
|
|
74
79
|
*/
|
|
75
|
-
cuedOn(channel, holdsNumber) {
|
|
80
|
+
cuedOn(channel, holdsNumber, round = false) {
|
|
81
|
+
if (round && this.shape.law[0] === BOUND)
|
|
82
|
+
throw new Error(`blits: channel ${channel} goes round the hue, and a glide's bounds are a box on its OKLab axes; glide it without bounds`);
|
|
83
|
+
if (round && this.n >= 0 && this.n !== 4)
|
|
84
|
+
throw notOklab(channel);
|
|
76
85
|
const every = this.shape.scalarEvery();
|
|
77
86
|
if (every !== undefined && every !== holdsNumber)
|
|
78
87
|
throw wrongKind(channel, holdsNumber);
|
|
@@ -82,6 +91,7 @@ export class Motions {
|
|
|
82
91
|
throw wrongKind(channel, holdsNumber);
|
|
83
92
|
this.holdsNumber = holdsNumber;
|
|
84
93
|
this.channel = channel;
|
|
94
|
+
this.round = round;
|
|
85
95
|
}
|
|
86
96
|
frame(subject) {
|
|
87
97
|
return this.owner === null ? Number.NaN : this.owner.frame(this.ownerId, subject);
|
|
@@ -127,6 +137,8 @@ export class Motions {
|
|
|
127
137
|
}
|
|
128
138
|
/** Sets the axes every subject moves on, at the first. */
|
|
129
139
|
size(n) {
|
|
140
|
+
if (this.round && n !== 4)
|
|
141
|
+
throw notOklab(this.channel);
|
|
130
142
|
this.n = n;
|
|
131
143
|
this.stride = 3 + 3 * n;
|
|
132
144
|
if (shared.xs.length < n)
|
|
@@ -426,6 +438,8 @@ export class Motions {
|
|
|
426
438
|
this.evaluate(seg.at, seg.ms, seg.x0, 0, seg.v0, 0, seg.to, 0, t, xo, vo);
|
|
427
439
|
}
|
|
428
440
|
evaluate(at, ms, x0, x, v0, v, to, g, t, xo, vo) {
|
|
441
|
+
if (this.round)
|
|
442
|
+
return closedLch(this.runs, this.shape.ease, at, ms, x0, x, v0, v, to, g, t, xo, vo);
|
|
429
443
|
return closed(this.runs, this.shape.ease, this.n, at, ms, x0, x, v0, v, to, g, t, xo, vo);
|
|
430
444
|
}
|
|
431
445
|
}
|
package/dist/move.js
CHANGED
|
@@ -2,16 +2,15 @@ import { settleArcs } from './arcs.js';
|
|
|
2
2
|
import { changed } from './chain.js';
|
|
3
3
|
import { elapsedWith } from './clock.js';
|
|
4
4
|
import { byId, popDue, schedule } from './due.js';
|
|
5
|
-
import {
|
|
6
|
-
import { beginFade, part, retire } from './fade.js';
|
|
5
|
+
import { beginFade, part, retire, rouse, stay } from './fade.js';
|
|
7
6
|
import { expireGone, keepGone } from './gone.js';
|
|
8
7
|
import { begin } from './held.js';
|
|
9
8
|
import { noted } from './history.js';
|
|
10
9
|
import { leave as leaveClock } from './origin.js';
|
|
11
|
-
import { ownerReading } from './owner.js';
|
|
10
|
+
import { ownerReading, plays } from './owner.js';
|
|
12
11
|
import { mixAt, place, repin, startAt, startOf } from './place.js';
|
|
13
12
|
import { pageVoice } from './revive.js';
|
|
14
|
-
import { delist } from './roster.js';
|
|
13
|
+
import { delist, detour } from './roster.js';
|
|
15
14
|
import { scoredLeft, scoredRemove } from './scored.js';
|
|
16
15
|
import { lapse } from './spans.js';
|
|
17
16
|
import { unplay } from './strays.js';
|
|
@@ -80,6 +79,8 @@ function moveTo(mix, now) {
|
|
|
80
79
|
if (voice.state !== 'pending') {
|
|
81
80
|
if (voice.turns)
|
|
82
81
|
turn(mix, voice, now);
|
|
82
|
+
if (voice.state === 'live' && voice.out !== null && !voice.quietAt(now))
|
|
83
|
+
rouse(mix, voice, now);
|
|
83
84
|
// Its passes run out at its end running forward, and at its start running back. A clock
|
|
84
85
|
// standing still at or before its start is where it was: waiting, or frozen there.
|
|
85
86
|
const way = heading(voice, now);
|
|
@@ -87,7 +88,7 @@ function moveTo(mix, now) {
|
|
|
87
88
|
const back = way < 0;
|
|
88
89
|
const atStart = !voice.beginless && at <= voice.soonest;
|
|
89
90
|
// An owner run back to its start stays for what it holds, and leaves with its last child.
|
|
90
|
-
const holds = voice.holding !== null && voice
|
|
91
|
+
const holds = voice.holding !== null && plays(voice, now);
|
|
91
92
|
const over = back
|
|
92
93
|
? atStart && !holds
|
|
93
94
|
: Number.isFinite(voice.span) && at >= voice.span + voice.latest;
|
|
@@ -95,11 +96,11 @@ function moveTo(mix, now) {
|
|
|
95
96
|
voice.play(true, now, mix.transport.seq);
|
|
96
97
|
// The fade starts when its passes ran out, not at the frame that noticed, so it plays
|
|
97
98
|
// the same at any frame rate and a read at another time can find it.
|
|
98
|
-
if (voice.state === 'live') {
|
|
99
|
+
if (voice.state === 'live' && voice.out === null) {
|
|
99
100
|
if (back ? voice.freezesBefore : voice.freezesAfter)
|
|
100
101
|
voice.state = 'frozen';
|
|
101
102
|
else
|
|
102
|
-
beginFade(mix, voice, { back }, Math.max(startOf(voice), Math.min(now, voice.endsAt())));
|
|
103
|
+
beginFade(mix, voice, { back, stays: voice.owner !== null && mix.opts.history !== undefined }, Math.max(startOf(voice), Math.min(now, voice.endsAt())));
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
else if (voice.state === 'frozen' && !(atStart && way === 0))
|
|
@@ -126,8 +127,12 @@ function moveTo(mix, now) {
|
|
|
126
127
|
else if (settled)
|
|
127
128
|
retire(mix, voice);
|
|
128
129
|
}
|
|
129
|
-
else if (spent >= over)
|
|
130
|
-
|
|
130
|
+
else if (spent >= over) {
|
|
131
|
+
if (voice.out.stays)
|
|
132
|
+
stay(mix, voice, at + over);
|
|
133
|
+
else
|
|
134
|
+
retire(mix, voice, at + over);
|
|
135
|
+
}
|
|
131
136
|
}
|
|
132
137
|
if (!mix.projecting)
|
|
133
138
|
schedule(mix, voice);
|
|
@@ -137,7 +142,7 @@ function moveTo(mix, now) {
|
|
|
137
142
|
settleArcs(mix, now);
|
|
138
143
|
}
|
|
139
144
|
if (mix.sharers.length > 0 && !mix.projecting)
|
|
140
|
-
outgrow(mix);
|
|
145
|
+
mix.share?.outgrow(mix);
|
|
141
146
|
mix.stirred = false;
|
|
142
147
|
mix.asleep = false;
|
|
143
148
|
if (mix.retired.length > 0)
|
package/dist/owner.d.ts
CHANGED
|
@@ -36,8 +36,13 @@ export declare function mixTime<I, O>(owner: Voice<I, O>, t: number): number;
|
|
|
36
36
|
export declare function turnedBack<I, O>(voice: Voice<I, O>): boolean;
|
|
37
37
|
/** Takes a child into its owner. */
|
|
38
38
|
export declare function adopt<I, O>(owner: Voice<I, O>, child: Voice<I, O>): void;
|
|
39
|
-
/**
|
|
40
|
-
|
|
39
|
+
/**
|
|
40
|
+
* A child left at mix time `now`: its owner, where that was its last child still playing and it
|
|
41
|
+
* should leave too.
|
|
42
|
+
*/
|
|
43
|
+
export declare function orphan<I, O>(child: Voice<I, O>, now: number): Voice<I, O> | null;
|
|
44
|
+
/** Whether an owner holds a child at mix time `now` that is not kept quiet past its passes. */
|
|
45
|
+
export declare function plays<I, O>(owner: Voice<I, O>, now: number): boolean;
|
|
41
46
|
/** A child finished its passes: its owner has played once every child it held has. */
|
|
42
47
|
export declare function childPlayed<I, O>(owner: Voice<I, O>, at: number, seq: number): void;
|
|
43
48
|
/** Every voice an owner holds, its children's children included. */
|
package/dist/owner.js
CHANGED
|
@@ -76,14 +76,24 @@ export function adopt(owner, child) {
|
|
|
76
76
|
h.children.push(child);
|
|
77
77
|
h.kids++;
|
|
78
78
|
}
|
|
79
|
-
/**
|
|
80
|
-
|
|
79
|
+
/**
|
|
80
|
+
* A child left at mix time `now`: its owner, where that was its last child still playing and it
|
|
81
|
+
* should leave too.
|
|
82
|
+
*/
|
|
83
|
+
export function orphan(child, now) {
|
|
81
84
|
const owner = child.owner;
|
|
82
85
|
const h = owner.holding;
|
|
83
86
|
const i = h.children.indexOf(child);
|
|
84
87
|
if (i >= 0)
|
|
85
88
|
h.children.splice(i, 1);
|
|
86
|
-
return
|
|
89
|
+
return !plays(owner, now) && owner.state !== 'done' ? owner : null;
|
|
90
|
+
}
|
|
91
|
+
/** Whether an owner holds a child at mix time `now` that is not kept quiet past its passes. */
|
|
92
|
+
export function plays(owner, now) {
|
|
93
|
+
for (const child of owner.holding.children)
|
|
94
|
+
if (!child.quietAt(now))
|
|
95
|
+
return true;
|
|
96
|
+
return false;
|
|
87
97
|
}
|
|
88
98
|
/** A child finished its passes: its owner has played once every child it held has. */
|
|
89
99
|
export function childPlayed(owner, at, seq) {
|
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)
|
|
@@ -183,13 +184,7 @@ function copyBack(mix, c, t, cut) {
|
|
|
183
184
|
/** Sets each copied voice's state to what its clock and fade make it at `t`. */
|
|
184
185
|
export function stateAt(c, t) {
|
|
185
186
|
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';
|
|
187
|
+
copy.state = copy.stateAt(t);
|
|
193
188
|
}
|
|
194
189
|
/**
|
|
195
190
|
* 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';
|
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,7 +52,7 @@ 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);
|
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/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/seek.js
CHANGED
|
@@ -6,7 +6,6 @@ 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';
|
|
@@ -209,17 +208,6 @@ function restoreVoice(mix, voice, t, seq) {
|
|
|
209
208
|
}
|
|
210
209
|
records.back(t, cut, future);
|
|
211
210
|
}
|
|
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
211
|
/**
|
|
224
212
|
* Moves every mix on the transport to mix time `to`, as it stood at the end of that frame, or to
|
|
225
213
|
* the end of the frame numbered `to.frame`.
|
|
@@ -334,7 +322,7 @@ function back(mix, t, seq, on) {
|
|
|
334
322
|
for (const voice of kept)
|
|
335
323
|
restoreVoice(mix, voice, t, seq);
|
|
336
324
|
for (const voice of kept)
|
|
337
|
-
voice.state = stateAt(
|
|
325
|
+
voice.state = voice.stateAt(t);
|
|
338
326
|
mix.cued = kept;
|
|
339
327
|
mix.gone = gone;
|
|
340
328
|
mix.retired = [];
|
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.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.16.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/spans.d.ts
CHANGED
|
@@ -29,7 +29,10 @@ export declare function refit<I, O>(mix: Mixer<I, O>, span: Voice<I, O>, from?:
|
|
|
29
29
|
export declare function refloor<I, O>(mix: Mixer<I, O>): void;
|
|
30
30
|
/** Whether a span whose last child just left at mix time `at` stays, its budget not yet out. */
|
|
31
31
|
export declare function lingers<I, O>(span: Voice<I, O>, at: number): boolean;
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Lets the spans out of budget that hold no child still playing leave, at the moment their budget
|
|
34
|
+
* ran out.
|
|
35
|
+
*/
|
|
33
36
|
export declare function lapse<I, O>(mix: Mixer<I, O>, now: number): void;
|
|
34
37
|
/** Fits every span again, as after a seek put its children back. */
|
|
35
38
|
export declare function refitAll<I, O>(mix: Mixer<I, O>): void;
|
package/dist/spans.js
CHANGED
|
@@ -6,7 +6,7 @@ import { reorigin } from './held.js';
|
|
|
6
6
|
import { noted } from './history.js';
|
|
7
7
|
import { nextFrame } from './move.js';
|
|
8
8
|
import { leave } from './origin.js';
|
|
9
|
-
import { ownerReading } from './owner.js';
|
|
9
|
+
import { ownerReading, plays } from './owner.js';
|
|
10
10
|
import { resolve } from './place.js';
|
|
11
11
|
/** What a span keeps beside its owner: its claim, its fit, and how the last fit came out. */
|
|
12
12
|
export class Fitting {
|
|
@@ -222,13 +222,16 @@ export function lingers(span, at) {
|
|
|
222
222
|
const f = span.fitting;
|
|
223
223
|
return f !== null && Number.isFinite(f.budget) && ownerReading(span, at) < f.budget;
|
|
224
224
|
}
|
|
225
|
-
/**
|
|
225
|
+
/**
|
|
226
|
+
* Lets the spans out of budget that hold no child still playing leave, at the moment their budget
|
|
227
|
+
* ran out.
|
|
228
|
+
*/
|
|
226
229
|
export function lapse(mix, now) {
|
|
227
230
|
for (const span of mix.owners ?? []) {
|
|
228
231
|
const f = span.fitting;
|
|
229
232
|
if (f === null || span.state === 'done' || !Number.isFinite(f.budget))
|
|
230
233
|
continue;
|
|
231
|
-
if ((span
|
|
234
|
+
if (plays(span, now))
|
|
232
235
|
continue;
|
|
233
236
|
if (ownerReading(span, now) >= f.budget)
|
|
234
237
|
retire(mix, span, span.timeAt(f.budget));
|
package/dist/touch.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { headOf } from './chain.js';
|
|
2
|
-
import { restamp } from './everyone.js';
|
|
3
2
|
import { nextFrame } from './move.js';
|
|
4
3
|
/**
|
|
5
4
|
* What `Mix.touch` does: makes stale every delta read this frame, for one subject or for all, so
|
|
@@ -22,7 +21,7 @@ export function touch(mix, subject) {
|
|
|
22
21
|
held.seeks = -1;
|
|
23
22
|
const slot = headOf(mix, subject)?.slot ?? -1;
|
|
24
23
|
for (const voice of mix.sharers)
|
|
25
|
-
restamp(voice, slot);
|
|
24
|
+
mix.share?.restamp(voice, slot);
|
|
26
25
|
}
|
|
27
26
|
mix.lanes?.refill();
|
|
28
27
|
mix.stir();
|
package/dist/turns.js
CHANGED
|
@@ -51,7 +51,8 @@ export function turnToward(ch, values, base, value, taken, u) {
|
|
|
51
51
|
}
|
|
52
52
|
const axes = ch.axes;
|
|
53
53
|
let out = value;
|
|
54
|
-
|
|
54
|
+
// A first value of other axes than the lane's, as an ink contribution is, widens through the lerp.
|
|
55
|
+
if (taken !== 0 || out.length !== axes) {
|
|
55
56
|
held = lift(values, base, axes, held);
|
|
56
57
|
out = ch.channel.lerp(held, value, u);
|
|
57
58
|
}
|
package/dist/types/voice.d.ts
CHANGED
|
@@ -249,8 +249,9 @@ export interface OwnerSpec<I, H = unknown> extends SpanHints {
|
|
|
249
249
|
/**
|
|
250
250
|
* Its clock's rate, multiplied into every child's own. Default 1. Below 0 its clock runs back,
|
|
251
251
|
* and so does every child's: a child plays backward to its start and leaves there, as a voice cued
|
|
252
|
-
* backward does, and the owner leaves with its last child.
|
|
253
|
-
*
|
|
252
|
+
* backward does, and the owner leaves with its last child. Under `history` a child that already
|
|
253
|
+
* left runs back too: a child leaves only when its owner does. A span is not cued backward, since
|
|
254
|
+
* it lays out its children forward from its start; its handle's `rate` turns it once it plays.
|
|
254
255
|
*/
|
|
255
256
|
rate?: number;
|
|
256
257
|
/**
|
package/dist/voice.d.ts
CHANGED
|
@@ -46,6 +46,11 @@ export interface Ramp {
|
|
|
46
46
|
deadline?: number;
|
|
47
47
|
/** Begun where the voice ran back to its start, whose first frame it holds through the fade. */
|
|
48
48
|
back?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Begun where the passes of a voice an owner holds under history ran out: faded, it stays live
|
|
51
|
+
* and quiet with its owner, which brings it back by taking its clock back into its passes.
|
|
52
|
+
*/
|
|
53
|
+
stays?: boolean;
|
|
49
54
|
}
|
|
50
55
|
/**
|
|
51
56
|
* A climb back from a fade out that was turned around: from `from`, the place along the fade's
|
|
@@ -326,6 +331,20 @@ export declare class Voice<I, O> {
|
|
|
326
331
|
* turn it around.
|
|
327
332
|
*/
|
|
328
333
|
endsAt(): number;
|
|
334
|
+
/** The mix time its clock reads `elapsed`, by its controls now, through every owner above it. */
|
|
335
|
+
reaches(elapsed: number): number;
|
|
336
|
+
/**
|
|
337
|
+
* Its state at mix time `t`, from its clock and fade, once every clock above it is back where it
|
|
338
|
+
* was: a fade begins at once, even one whose ramp starts later, at the voice's start, and one
|
|
339
|
+
* from where an owner under history keeps it ends with it quiet and live.
|
|
340
|
+
*/
|
|
341
|
+
stateAt(t: number): Voice<I, O>['state'];
|
|
342
|
+
/**
|
|
343
|
+
* Whether it is kept quiet past its passes at mix time `now`: its passes ran out while an owner
|
|
344
|
+
* held it under history, and its clock has not come back into them. At their very edge it is
|
|
345
|
+
* quiet unless its clock runs into them.
|
|
346
|
+
*/
|
|
347
|
+
quietAt(now: number): boolean;
|
|
329
348
|
/**
|
|
330
349
|
* The mix time its clock ran back to `elapsed` by `now`, by its controls now: where a subject
|
|
331
350
|
* `elapsed` into it reached its start. NaN where it has not, and for a voice an owner holds.
|
package/dist/voice.js
CHANGED
|
@@ -472,9 +472,43 @@ export class Voice {
|
|
|
472
472
|
return Number.POSITIVE_INFINITY;
|
|
473
473
|
to = this.span + this.latest;
|
|
474
474
|
}
|
|
475
|
-
|
|
475
|
+
return this.reaches(to);
|
|
476
|
+
}
|
|
477
|
+
/** The mix time its clock reads `elapsed`, by its controls now, through every owner above it. */
|
|
478
|
+
reaches(elapsed) {
|
|
479
|
+
const t = this.backs ? backWith(this, elapsed) : timeWith(this, elapsed);
|
|
476
480
|
return this.owner === null ? t : mixTime(this.owner, t);
|
|
477
481
|
}
|
|
482
|
+
/**
|
|
483
|
+
* Its state at mix time `t`, from its clock and fade, once every clock above it is back where it
|
|
484
|
+
* was: a fade begins at once, even one whose ramp starts later, at the voice's start, and one
|
|
485
|
+
* from where an owner under history keeps it ends with it quiet and live.
|
|
486
|
+
*/
|
|
487
|
+
stateAt(t) {
|
|
488
|
+
const out = this.out;
|
|
489
|
+
if (out !== null)
|
|
490
|
+
return out.stays && t >= out.at + out.over ? 'live' : 'fading';
|
|
491
|
+
if ((this.owner === null ? t : ownerReading(this.owner, t)) < this.start)
|
|
492
|
+
return 'pending';
|
|
493
|
+
if (this.freezesAfter && this.elapsedAt(t) >= this.span + this.latest)
|
|
494
|
+
return 'frozen';
|
|
495
|
+
return 'live';
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Whether it is kept quiet past its passes at mix time `now`: its passes ran out while an owner
|
|
499
|
+
* held it under history, and its clock has not come back into them. At their very edge it is
|
|
500
|
+
* quiet unless its clock runs into them.
|
|
501
|
+
*/
|
|
502
|
+
quietAt(now) {
|
|
503
|
+
if (this.state !== 'live' || this.out?.stays !== true)
|
|
504
|
+
return false;
|
|
505
|
+
const at = this.elapsedAt(now);
|
|
506
|
+
const end = this.span + this.latest;
|
|
507
|
+
const back = this.backs !== (this.owner !== null && turnedBack(this));
|
|
508
|
+
if (at > end || (at === end && !back))
|
|
509
|
+
return true;
|
|
510
|
+
return !this.beginless && (at < this.soonest || (at === this.soonest && back));
|
|
511
|
+
}
|
|
478
512
|
/**
|
|
479
513
|
* The mix time its clock ran back to `elapsed` by `now`, by its controls now: where a subject
|
|
480
514
|
* `elapsed` into it reached its start. NaN where it has not, and for a voice an owner holds.
|