@msb235/blits 0.0.0-stage → 0.1.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 +25 -0
- package/LICENSE +21 -0
- package/README.md +90 -2
- package/dist/channels.d.ts +54 -0
- package/dist/channels.js +131 -0
- package/dist/easing.d.ts +4 -0
- package/dist/easing.js +75 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/mixer.d.ts +13 -0
- package/dist/mixer.js +788 -0
- package/dist/patch.d.ts +75 -0
- package/dist/patch.js +149 -0
- package/dist/signals.d.ts +50 -0
- package/dist/signals.js +111 -0
- package/dist/store.d.ts +15 -0
- package/dist/store.js +33 -0
- package/dist/types.d.ts +328 -0
- package/dist/types.js +1 -0
- package/docs/schema.html +622 -0
- package/package.json +57 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
This package follows [semver](https://semver.org). Below 1.0.0, a breaking change bumps the minor
|
|
4
|
+
version and everything else the patch. Each release lists its changes as **Breaking**, **Added** and
|
|
5
|
+
**Fixed**, and the release workflow refuses a tag with no section here.
|
|
6
|
+
|
|
7
|
+
## 0.1.1
|
|
8
|
+
|
|
9
|
+
First release. 0.1.0 was never published: npm holds the number and will not take it. A mix folds concurrent effects into one value per subject per frame: each effect runs
|
|
10
|
+
on its own clock with its own state and weight, and the rules for combining them belong to the
|
|
11
|
+
channel being written rather than to the effect writing it.
|
|
12
|
+
|
|
13
|
+
What is here: the stock channels (`sum`, `mul`, `max`, `last`, `vec`, `hex`), both authoring forms
|
|
14
|
+
for a patch (a function of phase, or a list of keyframes), voices with rates, loops, stagger, fade
|
|
15
|
+
envelopes and loci, the five signals (`peak`, `slew`, `lag`, `level`, `gate`) with their state
|
|
16
|
+
kept per voice and subject, per-subject state that catches up by its own gap or, under `stepMs`, at a
|
|
17
|
+
fixed interval so it plays the same at any frame rate, events a patch sends for the host to `drain`,
|
|
18
|
+
`handle.weightOf` for reading a voice's weight per subject, the checks that let one package's
|
|
19
|
+
patches mix into another's (`Channel.kind`, `Patch.kit` and `Patch.reads` checked at `cue`, and
|
|
20
|
+
`tags` to drain one package's events), and the `Engine` seam behind `mix`.
|
|
21
|
+
|
|
22
|
+
[klieg](https://github.com/orochi235/klieg) composes its motion, its effects and its lighting on
|
|
23
|
+
this, which is where the arithmetic was proven: that port changed no number and moved no baseline.
|
|
24
|
+
|
|
25
|
+
Zero runtime dependencies. ESM only. The design is `docs/schema.html`, shipped alongside.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Baker
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,91 @@
|
|
|
1
|
-
#
|
|
1
|
+
# blits
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Concurrent effects, mixed. Each effect runs on its own clock with its own state and weight, and a
|
|
4
|
+
mix folds them into one value per subject per frame by rules that belong to the channel, not the
|
|
5
|
+
effect.
|
|
6
|
+
|
|
7
|
+
It is the thing klieg does three times over — motion, effects, lighting — and wod does once for
|
|
8
|
+
transitions, extracted so those repos, sherpa and magicsmoke can share one vocabulary and one
|
|
9
|
+
engine.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { hex, kit, max, mix, mul, patch, sum, vec } from '@msb235/blits';
|
|
13
|
+
|
|
14
|
+
// What a part of a sign can move on. The arithmetic lives here and nowhere else.
|
|
15
|
+
const PART = kit<PartPose>({
|
|
16
|
+
gain: mul(),
|
|
17
|
+
dark: max(),
|
|
18
|
+
position: vec(3, sum()),
|
|
19
|
+
color: hex(),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const flicker = patch<Part, PartPose>(
|
|
23
|
+
180,
|
|
24
|
+
(phase, part) => ({ gain: 0.2 + 0.8 * Math.abs(Math.sin(phase * Math.PI + part.seed)) }),
|
|
25
|
+
{ writes: ['gain'] },
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const m = mix<Part, PartPose>(PART);
|
|
29
|
+
const handle = m.cue({ patch: flicker, fade: { in: 300, out: 300 } });
|
|
30
|
+
|
|
31
|
+
// Once a frame: tell the mix what time it is, then ask for the parts you are about to draw.
|
|
32
|
+
function frame(timestamp: number) {
|
|
33
|
+
m.sync(timestamp);
|
|
34
|
+
for (const part of visible) apply(part, m.probe(part, scratch));
|
|
35
|
+
if (m.live) requestAnimationFrame(frame);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// A hidden tab gets no frames; say the time away should not count, or every fade finishes at once.
|
|
39
|
+
document.addEventListener('visibilitychange', () => document.hidden || m.rebase());
|
|
40
|
+
|
|
41
|
+
handle.fade({ over: 500 }); // the voice ramps out and leaves
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## The words
|
|
45
|
+
|
|
46
|
+
Ten of them carry the rest: **delta** (a partial record of channel values), **channel** (one field
|
|
47
|
+
with its own arithmetic), **kit** (the channel set for one kind of delta), **subject** (what is
|
|
48
|
+
driven), **patch** (a pure function of phase and a subject), **voice** (a patch with its own clock
|
|
49
|
+
and weight), **mix** (the live voices over one kit), **signal** (a 0..1 scalar from outside the
|
|
50
|
+
clock), **handle** (the live controls on one voice), **engine** (the implementation behind a mix).
|
|
51
|
+
|
|
52
|
+
The design — the full vocabulary, the channel table, the time model, blending, the engine seam, and
|
|
53
|
+
what is still open — is `docs/schema.html`, which ships in the package: open it from
|
|
54
|
+
`node_modules/@msb235/blits/`. The naming work behind it is
|
|
55
|
+
`docs/vocabulary.json`, which semanticore serves as a page.
|
|
56
|
+
That repo is private; the JSON stands on its own.
|
|
57
|
+
|
|
58
|
+
## The site
|
|
59
|
+
|
|
60
|
+
`site/` is a docs site with a live explainer for each word and the API reference, generated from the
|
|
61
|
+
doc comments in `src/`. It runs the working tree, not a build:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
npm run site # dev server on port 4880
|
|
65
|
+
npm run site:smoke # build, then load every page headless and fail on any error
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`.github/workflows/site.yml` deploys it to GitHub Pages. It runs only by hand until Pages is enabled
|
|
69
|
+
on the repo.
|
|
70
|
+
|
|
71
|
+
## Status
|
|
72
|
+
|
|
73
|
+
v0.1.0, and one real consumer: [klieg](https://github.com/orochi235/klieg) composes all three of
|
|
74
|
+
its systems — letter motion, part effects, and the environment a sign is lit by — on a mix each.
|
|
75
|
+
That port was an extraction rather than a rewrite, so it is also the evidence that the arithmetic
|
|
76
|
+
here is the arithmetic a working renderer already had: klieg's suite of 1974 cases and its
|
|
77
|
+
screenshot baselines came through it unchanged.
|
|
78
|
+
|
|
79
|
+
One thing the port sent back. klieg's three motion phases layer, so they cue as separate voices; a
|
|
80
|
+
`locus` folds its members through each channel's `lerp` instead, which is what a crossfade between
|
|
81
|
+
alternatives wants and is not the same number on a multiplicative channel. Reach for a locus when
|
|
82
|
+
one voice should replace another, not when both should be heard.
|
|
83
|
+
|
|
84
|
+
Zero runtime dependencies, ESM only, types included.
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
npm install
|
|
88
|
+
npm run check # lint, typecheck, test
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
MIT.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Channel, Kit } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Position axes, rotation, crawl, yaw, pitch, offset.
|
|
4
|
+
*
|
|
5
|
+
* @category channel
|
|
6
|
+
*/
|
|
7
|
+
export declare function sum(): Channel<number>;
|
|
8
|
+
/**
|
|
9
|
+
* Gain, scale, opacity, hold.
|
|
10
|
+
*
|
|
11
|
+
* @category channel
|
|
12
|
+
*/
|
|
13
|
+
export declare function mul(): Channel<number>;
|
|
14
|
+
/**
|
|
15
|
+
* Dark, aperture.
|
|
16
|
+
*
|
|
17
|
+
* @category channel
|
|
18
|
+
*/
|
|
19
|
+
export declare function max(): Channel<number>;
|
|
20
|
+
/**
|
|
21
|
+
* A channel with no rest: the last influence to pass wins, and a weight can only gate it. The
|
|
22
|
+
* default `lerp` steps at the midpoint, which is all a value with no arithmetic can promise; a
|
|
23
|
+
* consumer with a real interpolation passes its own, as `hex` does.
|
|
24
|
+
*
|
|
25
|
+
* @category channel
|
|
26
|
+
*/
|
|
27
|
+
export declare function last<V>(opts?: {
|
|
28
|
+
lerp?: (a: V, b: V, u: number) => V;
|
|
29
|
+
}): Channel<V>;
|
|
30
|
+
/**
|
|
31
|
+
* Vec3 position, premultiplied light: one channel's arithmetic applied down an axis list.
|
|
32
|
+
*
|
|
33
|
+
* @category channel
|
|
34
|
+
*/
|
|
35
|
+
export declare function vec(n: number, of: Channel<number>): Channel<number[]>;
|
|
36
|
+
/**
|
|
37
|
+
* sRGB, which is what klieg's light channel already assumes, so the port's arithmetic is
|
|
38
|
+
* unchanged. OKLCH reads better across hues and is the open question, not a second function.
|
|
39
|
+
*
|
|
40
|
+
* @category channel
|
|
41
|
+
*/
|
|
42
|
+
export declare function mixHex(a: number, b: number, u: number): number;
|
|
43
|
+
/**
|
|
44
|
+
* Color, as 0xrrggbb.
|
|
45
|
+
*
|
|
46
|
+
* @category channel
|
|
47
|
+
*/
|
|
48
|
+
export declare function hex(): Channel<number>;
|
|
49
|
+
/**
|
|
50
|
+
* A kit is plain data; this only fixes the type.
|
|
51
|
+
*
|
|
52
|
+
* @category channel
|
|
53
|
+
*/
|
|
54
|
+
export declare function kit<O>(channels: Kit<O>): Kit<O>;
|
package/dist/channels.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const mix = (a, b, u) => a + (b - a) * u;
|
|
2
|
+
/**
|
|
3
|
+
* Position axes, rotation, crawl, yaw, pitch, offset.
|
|
4
|
+
*
|
|
5
|
+
* @category channel
|
|
6
|
+
*/
|
|
7
|
+
export function sum() {
|
|
8
|
+
return {
|
|
9
|
+
kind: 'sum',
|
|
10
|
+
rest: 0,
|
|
11
|
+
merge: (a, b) => a + b,
|
|
12
|
+
scale: (v, w) => v * w,
|
|
13
|
+
lerp: mix,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Gain, scale, opacity, hold.
|
|
18
|
+
*
|
|
19
|
+
* @category channel
|
|
20
|
+
*/
|
|
21
|
+
export function mul() {
|
|
22
|
+
return {
|
|
23
|
+
kind: 'mul',
|
|
24
|
+
rest: 1,
|
|
25
|
+
merge: (a, b) => a * b,
|
|
26
|
+
scale: (v, w) => 1 + (v - 1) * w,
|
|
27
|
+
lerp: mix,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Dark, aperture.
|
|
32
|
+
*
|
|
33
|
+
* @category channel
|
|
34
|
+
*/
|
|
35
|
+
export function max() {
|
|
36
|
+
return {
|
|
37
|
+
kind: 'max',
|
|
38
|
+
rest: 0,
|
|
39
|
+
merge: (a, b) => (a > b ? a : b),
|
|
40
|
+
scale: (v, w) => v * w,
|
|
41
|
+
lerp: mix,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A channel with no rest: the last influence to pass wins, and a weight can only gate it. The
|
|
46
|
+
* default `lerp` steps at the midpoint, which is all a value with no arithmetic can promise; a
|
|
47
|
+
* consumer with a real interpolation passes its own, as `hex` does.
|
|
48
|
+
*
|
|
49
|
+
* @category channel
|
|
50
|
+
*/
|
|
51
|
+
export function last(opts) {
|
|
52
|
+
return {
|
|
53
|
+
// A lerp of its own is arithmetic the name cannot vouch for.
|
|
54
|
+
kind: opts?.lerp ? undefined : 'last',
|
|
55
|
+
merge: (_a, b) => b,
|
|
56
|
+
lerp: opts?.lerp ?? ((a, b, u) => (u < 0.5 ? a : b)),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Vec3 position, premultiplied light: one channel's arithmetic applied down an axis list.
|
|
61
|
+
*
|
|
62
|
+
* @category channel
|
|
63
|
+
*/
|
|
64
|
+
export function vec(n, of) {
|
|
65
|
+
const rest = of.rest === undefined ? undefined : new Array(n).fill(of.rest);
|
|
66
|
+
const scale = of.scale;
|
|
67
|
+
const fill = of.rest ?? 0;
|
|
68
|
+
return {
|
|
69
|
+
kind: of.kind === undefined ? undefined : `vec(${n}, ${of.kind})`,
|
|
70
|
+
rest,
|
|
71
|
+
merge: (a, b) => {
|
|
72
|
+
const out = new Array(n);
|
|
73
|
+
for (let i = 0; i < n; i++)
|
|
74
|
+
out[i] = of.merge(a[i] ?? fill, b[i] ?? fill);
|
|
75
|
+
return out;
|
|
76
|
+
},
|
|
77
|
+
scale: scale === undefined
|
|
78
|
+
? undefined
|
|
79
|
+
: (v, w) => {
|
|
80
|
+
const out = new Array(n);
|
|
81
|
+
for (let i = 0; i < n; i++)
|
|
82
|
+
out[i] = scale(v[i] ?? fill, w);
|
|
83
|
+
return out;
|
|
84
|
+
},
|
|
85
|
+
fold: scale === undefined
|
|
86
|
+
? undefined
|
|
87
|
+
: (into, v, w) => {
|
|
88
|
+
for (let i = 0; i < n; i++)
|
|
89
|
+
into[i] = of.merge(into[i] ?? fill, scale(v[i] ?? fill, w));
|
|
90
|
+
return into;
|
|
91
|
+
},
|
|
92
|
+
lerp: (a, b, u) => {
|
|
93
|
+
const out = new Array(n);
|
|
94
|
+
for (let i = 0; i < n; i++)
|
|
95
|
+
out[i] = of.lerp(a[i] ?? fill, b[i] ?? fill, u);
|
|
96
|
+
return out;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const clamp255 = (v) => (v < 0 ? 0 : v > 255 ? 255 : Math.round(v));
|
|
101
|
+
/**
|
|
102
|
+
* sRGB, which is what klieg's light channel already assumes, so the port's arithmetic is
|
|
103
|
+
* unchanged. OKLCH reads better across hues and is the open question, not a second function.
|
|
104
|
+
*
|
|
105
|
+
* @category channel
|
|
106
|
+
*/
|
|
107
|
+
export function mixHex(a, b, u) {
|
|
108
|
+
const ar = (a >> 16) & 0xff;
|
|
109
|
+
const ag = (a >> 8) & 0xff;
|
|
110
|
+
const ab = a & 0xff;
|
|
111
|
+
const br = (b >> 16) & 0xff;
|
|
112
|
+
const bg = (b >> 8) & 0xff;
|
|
113
|
+
const bb = b & 0xff;
|
|
114
|
+
return ((clamp255(mix(ar, br, u)) << 16) | (clamp255(mix(ag, bg, u)) << 8) | clamp255(mix(ab, bb, u)));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Color, as 0xrrggbb.
|
|
118
|
+
*
|
|
119
|
+
* @category channel
|
|
120
|
+
*/
|
|
121
|
+
export function hex() {
|
|
122
|
+
return { ...last({ lerp: mixHex }), kind: 'hex' };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* A kit is plain data; this only fixes the type.
|
|
126
|
+
*
|
|
127
|
+
* @category channel
|
|
128
|
+
*/
|
|
129
|
+
export function kit(channels) {
|
|
130
|
+
return channels;
|
|
131
|
+
}
|
package/dist/easing.d.ts
ADDED
package/dist/easing.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const linear = (u) => u;
|
|
2
|
+
/** A CSS `cubic-bezier`: solves x(t) = u for t, then reads y(t). */
|
|
3
|
+
function bezier(x1, y1, x2, y2) {
|
|
4
|
+
const cx = 3 * x1;
|
|
5
|
+
const bx = 3 * (x2 - x1) - cx;
|
|
6
|
+
const ax = 1 - cx - bx;
|
|
7
|
+
const cy = 3 * y1;
|
|
8
|
+
const by = 3 * (y2 - y1) - cy;
|
|
9
|
+
const ay = 1 - cy - by;
|
|
10
|
+
const x = (t) => ((ax * t + bx) * t + cx) * t;
|
|
11
|
+
const dx = (t) => (3 * ax * t + 2 * bx) * t + cx;
|
|
12
|
+
const y = (t) => ((ay * t + by) * t + cy) * t;
|
|
13
|
+
return (u) => {
|
|
14
|
+
if (u <= 0)
|
|
15
|
+
return 0;
|
|
16
|
+
if (u >= 1)
|
|
17
|
+
return 1;
|
|
18
|
+
let t = u;
|
|
19
|
+
for (let i = 0; i < 8; i++) {
|
|
20
|
+
const err = x(t) - u;
|
|
21
|
+
if (Math.abs(err) < 1e-7)
|
|
22
|
+
return y(t);
|
|
23
|
+
const d = dx(t);
|
|
24
|
+
if (Math.abs(d) < 1e-6)
|
|
25
|
+
break;
|
|
26
|
+
t -= err / d;
|
|
27
|
+
}
|
|
28
|
+
let lo = 0;
|
|
29
|
+
let hi = 1;
|
|
30
|
+
t = u;
|
|
31
|
+
while (hi - lo > 1e-7) {
|
|
32
|
+
if (x(t) < u)
|
|
33
|
+
lo = t;
|
|
34
|
+
else
|
|
35
|
+
hi = t;
|
|
36
|
+
t = (lo + hi) / 2;
|
|
37
|
+
}
|
|
38
|
+
return y(t);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const named = {
|
|
42
|
+
linear,
|
|
43
|
+
ease: bezier(0.25, 0.1, 0.25, 1),
|
|
44
|
+
'ease-in': bezier(0.42, 0, 1, 1),
|
|
45
|
+
'ease-out': bezier(0, 0, 0.58, 1),
|
|
46
|
+
'ease-in-out': bezier(0.42, 0, 0.58, 1),
|
|
47
|
+
};
|
|
48
|
+
const built = new WeakMap();
|
|
49
|
+
/** The function an easing names. Resolved once where a patch or voice is built, not per frame. */
|
|
50
|
+
export function curve(easing) {
|
|
51
|
+
if (typeof easing === 'function')
|
|
52
|
+
return easing;
|
|
53
|
+
if (typeof easing === 'string') {
|
|
54
|
+
const found = named[easing];
|
|
55
|
+
if (!found)
|
|
56
|
+
throw new Error(`blits: no easing named ${easing}`);
|
|
57
|
+
return found;
|
|
58
|
+
}
|
|
59
|
+
const held = built.get(easing);
|
|
60
|
+
if (held)
|
|
61
|
+
return held;
|
|
62
|
+
let made;
|
|
63
|
+
if ('bezier' in easing)
|
|
64
|
+
made = bezier(...easing.bezier);
|
|
65
|
+
else {
|
|
66
|
+
const n = easing.steps;
|
|
67
|
+
const start = easing.jump === 'start';
|
|
68
|
+
made = (u) => {
|
|
69
|
+
const c = u <= 0 ? 0 : u >= 1 ? 1 : u;
|
|
70
|
+
return (start ? Math.ceil(c * n) : Math.floor(c * n)) / n;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
built.set(easing, made);
|
|
74
|
+
return made;
|
|
75
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { hex, kit, last, max, mixHex, mul, sum, vec } from './channels.js';
|
|
2
|
+
export { mix, mixer } from './mixer.js';
|
|
3
|
+
export type { KeysOptions, PatchOptions } from './patch.js';
|
|
4
|
+
export { keys, patch } from './patch.js';
|
|
5
|
+
export { gate, lag, level, peak, slew } from './signals.js';
|
|
6
|
+
export type { Channel, Easing, Engine, FadeOptions, FadeSpec, Handle, Keyframe, Kit, Mix, MixOptions, Patch, Sent, Setting, Signal, VoiceSpec, } from './types.js';
|
package/dist/index.js
ADDED
package/dist/mixer.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Engine, Kit, Mix, MixOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The one that ships: both forms on the CPU, probed per subject on demand.
|
|
4
|
+
*
|
|
5
|
+
* @category engine
|
|
6
|
+
*/
|
|
7
|
+
export declare const mixer: Engine;
|
|
8
|
+
/**
|
|
9
|
+
* Makes a mix over a kit, on the engine the options name or the stock one.
|
|
10
|
+
*
|
|
11
|
+
* @category mix
|
|
12
|
+
*/
|
|
13
|
+
export declare function mix<I, O>(kit: Kit<O>, opts?: MixOptions): Mix<I, O>;
|