@msb235/blits 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.md +3 -3
  3. package/dist/ahead.d.ts +26 -0
  4. package/dist/ahead.js +264 -0
  5. package/dist/around.d.ts +11 -0
  6. package/dist/around.js +32 -0
  7. package/dist/bare.js +15 -7
  8. package/dist/blank.d.ts +10 -0
  9. package/dist/blank.js +26 -0
  10. package/dist/blend.d.ts +2 -1
  11. package/dist/blend.js +1 -6
  12. package/dist/bound.d.ts +70 -0
  13. package/dist/bound.js +351 -0
  14. package/dist/chain.d.ts +2 -1
  15. package/dist/chain.js +7 -5
  16. package/dist/changes.d.ts +24 -0
  17. package/dist/changes.js +189 -0
  18. package/dist/channels.d.ts +39 -13
  19. package/dist/channels.js +14 -5
  20. package/dist/color.d.ts +12 -10
  21. package/dist/color.js +25 -25
  22. package/dist/columns.js +7 -3
  23. package/dist/contribution.d.ts +30 -0
  24. package/dist/contribution.js +374 -0
  25. package/dist/copyout.d.ts +10 -0
  26. package/dist/copyout.js +69 -24
  27. package/dist/crowd.d.ts +8 -2
  28. package/dist/crowd.js +4 -5
  29. package/dist/cue.d.ts +8 -1
  30. package/dist/cue.js +39 -13
  31. package/dist/cut.d.ts +8 -0
  32. package/dist/cut.js +4 -0
  33. package/dist/drop.d.ts +9 -0
  34. package/dist/drop.js +84 -0
  35. package/dist/due.d.ts +24 -5
  36. package/dist/due.js +113 -33
  37. package/dist/easing.d.ts +4 -4
  38. package/dist/easing.js +3 -3
  39. package/dist/everyone.d.ts +3 -2
  40. package/dist/everyone.js +3 -3
  41. package/dist/fade.d.ts +2 -1
  42. package/dist/fade.js +2 -1
  43. package/dist/fill.d.ts +3 -2
  44. package/dist/fill.js +51 -19
  45. package/dist/fit.d.ts +44 -26
  46. package/dist/fit.js +10 -9
  47. package/dist/fold.d.ts +4 -37
  48. package/dist/fold.js +5 -513
  49. package/dist/gather.d.ts +12 -7
  50. package/dist/gather.js +179 -44
  51. package/dist/gone.js +2 -2
  52. package/dist/grid.d.ts +47 -0
  53. package/dist/grid.js +247 -0
  54. package/dist/handle.d.ts +2 -0
  55. package/dist/handle.js +14 -8
  56. package/dist/held.d.ts +2 -1
  57. package/dist/history.d.ts +6 -5
  58. package/dist/history.js +7 -9
  59. package/dist/hosts.js +9 -15
  60. package/dist/index.d.ts +5 -4
  61. package/dist/keyfill.d.ts +1 -1
  62. package/dist/keyfill.js +5 -3
  63. package/dist/keyrows.d.ts +12 -0
  64. package/dist/keyrows.js +99 -12
  65. package/dist/lane.d.ts +36 -6
  66. package/dist/lane.js +32 -1
  67. package/dist/lanes.d.ts +23 -8
  68. package/dist/lanes.js +29 -8
  69. package/dist/leavings.d.ts +2 -2
  70. package/dist/leavings.js +1 -1
  71. package/dist/lives.d.ts +47 -0
  72. package/dist/lives.js +180 -0
  73. package/dist/meet.d.ts +2 -2
  74. package/dist/meet.js +90 -4
  75. package/dist/mixer.d.ts +54 -36
  76. package/dist/mixer.js +53 -171
  77. package/dist/motion.d.ts +14 -118
  78. package/dist/motion.js +16 -8
  79. package/dist/motions.d.ts +62 -155
  80. package/dist/motions.js +56 -370
  81. package/dist/moved.d.ts +1 -1
  82. package/dist/moved.js +16 -7
  83. package/dist/named.d.ts +0 -1
  84. package/dist/named.js +20 -2
  85. package/dist/numbers.d.ts +2 -0
  86. package/dist/numbers.js +4 -0
  87. package/dist/owed.d.ts +2 -0
  88. package/dist/owed.js +4 -0
  89. package/dist/pack.d.ts +2 -1
  90. package/dist/pack.js +2 -3
  91. package/dist/patch.d.ts +7 -3
  92. package/dist/patch.js +6 -2
  93. package/dist/places.d.ts +53 -0
  94. package/dist/places.js +171 -0
  95. package/dist/plot.d.ts +12 -0
  96. package/dist/plot.js +52 -0
  97. package/dist/project.d.ts +4 -4
  98. package/dist/project.js +9 -212
  99. package/dist/pull.js +11 -8
  100. package/dist/qualify.js +84 -21
  101. package/dist/reading.d.ts +6 -0
  102. package/dist/reading.js +5 -0
  103. package/dist/record.d.ts +5 -1
  104. package/dist/record.js +3 -2
  105. package/dist/relink.d.ts +1 -1
  106. package/dist/restored.d.ts +2 -2
  107. package/dist/restored.js +1 -1
  108. package/dist/rests.d.ts +9 -0
  109. package/dist/rests.js +76 -0
  110. package/dist/revive.d.ts +3 -2
  111. package/dist/revive.js +2 -2
  112. package/dist/{locus.d.ts → role.d.ts} +10 -9
  113. package/dist/{locus.js → role.js} +3 -3
  114. package/dist/roles.d.ts +10 -0
  115. package/dist/roles.js +158 -0
  116. package/dist/roster.js +3 -3
  117. package/dist/rotation.d.ts +1 -1
  118. package/dist/rotation.js +1 -1
  119. package/dist/rows.js +1 -1
  120. package/dist/sample.d.ts +2 -2
  121. package/dist/sample.js +33 -7
  122. package/dist/seek.js +5 -5
  123. package/dist/setting.d.ts +27 -0
  124. package/dist/setting.js +55 -0
  125. package/dist/shared.d.ts +1 -1
  126. package/dist/shared.js +1 -1
  127. package/dist/signals.d.ts +64 -32
  128. package/dist/signals.js +20 -18
  129. package/dist/stack.d.ts +5 -5
  130. package/dist/stack.js +5 -5
  131. package/dist/standing.d.ts +2 -1
  132. package/dist/standing.js +3 -2
  133. package/dist/store.d.ts +9 -0
  134. package/dist/store.js +24 -0
  135. package/dist/strays.d.ts +2 -1
  136. package/dist/strays.js +20 -13
  137. package/dist/stretch.d.ts +112 -0
  138. package/dist/stretch.js +9 -0
  139. package/dist/subject.d.ts +142 -0
  140. package/dist/subject.js +1 -0
  141. package/dist/tape.d.ts +9 -5
  142. package/dist/tape.js +5 -1
  143. package/dist/then.d.ts +9 -0
  144. package/dist/then.js +57 -0
  145. package/dist/ticker.d.ts +4 -4
  146. package/dist/transport.d.ts +0 -8
  147. package/dist/transport.js +0 -4
  148. package/dist/turns.d.ts +4 -3
  149. package/dist/turns.js +4 -3
  150. package/dist/types/arc.d.ts +12 -11
  151. package/dist/types/channel.d.ts +12 -8
  152. package/dist/types/history.d.ts +35 -19
  153. package/dist/types/mix.d.ts +222 -163
  154. package/dist/types/motion.d.ts +151 -0
  155. package/dist/types/motion.js +1 -0
  156. package/dist/types/patch.d.ts +67 -34
  157. package/dist/types/place.d.ts +51 -36
  158. package/dist/types/transport.d.ts +20 -18
  159. package/dist/types/voice.d.ts +136 -70
  160. package/dist/types/watch.d.ts +88 -40
  161. package/dist/types.d.ts +1 -0
  162. package/dist/voice.d.ts +7 -143
  163. package/dist/voice.js +28 -79
  164. package/dist/warn.d.ts +2 -0
  165. package/dist/warn.js +1 -1
  166. package/dist/watch.d.ts +2 -2
  167. package/dist/watch.js +5 -3
  168. package/dist/wave.d.ts +4 -3
  169. package/dist/wave.js +3 -2
  170. package/dist/weigh.d.ts +7 -1
  171. package/dist/weigh.js +27 -0
  172. package/docs/schema.html +212 -34
  173. package/package.json +2 -2
package/dist/voice.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Arc } from './arcs.js';
2
2
  import type { Blend } from './blend.js';
3
+ import type { Bound } from './bound.js';
3
4
  import { type Clock } from './clock.js';
4
5
  import { type Curve } from './easing.js';
5
6
  import type { Leavings } from './leavings.js';
@@ -8,151 +9,12 @@ import { Named } from './named.js';
8
9
  import type { Past } from './origin.js';
9
10
  import { Holding } from './owner.js';
10
11
  import { type Built, intosOf, type Scratch } from './patch.js';
11
- import type { Stamp } from './restored.js';
12
+ import { VoiceSetting } from './setting.js';
12
13
  import type { Fitting } from './spans.js';
13
14
  import { Store } from './store.js';
14
- import type { Anchor, Channel, FadeSpec, Handle, Patch, Setting, VoiceSpec } from './types.js';
15
- /**
16
- * A subject's record as it left a voice, faded out of it or dropped: the mix time and frame it
17
- * left at, and `sync` where it shows in its own frame: left in the frame's sync, or before anything
18
- * read the mix that frame.
19
- */
20
- export interface Left<I> {
21
- subject: I;
22
- at: number;
23
- seq: number;
24
- sync: boolean;
25
- held: Subject<unknown>;
26
- /**
27
- * The voice's fade of the subject as it stood on leaving, which a seek or read back to before
28
- * puts back: its ramp out, while running, or its having faded out.
29
- */
30
- ramp: Parting | null;
31
- parted: Parted | null;
32
- }
33
- /** A subject's ramp out of one voice: when it began, how long it runs, and the frame it was asked in. */
34
- export interface Parting {
35
- at: number;
36
- over: number;
37
- seq: number;
38
- }
39
- export interface Parted {
40
- at: number;
41
- seq: number;
42
- ramp: Parting | undefined;
43
- }
15
+ import type { Parted, Parting, Snap, Subject } from './subject.js';
16
+ import type { Anchor, Channel, FadeSpec, Handle, Patch, VoiceSpec } from './types.js';
44
17
  export declare const none: readonly string[];
45
- /**
46
- * What a copy of a record keeps for the seeks that put a record back from it: the copy's state
47
- * stepped on to `ticks`, as it stood near `at`, a moment one of them sought.
48
- */
49
- export interface Ahead<S> {
50
- /** The record the last seek put back, and the moment it sought, until that record steps. */
51
- put: Subject<S> | null;
52
- sought: number;
53
- /** The `since` of the record put back, which the steps in `state` were counted from. */
54
- since: number;
55
- at: number;
56
- ticks: number;
57
- /** Undefined until a record has stepped on from the copy. */
58
- state: S | undefined;
59
- /**
60
- * The state the record a seek replaced had stepped on to from the copy, at `leftTicks`; undefined
61
- * until one had.
62
- */
63
- leftTicks: number;
64
- left: S | undefined;
65
- }
66
- /** A copy of a record kept under `history`, by the mix time and frame it was taken at. */
67
- export interface Snap<S> {
68
- at: number;
69
- seq: number;
70
- held: Subject<S>;
71
- ahead?: Ahead<S>;
72
- /** Set where another record's list holds it too, so a seek cutting it from one lets go of it. */
73
- shared?: true;
74
- }
75
- /** Everything one voice holds for one subject, chained through the next voice that reaches it. */
76
- export interface Subject<S> {
77
- /** The voice's `target` answer, fixed on first sight. */
78
- reaches: boolean;
79
- /** The voice's `stagger` answer in voice ms, fixed on first sight. */
80
- delay: number;
81
- /** The mix timestamp this subject's delay ran out at, which its step grid counts from. */
82
- since: number;
83
- /** The mix timestamp its fade in counts from: `since`, or earlier for a voice freezing before. */
84
- shown: number;
85
- /** The weight this voice gave this subject the last frame it was probed, 0 where it gave none. */
86
- weight: number;
87
- /** Left at rest during a handover, so it stops contributing. */
88
- rested: boolean;
89
- /** The mix time it rested at, which a seek reads to know whether it had by then; NaN until it does. */
90
- restedAt: number;
91
- /**
92
- * Per written channel, whether a rest-less contribution is on: 0 unknown, 1 on, 2 off; null until
93
- * a rest-less channel asks.
94
- */
95
- bands: Uint8Array | null;
96
- state: S;
97
- /** The `now` this subject last caught up to, for this voice. */
98
- stepped: number;
99
- /** Under `stepMs`, how many intervals have run since `since`; `stepped` is where that lands. */
100
- ticks: number;
101
- /** The `now` this subject was last probed at, so twelve probes in a frame step once. */
102
- probed: number;
103
- /** The last delta computed this frame, handed back to a repeat probe unchanged. */
104
- delta: Record<string, unknown> | null;
105
- /** The phase `delta` was read at, to read it again once its voice's scratch has moved on. */
106
- phase: number;
107
- /** The voice's `seeks` when `delta` was read, so a seek later in the frame reads it again. */
108
- seeks: number;
109
- /** The voice's `rebuilds` when its state was last made, so a seek's rebuild reaches it once. */
110
- rebuilt: number;
111
- /** Its kept signal state was stepped on in one go from a copy history kept, by a seek. */
112
- copied: boolean;
113
- /** Stop 0 for a `from: 'current'` voice, taken the first frame this subject is seen. */
114
- base?: Record<string, unknown>;
115
- /** The pose's velocity per channel at that moment, units per ms, so the first segment leaves at it. */
116
- slope?: Record<string, unknown>;
117
- /** What `setting.keep` holds for this voice and subject, by owner; null until it holds any. */
118
- kept: Map<object, unknown> | null;
119
- /** Kept state a history store gave back, which each owner takes in turn on its first keep. */
120
- unkept?: unknown[];
121
- /** Under `history`, copies of this record by the mix time they were taken, oldest first. */
122
- snaps?: Snap<S>[];
123
- /** In a projection: where this record started from, and whether nothing known could be. */
124
- from?: number;
125
- unknown?: boolean;
126
- /** Under `history` with `inputs`, what an input weight signal read for this subject, when it changed. */
127
- inputs?: {
128
- at: number;
129
- seq: number;
130
- value: number;
131
- }[];
132
- /** In a projection reading back: that record, to read in place of the signal. */
133
- replay?: {
134
- at: number;
135
- value: number;
136
- }[];
137
- /** The voice this is the record of; null on a subject's stub. */
138
- voice: object | null;
139
- /** The next voice's record for this subject, in voice order, among those that reach it. */
140
- next: Subject<unknown> | null;
141
- /**
142
- * On the first record, which the mix keeps per subject so a probe makes one lookup: the `version`
143
- * the chain was linked at, and per locus, by channel slot, whether a rest-less contribution is on:
144
- * 0 never decided, 1 on, 2 off.
145
- */
146
- version: number;
147
- loci: Map<string, Uint8Array> | null;
148
- /** On the first record: the number lanes index this subject by, -1 without one. */
149
- slot: number;
150
- /** A motion voice's number for this subject in its patch, good while `freed` is the patch's own. */
151
- run: number;
152
- freed: number;
153
- /** In a voice's store once a seek has gone back, the stamp of the seek it was last put back or written at. */
154
- restored: Stamp | null;
155
- }
156
18
  /** A voice's clock, weight and fade from one mix time on, kept under `history`. */
157
19
  export interface Controls extends Clock {
158
20
  at: number;
@@ -301,7 +163,7 @@ export declare class Voice<I, O> {
301
163
  /** The clocks it ran on before its current one, where a subject's origin may lie; null for none. */
302
164
  clocks: Past[] | null;
303
165
  /** Reused for every call this voice makes, so it is valid only during the call. */
304
- readonly setting: Setting<unknown>;
166
+ readonly setting: VoiceSetting<I, O>;
305
167
  /** Every subject this voice has been asked about, so a handover knows when it is finished. */
306
168
  seen: number;
307
169
  /** The longest stagger of any subject seen, so a finite loop waits for the last of them. */
@@ -363,6 +225,8 @@ export declare class Voice<I, O> {
363
225
  unreachedBits: Uint32Array | null;
364
226
  /** Whether one record stands for every subject: see `shares` in `everyone.ts`. */
365
227
  sharing: boolean;
228
+ /** Where its signal is declared 0, its cue's `within`, so it is not read there: see `bound.ts`. */
229
+ bound: Bound<I, O> | null;
366
230
  /** The frames it has played sharing it. */
367
231
  shared: number;
368
232
  /** That record, null until a chain first asks and once the voice shares no more. */
package/dist/voice.js CHANGED
@@ -4,87 +4,33 @@ import { motionOf } from './motion.js';
4
4
  import { Named } from './named.js';
5
5
  import { childPlayed, Holding, mixTime, ownedElapsed, ownerPatch, ownerReading, turnedBack, } from './owner.js';
6
6
  import { builtOf, intosOf } from './patch.js';
7
- import { reading } from './reading.js';
8
- import { Store } from './store.js';
7
+ import { keeping, VoiceSetting } from './setting.js';
8
+ import { Filled, Store } from './store.js';
9
9
  import { warnOnce } from './warn.js';
10
10
  export const none = Object.freeze([]);
11
- /**
12
- * A voice's `setting.keep`, one per voice: a setting is valid only during its call, so the state
13
- * goes on the record of the subject being called for, `keepOn`, or on the voice before any is.
14
- */
15
- function keeping(voice) {
16
- return function keep(owner, init) {
17
- const held = voice.keepOn;
18
- let kept = held === null ? voice.ownKept : held.kept;
19
- if (kept === null) {
20
- kept = new Map();
21
- if (held === null)
22
- voice.ownKept = kept;
23
- else
24
- held.kept = kept;
25
- }
26
- if (kept.has(owner))
27
- return kept.get(owner);
28
- const unkept = held?.unkept;
29
- const made = unkept === undefined ? init() : unkept.shift();
30
- if (unkept?.length === 0 && held !== null)
31
- held.unkept = undefined;
32
- kept.set(owner, made);
33
- reading.kept++;
34
- return made;
35
- };
36
- }
37
- /**
38
- * A voice's setting. `keep` is made on first read: most patches keep no state, and a closure and
39
- * its context per voice cost a one-subject tween voice about 100 bytes.
40
- */
41
- class VoiceSetting {
42
- host;
43
- send;
44
- voice;
45
- timestamp = 0;
46
- dt = 0;
47
- elapsed = 0;
48
- pass = 0;
49
- weight = 0;
50
- state = undefined;
51
- kept = null;
52
- constructor(host, send, voice) {
53
- this.host = host;
54
- this.send = send;
55
- this.voice = voice;
56
- }
57
- get keep() {
58
- if (this.kept === null)
59
- this.kept = keeping(this.voice);
60
- return this.kept;
61
- }
11
+ const noSend = () => { };
12
+ /** By a mix's `slotOf`, the slots and lerps of a patch writing one channel, shared by its voices. */
13
+ const writings = new WeakMap();
14
+ function writing(writes, slotOf, channels) {
15
+ if (writes.length !== 1)
16
+ return written(writes, slotOf, channels);
17
+ let known = writings.get(slotOf);
18
+ if (known === undefined) {
19
+ known = new Map();
20
+ writings.set(slotOf, known);
21
+ }
22
+ const key = writes[0];
23
+ let found = known.get(key);
24
+ if (found === undefined) {
25
+ found = written(writes, slotOf, channels);
26
+ known.set(key, found);
27
+ }
28
+ return found;
62
29
  }
63
- /** A store that fills a missing entry from `make` on first ask. */
64
- class Filled extends Store {
65
- make;
66
- /** Keys deleted here, which are made afresh by whoever asks and never again by `make`. */
67
- gone = null;
68
- constructor(make) {
69
- super();
70
- this.make = make;
71
- }
72
- get(key) {
73
- let v = super.get(key);
74
- if (v === undefined && this.gone?.get(key) !== true) {
75
- v = this.make(key);
76
- if (v !== undefined)
77
- super.set(key, v);
78
- }
79
- return v;
80
- }
81
- delete(key) {
82
- super.delete(key);
83
- this.gone ??= new Store();
84
- this.gone.set(key, true);
85
- }
30
+ function written(writes, slotOf, channels) {
31
+ const slots = writes.map((k) => slotOf.get(k));
32
+ return { slots, lerps: slots.map((slot) => channels[slot].lerp) };
86
33
  }
87
- const noSend = () => { };
88
34
  export class Voice {
89
35
  id;
90
36
  spec;
@@ -251,6 +197,8 @@ export class Voice {
251
197
  unreachedBits = null;
252
198
  /** Whether one record stands for every subject: see `shares` in `everyone.ts`. */
253
199
  sharing = false;
200
+ /** Where its signal is declared 0, its cue's `within`, so it is not read there: see `bound.ts`. */
201
+ bound = null;
254
202
  /** The frames it has played sharing it. */
255
203
  shared = 0;
256
204
  /** That record, null until a chain first asks and once the voice shares no more. */
@@ -443,10 +391,11 @@ export class Voice {
443
391
  this.start = start;
444
392
  this.owner = owner;
445
393
  this.holding = patch === ownerPatch ? new Holding() : null;
446
- this.slots = patch.writes.map((k) => slotOf.get(k));
394
+ const wrote = writing(patch.writes, slotOf, channels);
395
+ this.slots = wrote.slots;
447
396
  this.named = spec.subjects ? new Named(spec.subjects) : null;
448
397
  this.built = patch.form === 'keys' && patch.keys ? builtOf(patch) : null;
449
- this.lerps = this.slots.map((slot) => channels[slot].lerp);
398
+ this.lerps = wrote.lerps;
450
399
  this.intos = this.built
451
400
  ? intosOf(this.built, this.slots.map((slot) => channels[slot]))
452
401
  : undefined;
package/dist/warn.d.ts CHANGED
@@ -1,2 +1,4 @@
1
+ /** Whether this is a production build: a bundler's `NODE_ENV`, or Node's; false where neither is. */
2
+ export declare function production(): boolean;
1
3
  /** Warns outside production, once for each `about`. */
2
4
  export declare function warnOnce(about: object, message: string): void;
package/dist/warn.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Whether this is a production build: a bundler's `NODE_ENV`, or Node's; false where neither is. */
2
- function production() {
2
+ export function production() {
3
3
  try {
4
4
  return process.env.NODE_ENV === 'production';
5
5
  }
package/dist/watch.d.ts CHANGED
@@ -2,8 +2,8 @@ import type { Mixer } from './mixer.js';
2
2
  import type { MixOptions, Registry } from './types.js';
3
3
  type Any = Mixer<unknown, unknown>;
4
4
  /**
5
- * Every mix made on the page, shared by every copy of blits loaded: what a debugger reads to find
6
- * them. See `Registry`.
5
+ * The registry a debugger reads to find every mix made on the page. It is shared by every copy of
6
+ * blits loaded. See `Registry`.
7
7
  *
8
8
  * @category mix
9
9
  */
package/dist/watch.js CHANGED
@@ -4,8 +4,8 @@ import { hostAhead } from './tape.js';
4
4
  const KEY = Symbol.for('@msb235/blits/watch/1');
5
5
  const slot = globalThis;
6
6
  /**
7
- * Every mix made on the page, shared by every copy of blits loaded: what a debugger reads to find
8
- * them. See `Registry`.
7
+ * The registry a debugger reads to find every mix made on the page. It is shared by every copy of
8
+ * blits loaded. See `Registry`.
9
9
  *
10
10
  * @category mix
11
11
  */
@@ -90,7 +90,9 @@ export function register(mix) {
90
90
  channels: mix.names,
91
91
  voice: (handle) => {
92
92
  const v = mix.cued.find((c) => c.handle === handle) ?? mix.gone.find((c) => c.handle === handle);
93
- return v === undefined ? undefined : { name: v.spec.name, tags: v.spec.tags ?? [] };
93
+ return v === undefined
94
+ ? undefined
95
+ : { name: v.spec.name, tags: v.spec.tags ?? [], within: v.bound?.area };
94
96
  },
95
97
  label: (subject) => labelOf(mix, subject),
96
98
  watch: (fn) => tap(mix, fn),
package/dist/wave.d.ts CHANGED
@@ -11,7 +11,7 @@ export type WaveShape = 'sine' | 'triangle' | 'saw' | 'square';
11
11
  * @category patch
12
12
  */
13
13
  export interface WaveOptions<O> {
14
- /** Default 'sine'. */
14
+ /** The wave's form: 'sine', 'triangle', 'saw' or 'square'. Default 'sine'. */
15
15
  shape?: WaveShape;
16
16
  /** Whole or fractional cycles per pass of the patch's duration. Default 1. */
17
17
  cycles?: number;
@@ -27,13 +27,14 @@ export interface WaveOptions<O> {
27
27
  kit?: Partial<Kit<O>>;
28
28
  }
29
29
  /**
30
- * The unit wave: -1..1 at `x` cycles, starting at 0 and rising (square: +1 for the first half).
30
+ * The unit wave's value at `x` cycles, from -1 to 1. It starts at 0 and rises (square: +1 for the
31
+ * first half).
31
32
  *
32
33
  * @category patch
33
34
  */
34
35
  export declare function waveAt(shape: WaveShape, x: number): number;
35
36
  /**
36
- * A periodic swing on each channel `depth` names, around its rest: an LFO for a bob, a sway or a
37
+ * A periodic swing on each channel `depth` names, around its rest. An LFO for a bob, a sway or a
37
38
  * pulse. An `fn` patch that keeps its options on `patch.wave`, for an engine reading the wave
38
39
  * rather than calling it.
39
40
  *
package/dist/wave.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { patch } from './patch.js';
2
2
  /**
3
- * The unit wave: -1..1 at `x` cycles, starting at 0 and rising (square: +1 for the first half).
3
+ * The unit wave's value at `x` cycles, from -1 to 1. It starts at 0 and rises (square: +1 for the
4
+ * first half).
4
5
  *
5
6
  * @category patch
6
7
  */
@@ -39,7 +40,7 @@ function planOf(opts) {
39
40
  return plan;
40
41
  }
41
42
  /**
42
- * A periodic swing on each channel `depth` names, around its rest: an LFO for a bob, a sway or a
43
+ * A periodic swing on each channel `depth` names, around its rest. An LFO for a bob, a sway or a
43
44
  * pulse. An `fn` patch that keeps its options on `patch.wave`, for an engine reading the wave
44
45
  * rather than calling it.
45
46
  *
package/dist/weigh.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Mixer } from './mixer.js';
2
- import type { Subject, Voice } from './voice.js';
2
+ import type { Subject } from './subject.js';
3
+ import type { Voice } from './voice.js';
3
4
  /**
4
5
  * Where `prime` reads its numbers in `Mixer.primed`: as arguments, each would be boxed wherever V8
5
6
  * does not inline the call, which turns on the order its compiles ran (bench/frame.mjs `glow`,
@@ -13,6 +14,11 @@ export declare const enum Primed {
13
14
  }
14
15
  /** Fills a voice's setting for a call to its patch, the weight aside, from `primed`. */
15
16
  export declare function prime<I, O>(this: Mixer<I, O>, voice: Voice<I, O>, held: Subject<unknown>): void;
17
+ /**
18
+ * `prime` for a lane's call, from `arg`: the per-lane fields only where the setting was not
19
+ * already filled under `Arg.MARK`, since nothing but the engine writes a setting.
20
+ */
21
+ export declare function primeLaned<I, O>(this: Mixer<I, O>, voice: Voice<I, O>, held: Subject<unknown>, arg: Float64Array): void;
16
22
  /** A gap as a `dt`: Infinity under reduced motion, and no more than `maxDt`. */
17
23
  export declare function capped<I, O>(this: Mixer<I, O>, gap: number): number;
18
24
  /** The earliest voice time a read may still ask for, for a subject delayed `delay`. */
package/dist/weigh.js CHANGED
@@ -17,8 +17,35 @@ export function prime(voice, held) {
17
17
  setting.pass = pass;
18
18
  setting.weight = 0;
19
19
  setting.state = held.state;
20
+ setting.mark = 0;
20
21
  voice.keepOn = held;
21
22
  }
23
+ /**
24
+ * `prime` for a lane's call, from `arg`: the per-lane fields only where the setting was not
25
+ * already filled under `Arg.MARK`, since nothing but the engine writes a setting.
26
+ */
27
+ export function primeLaned(voice, held, arg) {
28
+ const now = this.now;
29
+ const setting = voice.setting;
30
+ if (setting.mark !== arg[6 /* Arg.MARK */])
31
+ markSetting(setting, now, arg);
32
+ if (voice.patch.step === undefined && held.probed < now)
33
+ held.stepped = held.probed;
34
+ setting.dt = this.capped(now - held.stepped);
35
+ setting.weight = 0;
36
+ setting.state = held.state;
37
+ voice.keepOn = held;
38
+ }
39
+ /**
40
+ * `primeLaned`'s once-a-lane fields, kept out of it so it fits `one`'s inlining budget beside
41
+ * `signalled`, which otherwise took its place (`glow^` 4.5% faster, 2026-10-28).
42
+ */
43
+ function markSetting(setting, now, arg) {
44
+ setting.timestamp = now;
45
+ setting.elapsed = arg[1 /* Arg.ELAPSED */];
46
+ setting.pass = arg[3 /* Arg.PASS */];
47
+ setting.mark = arg[6 /* Arg.MARK */];
48
+ }
22
49
  /** A gap as a `dt`: Infinity under reduced motion, and no more than `maxDt`. */
23
50
  export function capped(gap) {
24
51
  const cap = this.opts.maxDt;