@msb235/blits 0.3.0 → 0.5.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 +314 -0
- package/README.md +3 -2
- package/dist/bare.d.ts +29 -0
- package/dist/bare.js +105 -0
- package/dist/blend.d.ts +34 -0
- package/dist/blend.js +102 -0
- package/dist/book.d.ts +53 -0
- package/dist/book.js +218 -0
- package/dist/chain.d.ts +22 -0
- package/dist/chain.js +150 -0
- package/dist/channels.d.ts +2 -0
- package/dist/channels.js +3 -1
- package/dist/clock.d.ts +50 -3
- package/dist/clock.js +102 -9
- package/dist/clone.d.ts +7 -0
- package/dist/clone.js +57 -0
- package/dist/columns.d.ts +29 -0
- package/dist/columns.js +183 -0
- package/dist/crowd.d.ts +128 -0
- package/dist/crowd.js +354 -0
- package/dist/cue.d.ts +3 -0
- package/dist/cue.js +115 -0
- package/dist/due.d.ts +12 -0
- package/dist/due.js +93 -0
- package/dist/fade.d.ts +19 -0
- package/dist/fade.js +133 -0
- package/dist/fill.d.ts +42 -0
- package/dist/fill.js +381 -0
- package/dist/fold.d.ts +51 -0
- package/dist/fold.js +475 -0
- package/dist/gather.d.ts +24 -0
- package/dist/gather.js +186 -0
- package/dist/handle.d.ts +31 -0
- package/dist/handle.js +56 -0
- package/dist/held.d.ts +14 -0
- package/dist/held.js +117 -0
- package/dist/history.d.ts +22 -0
- package/dist/history.js +149 -0
- package/dist/hosts.d.ts +16 -0
- package/dist/hosts.js +178 -0
- package/dist/index.d.ts +1 -1
- package/dist/keyrows.d.ts +36 -0
- package/dist/keyrows.js +138 -0
- package/dist/lane.d.ts +210 -0
- package/dist/lane.js +187 -0
- package/dist/lanes.d.ts +143 -122
- package/dist/lanes.js +236 -742
- package/dist/locus.d.ts +40 -0
- package/dist/locus.js +89 -0
- package/dist/marks.d.ts +12 -0
- package/dist/marks.js +80 -0
- package/dist/meet.d.ts +16 -0
- package/dist/meet.js +113 -0
- package/dist/mixer.d.ts +244 -169
- package/dist/mixer.js +321 -1793
- package/dist/motion.d.ts +104 -19
- package/dist/motion.js +448 -180
- package/dist/move.d.ts +9 -0
- package/dist/move.js +190 -0
- package/dist/named.d.ts +12 -0
- package/dist/named.js +39 -0
- package/dist/numbers.d.ts +18 -6
- package/dist/numbers.js +59 -31
- package/dist/owed.d.ts +24 -0
- package/dist/owed.js +51 -0
- package/dist/owner.d.ts +43 -0
- package/dist/owner.js +117 -0
- package/dist/pace.d.ts +40 -0
- package/dist/pace.js +113 -0
- package/dist/patch.d.ts +51 -10
- package/dist/patch.js +140 -45
- package/dist/place.d.ts +20 -0
- package/dist/place.js +196 -0
- package/dist/project.d.ts +4 -0
- package/dist/project.js +233 -0
- package/dist/pull.d.ts +5 -0
- package/dist/pull.js +175 -0
- package/dist/qualify.d.ts +31 -0
- package/dist/qualify.js +345 -0
- package/dist/relink.d.ts +25 -0
- package/dist/relink.js +59 -0
- package/dist/rows.d.ts +33 -0
- package/dist/rows.js +282 -0
- package/dist/sample.d.ts +21 -0
- package/dist/sample.js +232 -0
- package/dist/signals.d.ts +12 -9
- package/dist/signals.js +8 -5
- package/dist/store.d.ts +10 -3
- package/dist/store.js +44 -9
- package/dist/strays.d.ts +21 -0
- package/dist/strays.js +84 -0
- package/dist/tweened.d.ts +11 -0
- package/dist/tweened.js +48 -0
- package/dist/types.d.ts +261 -42
- package/dist/unreached.d.ts +5 -0
- package/dist/unreached.js +24 -0
- package/dist/voice.d.ts +240 -0
- package/dist/voice.js +322 -0
- package/dist/weigh.d.ts +26 -0
- package/dist/weigh.js +89 -0
- package/docs/schema.html +151 -46
- package/package.json +5 -2
package/dist/store.js
CHANGED
|
@@ -1,22 +1,47 @@
|
|
|
1
|
+
/** What every store reads before its first write: never written, so always empty. */
|
|
2
|
+
const noWeak = new WeakMap();
|
|
3
|
+
const noStrong = new Map();
|
|
1
4
|
/**
|
|
2
5
|
* Per-subject storage keyed by identity. Objects go in a WeakMap and are forgotten when the host
|
|
3
6
|
* drops them; anything else — a string id, the unit subject of a mix with no subject dimension —
|
|
4
7
|
* goes in a Map that only `drop` and `clear` empty, which is why a host keying by value should
|
|
5
|
-
* call `drop`.
|
|
8
|
+
* call `drop`. Each map is made when first written, since a mix holds a store per voice and patch;
|
|
9
|
+
* until then it is a shared empty one, so the field always holds a map.
|
|
6
10
|
*/
|
|
7
11
|
export class Store {
|
|
8
|
-
weak =
|
|
9
|
-
strong =
|
|
12
|
+
weak = noWeak;
|
|
13
|
+
strong = noStrong;
|
|
14
|
+
/**
|
|
15
|
+
* The first key that is not an object, and its value, held here until a second comes: a voice of
|
|
16
|
+
* one subject keyed by id would otherwise spend a Map's smallest table on it.
|
|
17
|
+
*/
|
|
18
|
+
oneKey = none;
|
|
19
|
+
oneValue = undefined;
|
|
10
20
|
get(key) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
if (typeof key === 'object' && key !== null)
|
|
22
|
+
return this.weak.get(key);
|
|
23
|
+
return same(this.oneKey, key) ? this.oneValue : this.strong.get(key);
|
|
14
24
|
}
|
|
15
25
|
set(key, value) {
|
|
16
|
-
if (typeof key === 'object' && key !== null)
|
|
26
|
+
if (typeof key === 'object' && key !== null) {
|
|
27
|
+
if (this.weak === noWeak)
|
|
28
|
+
this.weak = new WeakMap();
|
|
17
29
|
this.weak.set(key, value);
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (this.strong === noStrong && (this.oneKey === none || same(this.oneKey, key))) {
|
|
33
|
+
this.oneKey = key;
|
|
34
|
+
this.oneValue = value;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (this.strong === noStrong)
|
|
38
|
+
this.strong = new Map();
|
|
39
|
+
if (this.oneKey !== none) {
|
|
40
|
+
this.strong.set(this.oneKey, this.oneValue);
|
|
41
|
+
this.oneKey = none;
|
|
42
|
+
this.oneValue = undefined;
|
|
43
|
+
}
|
|
44
|
+
this.strong.set(key, value);
|
|
20
45
|
}
|
|
21
46
|
has(key) {
|
|
22
47
|
return this.get(key) !== undefined;
|
|
@@ -24,10 +49,20 @@ export class Store {
|
|
|
24
49
|
delete(key) {
|
|
25
50
|
if (typeof key === 'object' && key !== null)
|
|
26
51
|
this.weak.delete(key);
|
|
52
|
+
else if (same(this.oneKey, key)) {
|
|
53
|
+
this.oneKey = none;
|
|
54
|
+
this.oneValue = undefined;
|
|
55
|
+
}
|
|
27
56
|
else
|
|
28
57
|
this.strong.delete(key);
|
|
29
58
|
}
|
|
30
59
|
clear() {
|
|
60
|
+
this.oneKey = none;
|
|
61
|
+
this.oneValue = undefined;
|
|
31
62
|
this.strong.clear();
|
|
32
63
|
}
|
|
33
64
|
}
|
|
65
|
+
/** No key held inline. */
|
|
66
|
+
const none = Symbol('none');
|
|
67
|
+
/** A Map's key equality, SameValueZero: NaN finds NaN. */
|
|
68
|
+
const same = (a, b) => a === b || Object.is(a, b);
|
package/dist/strays.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Mixer } from './mixer.js';
|
|
2
|
+
import type { MotionOwner, Motions } from './motion.js';
|
|
3
|
+
import type { Voice } from './voice.js';
|
|
4
|
+
/** Notes a motion patch that may hold state for a subject no voice playing it reaches. */
|
|
5
|
+
export declare function stray<I, O>(mix: Mixer<I, O>, motion: Motions<I>, subject: I): void;
|
|
6
|
+
/** A motion voice left the list: if its patch plays on, its subjects' state there may stray. */
|
|
7
|
+
export declare function unplay<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>): void;
|
|
8
|
+
/**
|
|
9
|
+
* What a motion patch asks of the mix playing it, by its voice's id. It holds the mix weakly, so a
|
|
10
|
+
* patch the host keeps does not keep a mix it has let go of alive; a retired voice's patch no
|
|
11
|
+
* longer asks.
|
|
12
|
+
*/
|
|
13
|
+
export declare function motionOwner<I, O>(mix: WeakRef<Mixer<I, O>>): MotionOwner;
|
|
14
|
+
/** The voice in the list with this id, which is in id order. */
|
|
15
|
+
export declare function cuedById<I, O>(mix: Mixer<I, O>, id: number): Voice<I, O> | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* A subject's voice time at the latest frame, where a motion patch places an untimed change and a
|
|
18
|
+
* `read` with no time; NaN until the voice has started and met the subject, and while the
|
|
19
|
+
* subject's own time is still short of its stagger. A retired voice's patch no longer asks.
|
|
20
|
+
*/
|
|
21
|
+
export declare function frameOf<I, O>(mix: Mixer<I, O>, voice: Voice<I, O>, subject: I): number;
|
package/dist/strays.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { unpart } from './fade.js';
|
|
2
|
+
/** Notes a motion patch that may hold state for a subject no voice playing it reaches. */
|
|
3
|
+
export function stray(mix, motion, subject) {
|
|
4
|
+
const list = mix.strays.get(subject);
|
|
5
|
+
if (list === undefined)
|
|
6
|
+
mix.strays.set(subject, [motion]);
|
|
7
|
+
else if (!list.includes(motion))
|
|
8
|
+
list.push(motion);
|
|
9
|
+
}
|
|
10
|
+
/** A motion voice left the list: if its patch plays on, its subjects' state there may stray. */
|
|
11
|
+
export function unplay(mix, voice) {
|
|
12
|
+
const motion = voice.motion;
|
|
13
|
+
if (motion === undefined)
|
|
14
|
+
return;
|
|
15
|
+
const left = (mix.playing.get(motion) ?? 1) - 1;
|
|
16
|
+
if (left <= 0) {
|
|
17
|
+
mix.playing.delete(motion);
|
|
18
|
+
mix.strayAll.delete(motion);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
mix.playing.set(motion, left);
|
|
22
|
+
if (voice.named === null)
|
|
23
|
+
mix.strayAll.add(motion);
|
|
24
|
+
else
|
|
25
|
+
for (const subject of voice.named)
|
|
26
|
+
stray(mix, motion, subject);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* What a motion patch asks of the mix playing it, by its voice's id. It holds the mix weakly, so a
|
|
30
|
+
* patch the host keeps does not keep a mix it has let go of alive; a retired voice's patch no
|
|
31
|
+
* longer asks.
|
|
32
|
+
*/
|
|
33
|
+
export function motionOwner(mix) {
|
|
34
|
+
return {
|
|
35
|
+
frame(id, subject) {
|
|
36
|
+
const m = mix.deref();
|
|
37
|
+
const v = m === undefined ? undefined : cuedById(m, id);
|
|
38
|
+
return m === undefined || v === undefined ? Number.NaN : frameOf(m, v, subject);
|
|
39
|
+
},
|
|
40
|
+
revive(id, subject) {
|
|
41
|
+
const m = mix.deref();
|
|
42
|
+
if (m === undefined)
|
|
43
|
+
return;
|
|
44
|
+
m.stir();
|
|
45
|
+
const v = cuedById(m, id);
|
|
46
|
+
if (v === undefined)
|
|
47
|
+
return;
|
|
48
|
+
if (v.motion !== undefined && v.named !== null && !v.named.has(subject))
|
|
49
|
+
stray(m, v.motion, subject);
|
|
50
|
+
unpart(m, v, subject);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** The voice in the list with this id, which is in id order. */
|
|
55
|
+
export function cuedById(mix, id) {
|
|
56
|
+
const cued = mix.cued;
|
|
57
|
+
let lo = 0;
|
|
58
|
+
let hi = cued.length - 1;
|
|
59
|
+
while (lo <= hi) {
|
|
60
|
+
const mid = (lo + hi) >> 1;
|
|
61
|
+
const v = cued[mid];
|
|
62
|
+
if (v.id === id)
|
|
63
|
+
return v;
|
|
64
|
+
if (v.id < id)
|
|
65
|
+
lo = mid + 1;
|
|
66
|
+
else
|
|
67
|
+
hi = mid - 1;
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A subject's voice time at the latest frame, where a motion patch places an untimed change and a
|
|
73
|
+
* `read` with no time; NaN until the voice has started and met the subject, and while the
|
|
74
|
+
* subject's own time is still short of its stagger. A retired voice's patch no longer asks.
|
|
75
|
+
*/
|
|
76
|
+
export function frameOf(mix, voice, subject) {
|
|
77
|
+
if (Number.isNaN(mix.now) || voice.state === 'pending')
|
|
78
|
+
return Number.NaN;
|
|
79
|
+
const held = voice.subjects.get(subject);
|
|
80
|
+
if (held === undefined || !held.reaches)
|
|
81
|
+
return Number.NaN;
|
|
82
|
+
const t = voice.elapsedAt(mix.now) - held.delay;
|
|
83
|
+
return t < 0 ? Number.NaN : t;
|
|
84
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Curve } from './easing.js';
|
|
2
|
+
/** Turns the velocity `eased` works out on or off. */
|
|
3
|
+
export declare function sloped(on: boolean): void;
|
|
4
|
+
/** How far through a stretch released at `at` and lasting `ms` voice time `t` is, from 0. */
|
|
5
|
+
export declare function progress(t: number, at: number, ms: number): number;
|
|
6
|
+
/** The share of a tween's way left to go at `u`, 0 once it has arrived. */
|
|
7
|
+
export declare function left(ease: Curve, u: number): number;
|
|
8
|
+
/** An axis of a tween from `x0` to `goal` with `share` of the way left. */
|
|
9
|
+
export declare function between(x0: number, goal: number, share: number): number;
|
|
10
|
+
/** A tween's stretch at `u` into `xo` and `vo`: true once it has arrived. */
|
|
11
|
+
export declare function eased(ease: Curve, n: number, u: number, ms: number, x0: ArrayLike<number>, x: number, to: ArrayLike<number>, g: number, xo: Float64Array, vo: Float64Array): boolean;
|
package/dist/tweened.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** How far a tween's slope is read either side of `u`, for an easing that is only a function. */
|
|
2
|
+
const SPAN = 1e-4;
|
|
3
|
+
/**
|
|
4
|
+
* Whether an evaluation wants a tween's velocity, which costs two more reads of its easing. Only
|
|
5
|
+
* `read` asks for it; a mix and a retarget never use it.
|
|
6
|
+
*/
|
|
7
|
+
let slope = false;
|
|
8
|
+
/** The last tween sample's time, curve and length, and the share of the way it had left to go. */
|
|
9
|
+
const memo = { u: Number.NaN, ease: undefined, left: 0 };
|
|
10
|
+
/** Turns the velocity `eased` works out on or off. */
|
|
11
|
+
export function sloped(on) {
|
|
12
|
+
slope = on;
|
|
13
|
+
}
|
|
14
|
+
/** How far through a stretch released at `at` and lasting `ms` voice time `t` is, from 0. */
|
|
15
|
+
export function progress(t, at, ms) {
|
|
16
|
+
return Math.max(0, t - at) / ms;
|
|
17
|
+
}
|
|
18
|
+
/** The share of a tween's way left to go at `u`, 0 once it has arrived. */
|
|
19
|
+
export function left(ease, u) {
|
|
20
|
+
// Subjects released together share `u`, so a frame reads a bezier once, not once each.
|
|
21
|
+
if (u !== memo.u || ease !== memo.ease) {
|
|
22
|
+
memo.u = u;
|
|
23
|
+
memo.ease = ease;
|
|
24
|
+
memo.left = u >= 1 ? 0 : 1 - ease(u);
|
|
25
|
+
}
|
|
26
|
+
return memo.left;
|
|
27
|
+
}
|
|
28
|
+
/** An axis of a tween from `x0` to `goal` with `share` of the way left. */
|
|
29
|
+
export function between(x0, goal, share) {
|
|
30
|
+
return share === 0 ? goal : goal + (x0 - goal) * share;
|
|
31
|
+
}
|
|
32
|
+
/** A tween's stretch at `u` into `xo` and `vo`: true once it has arrived. */
|
|
33
|
+
export function eased(ease, n, u, ms, x0, x, to, g, xo, vo) {
|
|
34
|
+
const share = left(ease, u);
|
|
35
|
+
let rate = 0;
|
|
36
|
+
if (slope && u < 1) {
|
|
37
|
+
const lo = Math.max(0, u - SPAN);
|
|
38
|
+
const hi = Math.min(1, u + SPAN);
|
|
39
|
+
rate = ((ease(hi) - ease(lo)) / (hi - lo)) * (1000 / ms);
|
|
40
|
+
}
|
|
41
|
+
for (let i = 0; i < n; i++) {
|
|
42
|
+
const a = x0[x + i];
|
|
43
|
+
const goal = to[g + i];
|
|
44
|
+
xo[i] = between(a, goal, share);
|
|
45
|
+
vo[i] = -(a - goal) * rate;
|
|
46
|
+
}
|
|
47
|
+
return share === 0;
|
|
48
|
+
}
|