@msb235/blits 0.7.0 → 0.8.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 (156) hide show
  1. package/CHANGELOG.md +196 -0
  2. package/README.md +22 -4
  3. package/dist/book.js +4 -4
  4. package/dist/chain.d.ts +1 -1
  5. package/dist/chain.js +57 -54
  6. package/dist/channels.d.ts +26 -5
  7. package/dist/channels.js +12 -8
  8. package/dist/clock.d.ts +8 -1
  9. package/dist/clock.js +14 -3
  10. package/dist/clone.d.ts +3 -0
  11. package/dist/clone.js +16 -1
  12. package/dist/closed.d.ts +1 -1
  13. package/dist/closed.js +3 -2
  14. package/dist/color.d.ts +0 -11
  15. package/dist/color.js +4 -24
  16. package/dist/columns.js +0 -1
  17. package/dist/copyout.d.ts +6 -0
  18. package/dist/copyout.js +38 -0
  19. package/dist/crowd.d.ts +7 -5
  20. package/dist/crowd.js +32 -18
  21. package/dist/cue.d.ts +3 -1
  22. package/dist/cue.js +33 -20
  23. package/dist/departed.d.ts +34 -0
  24. package/dist/departed.js +73 -0
  25. package/dist/easing.d.ts +5 -0
  26. package/dist/easing.js +31 -2
  27. package/dist/everyone.d.ts +56 -0
  28. package/dist/everyone.js +221 -0
  29. package/dist/fade.d.ts +8 -1
  30. package/dist/fade.js +36 -6
  31. package/dist/fill.d.ts +22 -13
  32. package/dist/fill.js +104 -41
  33. package/dist/fit.js +2 -1
  34. package/dist/fold.d.ts +37 -0
  35. package/dist/fold.js +213 -28
  36. package/dist/gather.d.ts +15 -9
  37. package/dist/gather.js +60 -25
  38. package/dist/gone.d.ts +32 -0
  39. package/dist/gone.js +144 -0
  40. package/dist/handle.d.ts +16 -5
  41. package/dist/handle.js +56 -6
  42. package/dist/held.d.ts +8 -5
  43. package/dist/held.js +56 -58
  44. package/dist/history.d.ts +17 -13
  45. package/dist/history.js +49 -28
  46. package/dist/hosts.js +57 -9
  47. package/dist/index.d.ts +9 -4
  48. package/dist/index.js +5 -2
  49. package/dist/keyfill.d.ts +7 -0
  50. package/dist/keyfill.js +124 -0
  51. package/dist/keyrows.d.ts +1 -0
  52. package/dist/keyrows.js +1 -1
  53. package/dist/lane.d.ts +32 -2
  54. package/dist/lane.js +5 -0
  55. package/dist/lanes.d.ts +32 -8
  56. package/dist/lanes.js +69 -37
  57. package/dist/leavings.d.ts +26 -0
  58. package/dist/leavings.js +70 -0
  59. package/dist/meet.js +14 -8
  60. package/dist/mixer.d.ts +43 -7
  61. package/dist/mixer.js +60 -11
  62. package/dist/motion.d.ts +2 -0
  63. package/dist/motion.js +4 -1
  64. package/dist/motions.d.ts +22 -15
  65. package/dist/motions.js +40 -34
  66. package/dist/move.js +31 -20
  67. package/dist/moved.d.ts +11 -0
  68. package/dist/moved.js +29 -0
  69. package/dist/origin.d.ts +19 -0
  70. package/dist/origin.js +68 -0
  71. package/dist/owed.d.ts +4 -4
  72. package/dist/owed.js +8 -8
  73. package/dist/owner.d.ts +1 -1
  74. package/dist/owner.js +2 -2
  75. package/dist/pace.d.ts +13 -5
  76. package/dist/pace.js +21 -8
  77. package/dist/pack.d.ts +3 -1
  78. package/dist/pack.js +15 -24
  79. package/dist/paging.d.ts +8 -2
  80. package/dist/paging.js +44 -4
  81. package/dist/patch.d.ts +14 -9
  82. package/dist/patch.js +83 -21
  83. package/dist/place.js +188 -30
  84. package/dist/project.d.ts +12 -1
  85. package/dist/project.js +101 -83
  86. package/dist/pull.d.ts +2 -0
  87. package/dist/pull.js +8 -0
  88. package/dist/qualify.js +10 -2
  89. package/dist/reading.d.ts +5 -0
  90. package/dist/reading.js +5 -0
  91. package/dist/record.d.ts +9 -0
  92. package/dist/record.js +42 -0
  93. package/dist/relink.d.ts +11 -5
  94. package/dist/relink.js +7 -5
  95. package/dist/restored.d.ts +41 -0
  96. package/dist/restored.js +91 -0
  97. package/dist/revive.d.ts +10 -3
  98. package/dist/revive.js +31 -23
  99. package/dist/roster.d.ts +11 -0
  100. package/dist/roster.js +46 -0
  101. package/dist/rotation.d.ts +29 -0
  102. package/dist/rotation.js +91 -0
  103. package/dist/rows.d.ts +5 -5
  104. package/dist/rows.js +5 -5
  105. package/dist/sample.d.ts +3 -2
  106. package/dist/sample.js +32 -15
  107. package/dist/scored.d.ts +57 -0
  108. package/dist/scored.js +196 -0
  109. package/dist/seek.js +97 -114
  110. package/dist/shared.d.ts +6 -0
  111. package/dist/shared.js +15 -0
  112. package/dist/signals.d.ts +24 -3
  113. package/dist/signals.js +50 -11
  114. package/dist/spans.js +7 -0
  115. package/dist/stack.d.ts +11 -0
  116. package/dist/stack.js +47 -0
  117. package/dist/standing.d.ts +10 -0
  118. package/dist/standing.js +79 -0
  119. package/dist/store.d.ts +3 -3
  120. package/dist/store.js +3 -3
  121. package/dist/strays.js +3 -0
  122. package/dist/tape.d.ts +8 -5
  123. package/dist/tape.js +21 -13
  124. package/dist/testing.d.ts +35 -0
  125. package/dist/testing.js +116 -0
  126. package/dist/touch.d.ts +6 -0
  127. package/dist/touch.js +28 -0
  128. package/dist/transport.d.ts +53 -6
  129. package/dist/transport.js +102 -20
  130. package/dist/turns.d.ts +18 -0
  131. package/dist/turns.js +72 -0
  132. package/dist/tweened.js +1 -1
  133. package/dist/types/channel.d.ts +46 -0
  134. package/dist/types/channel.js +1 -0
  135. package/dist/types/history.d.ts +139 -0
  136. package/dist/types/history.js +1 -0
  137. package/dist/types/mix.d.ts +336 -0
  138. package/dist/types/mix.js +1 -0
  139. package/dist/types/patch.d.ts +187 -0
  140. package/dist/types/patch.js +1 -0
  141. package/dist/types/place.d.ts +157 -0
  142. package/dist/types/place.js +1 -0
  143. package/dist/types/transport.d.ts +71 -0
  144. package/dist/types/transport.js +1 -0
  145. package/dist/types/voice.d.ts +323 -0
  146. package/dist/types/voice.js +1 -0
  147. package/dist/types.d.ts +7 -1162
  148. package/dist/unpage.d.ts +2 -2
  149. package/dist/unpage.js +55 -25
  150. package/dist/voice.d.ts +92 -22
  151. package/dist/voice.js +108 -43
  152. package/dist/wave.d.ts +42 -0
  153. package/dist/wave.js +62 -0
  154. package/dist/weigh.js +1 -1
  155. package/docs/schema.html +42 -36
  156. package/package.json +8 -3
package/dist/lanes.js CHANGED
@@ -1,8 +1,9 @@
1
+ import { copy } from './copyout.js';
1
2
  import { row } from './crowd.js';
2
- import { call, fillAll, foldKeys, one, parting, readKeyed, reset, run, signalled, subjectAt, } from './fill.js';
3
- import { fold, foldDelta, foldInto, foldRun, gate, gather } from './gather.js';
3
+ import { call, fillAll, foldKeys, one, parting, readKeyed, reset, run, runEveryone, signalled, subjectAt, } from './fill.js';
4
+ import { fold, foldDelta, foldInto, foldRun, gate, gather, unplain } from './gather.js';
4
5
  import { meet, reach } from './meet.js';
5
- import { Numbers } from './numbers.js';
6
+ import { absent, Numbers } from './numbers.js';
6
7
  import { Owed } from './owed.js';
7
8
  import { requalify, retouch } from './qualify.js';
8
9
  import { reading } from './reading.js';
@@ -19,7 +20,7 @@ export class Lanes {
19
20
  /** The lanes over every subject that have started playing, by epoch. */
20
21
  dense = [];
21
22
  byId = new Map();
22
- /** The crowds of single-subject motion voices, one per channel, and which holds each voice. */
23
+ /** The crowds of single-subject voices, one per list of channels, and which holds each voice. */
23
24
  crowds = [];
24
25
  crowdOf = new Map();
25
26
  /** Whether two crowds share a channel, so their rows must interleave in voice order. */
@@ -29,13 +30,20 @@ export class Lanes {
29
30
  /** The lane and record `one` is folding, whose band state a rest-less channel reads. */
30
31
  folding = null;
31
32
  rec = null;
33
+ /** The numbers a fill's methods hand each other: see `Arg`. */
34
+ arg = new Float64Array(6 /* Arg.SIZE */);
32
35
  /** While a fill gathers a locus: that locus and the member gathering, where folds go instead. */
33
36
  into = null;
34
37
  intoId = 0;
35
38
  lawsByKey = new Map();
36
39
  lastLaw = null;
37
- /** The lanes the last `meet` gave a position, and whether it placed a crowd row. */
40
+ /**
41
+ * The lanes the last `meet` gave a position, the first `metN` of `met`, and whether it placed a
42
+ * crowd row. Counted, not cut to length: an array emptied by its length takes new room at its
43
+ * next push, about 150 B a subject met (the `swap` row, bench/allocs.mjs, 2026-10-09).
44
+ */
38
45
  met = [];
46
+ metN = 0;
39
47
  metCrowd = false;
40
48
  /** By subject number, the laned voices its probes fold on the general path this fill. */
41
49
  owed = new Owed();
@@ -95,8 +103,9 @@ export class Lanes {
95
103
  keeps = false;
96
104
  now = Number.NaN;
97
105
  filledAt = Number.NaN;
98
- /** `reading.moved` at the last fill, so a retarget or push between two probes refills. */
106
+ /** `reading.moved` and `reading.inputs` at the last fill: see `current`. */
99
107
  moved = 0;
108
+ inputs = 0;
100
109
  /** The `now` of the latest probe, and the probe count before its first, to tell a probe this frame. */
101
110
  frameAt = Number.NaN;
102
111
  frameProbes = 0;
@@ -233,13 +242,23 @@ export class Lanes {
233
242
  }
234
243
  /** Whether this frame's lanes are filled and nothing since asks `begin` to look again. */
235
244
  filled(now, version) {
245
+ return (this.frameAt === now &&
246
+ this.qualifiedVersion === version &&
247
+ this.touched.length === 0 &&
248
+ !this.filling &&
249
+ this.current(now, version));
250
+ }
251
+ /**
252
+ * Whether the last fill still stands: everything a fill reads that can change between two probes,
253
+ * each stamped by `fillAll`. The clock; the mix's version, which voices coming, going, starting
254
+ * and stopping move; a motion's retargets and pushes; and a `level` set. Whatever else can change
255
+ * between probes keeps its voice off lanes in `fits`.
256
+ */
257
+ current(now, version) {
236
258
  return (this.filledAt === now &&
237
- this.frameAt === now &&
238
259
  this.filledVersion === version &&
239
- this.qualifiedVersion === version &&
240
260
  this.moved === reading.moved &&
241
- this.touched.length === 0 &&
242
- !this.filling);
261
+ this.inputs === reading.inputs);
243
262
  }
244
263
  /**
245
264
  * What a probe does before its subject, once a frame's lanes are settled: qualifies and fills as
@@ -257,8 +276,9 @@ export class Lanes {
257
276
  }
258
277
  if (this.filling)
259
278
  return 0 /* Begin.GENERAL */;
260
- // The mix's version moves only when a voice over every subject comes, goes, starts or stops
261
- // waiting, each of which touches it, so a version past a qualify that stands is a set of touches.
279
+ // Past a qualify that stands, the mix's version moves when a voice over every subject comes,
280
+ // goes, starts or stops waiting, each of which touches it, or stops sharing one record, which
281
+ // moves no voice on or off a lane: so with voices touched it is a set of touches.
262
282
  if (this.qualifiedVersion !== version) {
263
283
  if (!Number.isNaN(this.qualifiedVersion) && this.touched.length > 0 && retouch(this))
264
284
  this.qualifiedVersion = version;
@@ -269,7 +289,7 @@ export class Lanes {
269
289
  requalify(this, version);
270
290
  if (this.laned.length === 0)
271
291
  return 0 /* Begin.GENERAL */;
272
- if (this.filledAt !== now || this.filledVersion !== version || this.moved !== reading.moved) {
292
+ if (!this.current(now, version)) {
273
293
  fillAll(this, now, version);
274
294
  // A patch call in that fill made kept state, which took its voice off its lane: fill without it.
275
295
  if (this.qualifiedVersion !== version) {
@@ -349,30 +369,6 @@ export class Lanes {
349
369
  }
350
370
  return true;
351
371
  }
352
- /** Writes a subject's laned values into a pose, each array channel into a new array. */
353
- copy(slot, pose) {
354
- const laned = this.laned;
355
- for (let c = 0; c < laned.length; c++) {
356
- const ch = laned[c];
357
- const axes = ch.axes;
358
- // Never `delete`: it drops a reused out object into dictionary mode for good.
359
- if (ch.op === 'last' && Number.isNaN(ch.values[slot * axes])) {
360
- if (pose[ch.name] !== undefined)
361
- pose[ch.name] = undefined;
362
- continue;
363
- }
364
- if (ch.scalar) {
365
- pose[ch.name] = ch.values[slot];
366
- continue;
367
- }
368
- // Made as the general path makes it, a copy of rest, so poses from either path share a shape.
369
- const arr = [...ch.start];
370
- const base = slot * axes;
371
- for (let a = 0; a < axes; a++)
372
- arr[a] = ch.values[base + a];
373
- pose[ch.name] = arr;
374
- }
375
- }
376
372
  forget(slot) {
377
373
  this.host.forgot(slot);
378
374
  this.live--;
@@ -417,6 +413,39 @@ export class Lanes {
417
413
  if (q >= 0)
418
414
  lane.fix(q);
419
415
  }
416
+ /**
417
+ * A voice that kept one record for every subject keeps one each from now on: each of its lane's
418
+ * positions takes the record `of` gives its subject.
419
+ */
420
+ rerecord(id, of) {
421
+ const lane = this.byId.get(id);
422
+ if (lane === undefined)
423
+ return;
424
+ for (let p = 0; p < lane.list.length; p++) {
425
+ const slot = lane.list[p];
426
+ const subject = this.subjectAt(slot);
427
+ if (subject !== absent)
428
+ lane.records[p] = of(subject, slot);
429
+ }
430
+ }
431
+ /** A voice's clock moved the `shown` of records it had already placed: copies them again. */
432
+ reshown(id) {
433
+ const c = this.crowdOf.get(id);
434
+ const p = c?.rowOf.get(id);
435
+ if (c !== undefined && p !== undefined) {
436
+ const held = c.records[p];
437
+ if (held !== undefined)
438
+ c.data[p * 8 /* Row.STRIDE */ + 1 /* Row.SINCE */] = held.shown;
439
+ }
440
+ const lane = this.byId.get(id);
441
+ if (lane === undefined)
442
+ return;
443
+ for (let q = 0; q < lane.list.length; q++) {
444
+ const held = lane.records[q];
445
+ if (held !== undefined)
446
+ lane.data[q * 8 /* Row.STRIDE */ + 1 /* Row.SINCE */] = held.shown;
447
+ }
448
+ }
420
449
  /** Something on a voice changed: a crowd copies it again at the next fill. */
421
450
  voiceChanged(id) {
422
451
  const c = this.crowdOf.get(id);
@@ -430,12 +459,14 @@ export class Lanes {
430
459
  // A fill's per-subject path is methods, installed here from the modules that own them: as
431
460
  // functions called directly they made fills 5-8% slower (bench/ab.sh on teitou, 2026-10-05).
432
461
  const methods = {
462
+ copy,
433
463
  row,
434
464
  signalled,
435
465
  parting,
436
466
  subjectAt,
437
467
  reset,
438
468
  run,
469
+ runEveryone,
439
470
  one,
440
471
  foldKeys,
441
472
  readKeyed,
@@ -446,6 +477,7 @@ const methods = {
446
477
  foldRun,
447
478
  foldInto,
448
479
  gate,
480
+ unplain,
449
481
  };
450
482
  for (const [name, value] of Object.entries(methods))
451
483
  Object.defineProperty(Lanes.prototype, name, { value, writable: true, configurable: true });
@@ -0,0 +1,26 @@
1
+ import { type Cut } from './transport.js';
2
+ import type { Left, Subject } from './voice.js';
3
+ /**
4
+ * Under history, the records subjects left a voice with, while a seek or a read back may reach
5
+ * them: in the order they left, the oldest let go of from the front, and each subject's found
6
+ * without looking through the others'.
7
+ */
8
+ export declare class Leavings<I> {
9
+ private list;
10
+ /** How many at the front of `list` have been let go of, cleared out once they are half of it. */
11
+ private head;
12
+ private readonly by;
13
+ static from<I>(entries: readonly Left<I>[]): Leavings<I> | null;
14
+ push(e: Left<I>): void;
15
+ /**
16
+ * Lets go of every entry that left before `reach`, handing each to `out` first. They are at the
17
+ * front: entries are in the order they left, and mix time does not run back along it.
18
+ */
19
+ expire(reach: number, out: ((e: Left<I>) => void) | null): void;
20
+ /** The record `subject` had at `cut` and left with after it, if it left after `cut`. */
21
+ at(subject: I, cut: Cut): Subject<unknown> | undefined;
22
+ /** Each time `subject` left, oldest first. */
23
+ of(subject: I): readonly Left<I>[];
24
+ /** Every entry, oldest first. */
25
+ all(): readonly Left<I>[];
26
+ }
@@ -0,0 +1,70 @@
1
+ import { Store } from './store.js';
2
+ import { within } from './transport.js';
3
+ /**
4
+ * Under history, the records subjects left a voice with, while a seek or a read back may reach
5
+ * them: in the order they left, the oldest let go of from the front, and each subject's found
6
+ * without looking through the others'.
7
+ */
8
+ export class Leavings {
9
+ list = [];
10
+ /** How many at the front of `list` have been let go of, cleared out once they are half of it. */
11
+ head = 0;
12
+ by = new Store();
13
+ static from(entries) {
14
+ if (entries.length === 0)
15
+ return null;
16
+ const out = new Leavings();
17
+ for (const e of entries)
18
+ out.push(e);
19
+ return out;
20
+ }
21
+ push(e) {
22
+ this.list.push(e);
23
+ const own = this.by.get(e.subject);
24
+ if (own === undefined)
25
+ this.by.set(e.subject, [e]);
26
+ else
27
+ own.push(e);
28
+ }
29
+ /**
30
+ * Lets go of every entry that left before `reach`, handing each to `out` first. They are at the
31
+ * front: entries are in the order they left, and mix time does not run back along it.
32
+ */
33
+ expire(reach, out) {
34
+ const list = this.list;
35
+ let head = this.head;
36
+ while (head < list.length && !(list[head].at >= reach)) {
37
+ const e = list[head++];
38
+ if (out !== null)
39
+ out(e);
40
+ const own = this.by.get(e.subject);
41
+ if (own.length === 1)
42
+ this.by.delete(e.subject);
43
+ else
44
+ own.shift();
45
+ }
46
+ this.head = head;
47
+ if (head >= 32 && head * 2 >= list.length) {
48
+ this.list = list.slice(head);
49
+ this.head = 0;
50
+ }
51
+ }
52
+ /** The record `subject` had at `cut` and left with after it, if it left after `cut`. */
53
+ at(subject, cut) {
54
+ const own = this.by.get(subject);
55
+ if (own === undefined)
56
+ return undefined;
57
+ for (const e of own)
58
+ if (!within(cut, e.seq, e.sync))
59
+ return e.held;
60
+ return undefined;
61
+ }
62
+ /** Each time `subject` left, oldest first. */
63
+ of(subject) {
64
+ return this.by.get(subject) ?? [];
65
+ }
66
+ /** Every entry, oldest first. */
67
+ all() {
68
+ return this.head === 0 ? this.list : this.list.slice(this.head);
69
+ }
70
+ }
package/dist/meet.js CHANGED
@@ -8,21 +8,27 @@ export function owable(lanes, slot) {
8
8
  if (lanes.metCrowd || lanes.owes(slot))
9
9
  return false;
10
10
  // Subjects meeting the same lanes in one fill get the same answer, and a list is kept only once true.
11
- if (lanes.owed.last(lanes.met))
12
- return true;
13
11
  const met = lanes.met;
12
+ const n = lanes.metN;
13
+ if (lanes.owed.last(met, n))
14
+ return true;
14
15
  let other = Number.NEGATIVE_INFINITY;
15
16
  for (const lane of lanes.lanes) {
16
17
  const id = lane.voice.id;
17
- if (id > other && !met.includes(id))
18
+ if (id <= other)
19
+ continue;
20
+ const at = met.indexOf(id);
21
+ if (at < 0 || at >= n)
18
22
  other = id;
19
23
  }
20
24
  for (const c of lanes.crowds)
21
25
  if (c.size > 0)
22
26
  other = Math.max(other, c.hot[(c.size - 1) * c.stride + 7 /* Hot.ID */]);
23
- for (const id of met)
27
+ for (let i = 0; i < n; i++) {
28
+ const id = met[i];
24
29
  if (id <= other || lanes.byId.get(id).group !== null)
25
30
  return false;
31
+ }
26
32
  return true;
27
33
  }
28
34
  /**
@@ -35,7 +41,7 @@ export function meet(lanes, slot, subject, head, lane) {
35
41
  const from = seen < 0 ? -1 - seen : seen;
36
42
  lanes.per[slot * 6 /* Per.SLOT */ + 1 /* Per.SEEN */] = lanes.epochs;
37
43
  let met = false;
38
- lanes.met.length = 0;
44
+ lanes.metN = 0;
39
45
  lanes.metCrowd = false;
40
46
  const dense = lanes.dense;
41
47
  for (let i = dense.length - 1; i >= 0; i--) {
@@ -50,7 +56,7 @@ export function meet(lanes, slot, subject, head, lane) {
50
56
  lane.add(slot, held);
51
57
  if (lane.idle)
52
58
  reach(lanes, slot, 1);
53
- lanes.met.push(lane.voice.id);
59
+ lanes.met[lanes.metN++] = lane.voice.id;
54
60
  met = true;
55
61
  }
56
62
  // `open` marks every subject a voice naming it starts on, so an unmarked one has none to meet.
@@ -73,7 +79,7 @@ export function meet(lanes, slot, subject, head, lane) {
73
79
  lane.add(slot, held);
74
80
  if (lane.idle)
75
81
  reach(lanes, slot, 1);
76
- lanes.met.push(voice.id);
82
+ lanes.met[lanes.metN++] = voice.id;
77
83
  met = true;
78
84
  }
79
85
  if (!met)
@@ -83,7 +89,7 @@ export function meet(lanes, slot, subject, head, lane) {
83
89
  // otherwise it reads the general path all frame.
84
90
  const o = slot * 6 /* Per.SLOT */;
85
91
  if (lane && lanes.per[o + 2 /* Per.IDLE */] === 0 && owable(lanes, slot)) {
86
- lanes.owed.owe(slot, lanes.met);
92
+ lanes.owed.owe(slot, lanes.met, lanes.metN);
87
93
  return true;
88
94
  }
89
95
  lanes.per[o + 0 /* Per.FILLED */] = lanes.fills;
package/dist/mixer.d.ts CHANGED
@@ -2,9 +2,11 @@ import { blended, laneRead, shareKept } from './blend.js';
2
2
  import type { Book } from './book.js';
3
3
  import { aims, chain, linkable, relink } from './chain.js';
4
4
  import { type LerpInto } from './channels.js';
5
+ import { DepartedIndex } from './departed.js';
5
6
  import type { Due } from './due.js';
6
7
  import { parting } from './fade.js';
7
- import { apply, baseFor, clamp, contribution, fold, folded, foldLoci, foldWith, isRest, type Key, keyed, linked, owedBy, passes, read, slopeFor, tick } from './fold.js';
8
+ import { apply, baseFor, clamp, contribution, fold, foldDetour, folded, foldLoci, foldSharers, foldWith, isRest, type Key, keyed, linked, owedBy, passes, read, shared, slopeFor, tick } from './fold.js';
9
+ import { GoneIndex } from './gone.js';
8
10
  import type { HandleHost } from './handle.js';
9
11
  import { held, shownOf, sinceOf, unreachedOf } from './held.js';
10
12
  import { Lanes } from './lanes.js';
@@ -15,30 +17,46 @@ import { Keys } from './paging.js';
15
17
  import { keep } from './pull.js';
16
18
  import { Steps } from './relink.js';
17
19
  import { Outs } from './revive.js';
20
+ import { ScoreIndex } from './scored.js';
18
21
  import { Fitting } from './spans.js';
19
22
  import { Store } from './store.js';
20
23
  import { type Announced, Transport } from './transport.js';
21
24
  import type { Booker, BookOptions, Channel, Columns, Engine, Handle, Kit, Marked, Mix, MixOptions, OwnerSpec, Patch, Projection, Sent, Signal, SpanHandle, SpanSpec, Tape, VoiceSpec } from './types.js';
22
25
  import { type Subject, type Voice } from './voice.js';
23
26
  import { base, capped, fadeOf, horizonFor, ownedBy, ownerBase, prime, weigh, weighOwned } from './weigh.js';
27
+ /**
28
+ * What a mix takes where its options say nothing. Not exported from the package: the suite turns
29
+ * `lanes` off to run every test on the general path, which is what makes each one an equivalence check.
30
+ */
31
+ export declare const defaults: {
32
+ lanes: boolean;
33
+ };
24
34
  export declare class Mixer<I, O> implements Mix<I, O> {
25
35
  readonly kit: Kit<O>;
26
36
  readonly opts: MixOptions;
27
37
  cued: Voice<I, O>[];
28
38
  /** Under `history`, voices that have left but that a read back may still reach. */
29
39
  gone: Voice<I, O>[];
40
+ goneIx: GoneIndex<I, O>;
41
+ scored: ScoreIndex<I, O>;
30
42
  /** Set on a projection's own mixer: it sends nothing, keeps no history, and reads without committing. */
31
43
  projecting: boolean;
32
44
  /** Set on a projection reading back: a subject it has nothing on starts from its voice's start. */
33
45
  backward: boolean;
34
46
  /** True during a sync, so a control change it makes is recorded as showing in that frame. */
35
47
  moving: boolean;
48
+ /**
49
+ * Whether a probe or pull has read the mix since its clock last moved. A control change made
50
+ * before that shows in this frame live, so it is recorded as showing in it.
51
+ */
52
+ looked: boolean;
36
53
  /**
37
54
  * Under `history` with `inputs`, the host fields patches read, copied each frame they changed. In
38
55
  * a projection reading back, the copy in force then.
39
56
  */
40
57
  hostLog: {
41
58
  at: number;
59
+ seq: number;
42
60
  fields: Record<string, unknown>;
43
61
  }[];
44
62
  hostThen: {
@@ -58,20 +76,23 @@ export declare class Mixer<I, O> implements Mix<I, O> {
58
76
  /** Taken off its transport, so it takes no more calls until a seek puts it back. */
59
77
  dropped: boolean;
60
78
  readonly name: string | undefined;
61
- /** This mix's frame among every mix's: moved by a sync, and by a control change or drop within one. */
79
+ /**
80
+ * This mix's frame among every mix's: moved by a sync or seek, and by a control change, drop,
81
+ * or touch within one.
82
+ */
62
83
  frame: number;
63
84
  /** Pending voices whose start the host gave, by its host time, kept where the rate puts it. */
64
85
  pins: Map<Voice<I, O>, number> | null;
65
86
  wantsPose: boolean;
66
87
  /** The pose `pull` folds a subject into where it cannot read straight from the lanes. */
67
88
  scratch: O | undefined;
68
- /** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
69
89
  /** Live voices by the earliest mix time `moveTo` would change each, a binary heap. */
70
90
  due: Due<I, O>[];
71
91
  /** Voices retired since `moveTo` last pruned them, in the order they retired. */
72
92
  retired: Voice<I, O>[];
73
93
  /** Visit every voice each sync, as before the due queue; for tests that compare the two. */
74
94
  walkAll: boolean;
95
+ /** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
75
96
  pulled: I[];
76
97
  pulledHeads: (Subject<unknown> | undefined)[];
77
98
  /** Each remembered head's lane slot, and the `version` and `relinks` they were all current at. */
@@ -93,16 +114,18 @@ export declare class Mixer<I, O> implements Mix<I, O> {
93
114
  onWake(fn: () => void): () => void;
94
115
  /**
95
116
  * Per subject, the first record of the chain through every live voice that reaches it, or a stub
96
- * where none does. Relinked when `version` moves, which is whenever the list or a voice's pending
97
- * state changes.
117
+ * where none does. Relinked when `version` moves, or when a voice naming the subject marks its
118
+ * head stale: see `changed` in `chain.ts`.
98
119
  */
99
120
  chains: Store<I, Subject<unknown>>;
100
121
  version: number;
101
- readonly steps: Steps<Voice<I, O>>;
122
+ readonly steps: Steps<Voice<I, O>, I>;
102
123
  /** Per subject, the voices whose `subjects` name it, in voice order. */
103
124
  named: Store<I, Voice<I, O>[]>;
104
125
  /** Voices a subject has been faded out of, which `drop` looks in besides those that reach it. */
105
126
  readonly parters: Set<Voice<I, O>>;
127
+ /** What an anchor can still find of voices that left without history, or past its reach. */
128
+ readonly departed: DepartedIndex;
106
129
  /**
107
130
  * Motion patches that may hold state for a subject no voice still reaching it plays, which `drop`
108
131
  * frees besides those voices' own: per subject, a patch a voice naming it left while another
@@ -116,6 +139,15 @@ export declare class Mixer<I, O> implements Mix<I, O> {
116
139
  naming: number;
117
140
  /** The voices in the list that name no subjects, in voice order. */
118
141
  general: Voice<I, O>[];
142
+ /** Those of `general` that keep one record for every subject, in voice order: see `everyone.ts`. */
143
+ sharers: Voice<I, O>[];
144
+ /**
145
+ * Whether a voice stopped sharing this frame: a probe or pull under way then holds chains linked
146
+ * before it joined them, and takes each again.
147
+ */
148
+ unshared: boolean;
149
+ /** 0 where a fold is a walk of the chain: see `detour` in `everyone.ts`. */
150
+ detours: number;
119
151
  /** How many voices in the list carry a locus; with none, a fold allocates nothing. */
120
152
  loci: number;
121
153
  /** What every motion patch it plays asks for its voice's time, holding this mix weakly. */
@@ -212,6 +244,7 @@ export declare class Mixer<I, O> implements Mix<I, O> {
212
244
  over?: number;
213
245
  }): void;
214
246
  drop(subject: I): void;
247
+ touch(subject?: I): void;
215
248
  drain<E = unknown>(tag?: string): Sent<I, E>[];
216
249
  /** Voices whose stop 0 is mid-computation, so a fold for one cannot re-enter itself. */
217
250
  readonly folding: Set<number>;
@@ -221,7 +254,7 @@ export declare class Mixer<I, O> implements Mix<I, O> {
221
254
  * is first asked, when probes start writing it.
222
255
  */
223
256
  restStamps: Store<I, number> | null;
224
- /** What a probe's record of rest is good for: moved by a new frame, version or relink. */
257
+ /** What a probe's record of rest is good for: moved by a new frame, version, relink, or stir. */
225
258
  private restsEpoch;
226
259
  private restsFrame;
227
260
  private restsVersion;
@@ -239,6 +272,9 @@ declare const methods: {
239
272
  foldWith: typeof foldWith;
240
273
  owedBy: typeof owedBy;
241
274
  foldLoci: typeof foldLoci;
275
+ foldDetour: typeof foldDetour;
276
+ foldSharers: typeof foldSharers;
277
+ shared: typeof shared;
242
278
  read: typeof read;
243
279
  contribution: typeof contribution;
244
280
  keyed: typeof keyed;