@msb235/blits 0.5.0 → 0.7.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 (99) hide show
  1. package/CHANGELOG.md +163 -0
  2. package/README.md +32 -8
  3. package/dist/bare.js +7 -1
  4. package/dist/book.d.ts +8 -1
  5. package/dist/book.js +35 -4
  6. package/dist/chain.d.ts +4 -3
  7. package/dist/chain.js +10 -6
  8. package/dist/channels.d.ts +12 -19
  9. package/dist/channels.js +18 -118
  10. package/dist/clock.d.ts +12 -5
  11. package/dist/clock.js +13 -5
  12. package/dist/closed.d.ts +15 -0
  13. package/dist/closed.js +144 -0
  14. package/dist/color.d.ts +61 -0
  15. package/dist/color.js +229 -0
  16. package/dist/columns.js +2 -1
  17. package/dist/crowd.d.ts +4 -4
  18. package/dist/crowd.js +11 -8
  19. package/dist/cue.d.ts +2 -0
  20. package/dist/cue.js +78 -27
  21. package/dist/due.js +5 -2
  22. package/dist/fade.d.ts +13 -0
  23. package/dist/fade.js +55 -4
  24. package/dist/fill.d.ts +1 -1
  25. package/dist/fill.js +17 -10
  26. package/dist/fit.d.ts +144 -0
  27. package/dist/fit.js +181 -0
  28. package/dist/fold.d.ts +3 -3
  29. package/dist/fold.js +25 -18
  30. package/dist/gather.d.ts +6 -0
  31. package/dist/gather.js +18 -0
  32. package/dist/handle.d.ts +27 -2
  33. package/dist/handle.js +60 -11
  34. package/dist/held.js +7 -3
  35. package/dist/history.d.ts +15 -2
  36. package/dist/history.js +54 -9
  37. package/dist/hosts.d.ts +2 -2
  38. package/dist/hosts.js +19 -6
  39. package/dist/index.d.ts +10 -2
  40. package/dist/index.js +6 -1
  41. package/dist/lane.d.ts +4 -4
  42. package/dist/lane.js +5 -5
  43. package/dist/lanes.d.ts +32 -9
  44. package/dist/lanes.js +53 -24
  45. package/dist/locus.d.ts +3 -3
  46. package/dist/locus.js +1 -1
  47. package/dist/marks.d.ts +3 -0
  48. package/dist/marks.js +81 -13
  49. package/dist/meet.d.ts +3 -2
  50. package/dist/meet.js +15 -3
  51. package/dist/mixer.d.ts +55 -35
  52. package/dist/mixer.js +173 -83
  53. package/dist/motion.d.ts +2 -199
  54. package/dist/motion.js +2 -652
  55. package/dist/motions.d.ts +266 -0
  56. package/dist/motions.js +724 -0
  57. package/dist/move.d.ts +1 -1
  58. package/dist/move.js +27 -11
  59. package/dist/owner.d.ts +2 -2
  60. package/dist/owner.js +5 -5
  61. package/dist/pace.d.ts +2 -0
  62. package/dist/pace.js +8 -0
  63. package/dist/pack.d.ts +31 -0
  64. package/dist/pack.js +65 -0
  65. package/dist/paging.d.ts +63 -0
  66. package/dist/paging.js +110 -0
  67. package/dist/patch.d.ts +3 -0
  68. package/dist/patch.js +2 -0
  69. package/dist/place.js +74 -25
  70. package/dist/project.d.ts +7 -4
  71. package/dist/project.js +117 -78
  72. package/dist/pull.js +4 -3
  73. package/dist/qualify.js +4 -2
  74. package/dist/revive.d.ts +58 -0
  75. package/dist/revive.js +158 -0
  76. package/dist/sample.d.ts +1 -1
  77. package/dist/sample.js +6 -1
  78. package/dist/seek.d.ts +3 -0
  79. package/dist/seek.js +311 -0
  80. package/dist/signals.d.ts +3 -2
  81. package/dist/signals.js +12 -6
  82. package/dist/spans.d.ts +29 -0
  83. package/dist/spans.js +165 -0
  84. package/dist/strays.d.ts +1 -1
  85. package/dist/strays.js +21 -0
  86. package/dist/tape.d.ts +21 -0
  87. package/dist/tape.js +65 -0
  88. package/dist/ticker.d.ts +73 -0
  89. package/dist/ticker.js +115 -0
  90. package/dist/transport.d.ts +121 -0
  91. package/dist/transport.js +271 -0
  92. package/dist/types.d.ts +427 -50
  93. package/dist/unpage.d.ts +8 -0
  94. package/dist/unpage.js +163 -0
  95. package/dist/voice.d.ts +78 -12
  96. package/dist/voice.js +126 -12
  97. package/dist/weigh.js +2 -2
  98. package/docs/schema.html +140 -48
  99. package/package.json +2 -1
package/dist/marks.js CHANGED
@@ -10,22 +10,52 @@ export function readingAt(mix, u) {
10
10
  }
11
11
  /** Every mark between two host timestamps, earliest first, with the order that tells each apart. */
12
12
  export function listed(mix, from, to) {
13
- const lo = from - mix.offset;
14
- const hi = to - mix.offset;
13
+ const out = voiceMarks(mix, from, to);
14
+ for (const a of announcedMarks(mix.transport, from, to))
15
+ if (a.score !== undefined || a.slot === mix.slot)
16
+ out.push(a.listed);
17
+ return sorted(out);
18
+ }
19
+ /** Every mark of every mix on a transport and every one announced on it, earliest first. */
20
+ export function listedAll(transport, from, to) {
21
+ const out = [];
22
+ for (const m of transport.members)
23
+ out.push(...voiceMarks(m, from, to));
24
+ for (const a of announcedMarks(transport, from, to))
25
+ out.push(a.listed);
26
+ return sorted(out);
27
+ }
28
+ function sorted(out) {
29
+ return out.sort((a, b) => a.timestamp - b.timestamp || a.order - b.order);
30
+ }
31
+ function announcedMarks(transport, from, to) {
32
+ const lo = from - transport.offset;
33
+ const hi = to - transport.offset;
15
34
  const out = [];
16
- for (const a of mix.announced)
35
+ for (const a of transport.announced)
17
36
  if (a.at >= lo && a.at <= hi)
18
37
  out.push({
19
- timestamp: a.at + mix.offset,
20
- mark: undefined,
21
- voice: undefined,
22
38
  score: a.score,
23
- name: a.name,
24
- tags: a.tags,
25
- order: a.order,
39
+ slot: a.slot,
40
+ listed: {
41
+ timestamp: a.at + transport.offset,
42
+ mark: undefined,
43
+ voice: undefined,
44
+ score: a.score,
45
+ name: a.name,
46
+ tags: a.tags,
47
+ mix: a.mix,
48
+ order: a.order,
49
+ },
26
50
  });
51
+ return out;
52
+ }
53
+ function voiceMarks(mix, from, to) {
54
+ const lo = from - mix.offset;
55
+ const hi = to - mix.offset;
56
+ const out = [];
27
57
  for (const voice of [...mix.cued, ...mix.gone]) {
28
- for (const mark of ['start', 'in', 'out', 'end']) {
58
+ for (const mark of ['start', 'in', 'coast', 'out', 'end']) {
29
59
  const m = markOf(mix, voice, mark);
30
60
  const t = m === undefined ? m : hostOf(mix, m) - mix.offset;
31
61
  if (t === undefined || t < lo || t > hi)
@@ -37,11 +67,11 @@ export function listed(mix, from, to) {
37
67
  score: voice.spec.score,
38
68
  name: voice.spec.name,
39
69
  tags: voice.spec.tags ?? none,
70
+ mix: mix.name,
40
71
  order: voice.id,
41
72
  });
42
73
  }
43
74
  }
44
- out.sort((a, b) => a.timestamp - b.timestamp || a.order - b.order);
45
75
  return out;
46
76
  }
47
77
  /** When a voice reaches a mark, mix time, or undefined while nothing has fixed it. */
@@ -56,13 +86,20 @@ export function markOf(mix, voice, mark) {
56
86
  return start;
57
87
  if (mark === 'in')
58
88
  return start + (voice.fade.in ?? 0);
89
+ if (mark === 'coast')
90
+ return coastOf(mix, voice, start);
59
91
  const out = voice.out;
60
92
  let outAt;
61
93
  if (out !== null)
62
94
  outAt = out.at;
63
95
  else if (Number.isFinite(voice.outAt))
64
96
  outAt = voice.outAt;
65
- else if (!voice.holdsAfter && Number.isFinite(voice.span)) {
97
+ else if (voice.fitting !== null) {
98
+ const t = voice.timeAt(voice.fitting.end);
99
+ if (Number.isFinite(t))
100
+ outAt = Math.max(start, t);
101
+ }
102
+ else if (!voice.freezesAfter && Number.isFinite(voice.span)) {
66
103
  const t = voice.timeAt(voice.span + voice.latest);
67
104
  if (Number.isFinite(t))
68
105
  outAt = Math.max(start, t);
@@ -76,5 +113,36 @@ export function markOf(mix, voice, mark) {
76
113
  return out.deadline === undefined ? undefined : out.at + out.deadline;
77
114
  return out.at + out.over;
78
115
  }
79
- return outAt === undefined ? undefined : outAt + (mix.reduced ? 0 : (voice.fade.out ?? 0));
116
+ const over = Number.isNaN(voice.outOver) ? (voice.fade.out ?? 0) : voice.outOver;
117
+ return outAt === undefined ? undefined : outAt + (mix.reduced ? 0 : over);
118
+ }
119
+ /**
120
+ * When a voice's last pass ends, mix time: an owner's when its fit ends, or its last child's. None
121
+ * for a voice that never ends its passes, or that leaves or begins to fade before they end.
122
+ */
123
+ function coastOf(mix, voice, start) {
124
+ if (voice.unplayed)
125
+ return undefined;
126
+ let t;
127
+ if (voice.fitting !== null)
128
+ t = voice.timeAt(voice.fitting.end);
129
+ else if (voice.holding !== null) {
130
+ const children = voice.holding.children;
131
+ if (children.length === 0)
132
+ return undefined;
133
+ t = Number.NEGATIVE_INFINITY;
134
+ for (const child of children) {
135
+ const c = markOf(mix, child, 'coast');
136
+ if (c === undefined)
137
+ return undefined;
138
+ t = Math.max(t, c);
139
+ }
140
+ }
141
+ else if (Number.isFinite(voice.span))
142
+ t = voice.timeAt(voice.span + voice.latest);
143
+ if (t === undefined || !Number.isFinite(t))
144
+ return undefined;
145
+ t = Math.max(start, t);
146
+ const cut = voice.out !== null ? voice.out.at : voice.state === 'done' ? voice.doneAt : voice.outAt;
147
+ return cut < t ? undefined : t;
80
148
  }
package/dist/meet.d.ts CHANGED
@@ -9,8 +9,9 @@ import type { Subject } from './voice.js';
9
9
  export declare function owable<I, O>(lanes: Lanes<I, O>, slot: number): boolean;
10
10
  /**
11
11
  * Gives a probed subject a position on every lane that started playing since the subject was last
12
- * checked and that reaches it. True when any did, so the probe takes the general path.
12
+ * checked and that reaches it, and says whether the probe still reads the lanes, given `lane`,
13
+ * whether it would have. Kept out of `prepare`, which V8 then inlines into its callers.
13
14
  */
14
- export declare function meet<I, O>(lanes: Lanes<I, O>, slot: number, subject: I, head: Subject<unknown> | null): boolean;
15
+ export declare function meet<I, O>(lanes: Lanes<I, O>, slot: number, subject: I, head: Subject<unknown> | null, lane: boolean): boolean;
15
16
  /** Counts an idle lane more or fewer reaching a subject. */
16
17
  export declare function reach<I, O>(lanes: Lanes<I, O>, slot: number, by: number): void;
package/dist/meet.js CHANGED
@@ -27,9 +27,10 @@ export function owable(lanes, slot) {
27
27
  }
28
28
  /**
29
29
  * Gives a probed subject a position on every lane that started playing since the subject was last
30
- * checked and that reaches it. True when any did, so the probe takes the general path.
30
+ * checked and that reaches it, and says whether the probe still reads the lanes, given `lane`,
31
+ * whether it would have. Kept out of `prepare`, which V8 then inlines into its callers.
31
32
  */
32
- export function meet(lanes, slot, subject, head) {
33
+ export function meet(lanes, slot, subject, head, lane) {
33
34
  const seen = lanes.per[slot * 6 /* Per.SLOT */ + 1 /* Per.SEEN */];
34
35
  const from = seen < 0 ? -1 - seen : seen;
35
36
  lanes.per[slot * 6 /* Per.SLOT */ + 1 /* Per.SEEN */] = lanes.epochs;
@@ -75,7 +76,18 @@ export function meet(lanes, slot, subject, head) {
75
76
  lanes.met.push(voice.id);
76
77
  met = true;
77
78
  }
78
- return met;
79
+ if (!met)
80
+ return lane;
81
+ // The fill ran before the subject had these positions. Where every voice it just met folds
82
+ // after every other laned voice, the general path folds just those onto the lanes' values;
83
+ // otherwise it reads the general path all frame.
84
+ const o = slot * 6 /* Per.SLOT */;
85
+ if (lane && lanes.per[o + 2 /* Per.IDLE */] === 0 && owable(lanes, slot)) {
86
+ lanes.owed.owe(slot, lanes.met);
87
+ return true;
88
+ }
89
+ lanes.per[o + 0 /* Per.FILLED */] = lanes.fills;
90
+ return false;
79
91
  }
80
92
  /** Places a crowd voice's row on the subject a probe met, as `Lane.add` adds a position. */
81
93
  function place(lanes, voice, slot, subject, from, head) {
package/dist/mixer.d.ts CHANGED
@@ -1,20 +1,24 @@
1
1
  import { blended, laneRead, shareKept } from './blend.js';
2
2
  import type { Book } from './book.js';
3
- import { aims, chain, linkable } from './chain.js';
3
+ import { aims, chain, linkable, relink } from './chain.js';
4
4
  import { type LerpInto } from './channels.js';
5
5
  import type { Due } from './due.js';
6
6
  import { parting } from './fade.js';
7
- import { apply, baseFor, clamp, fold, folded, foldLoci, foldWith, influence, isRest, type Key, keyed, linked, owedBy, passes, read, slopeFor, tick } from './fold.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
8
  import type { HandleHost } from './handle.js';
9
9
  import { held, shownOf, sinceOf, unreachedOf } from './held.js';
10
10
  import { Lanes } from './lanes.js';
11
11
  import { foldLocus, type LocusScratch } from './locus.js';
12
- import type { MotionOwner, Motions } from './motion.js';
13
- import { Pace } from './pace.js';
12
+ import type { MotionOwner, Motions } from './motions.js';
13
+ import type { Pace } from './pace.js';
14
+ import { Keys } from './paging.js';
14
15
  import { keep } from './pull.js';
15
16
  import { Steps } from './relink.js';
17
+ import { Outs } from './revive.js';
18
+ import { Fitting } from './spans.js';
16
19
  import { Store } from './store.js';
17
- import type { Booker, BookOptions, Channel, Columns, Engine, Handle, Kit, Marked, Mix, MixOptions, OwnerSpec, Patch, Projection, Sent, Signal, VoiceSpec } from './types.js';
20
+ import { type Announced, Transport } from './transport.js';
21
+ import type { Booker, BookOptions, Channel, Columns, Engine, Handle, Kit, Marked, Mix, MixOptions, OwnerSpec, Patch, Projection, Sent, Signal, SpanHandle, SpanSpec, Tape, VoiceSpec } from './types.js';
18
22
  import { type Subject, type Voice } from './voice.js';
19
23
  import { base, capped, fadeOf, horizonFor, ownedBy, ownerBase, prime, weigh, weighOwned } from './weigh.js';
20
24
  export declare class Mixer<I, O> implements Mix<I, O> {
@@ -37,19 +41,6 @@ export declare class Mixer<I, O> implements Mix<I, O> {
37
41
  at: number;
38
42
  fields: Record<string, unknown>;
39
43
  }[];
40
- /**
41
- * Marks the host announced on a score: `at` in host time, so the mix's rate never moves one, and
42
- * NaN until the next sync for one announced as now before any sync; `made` is the mix time it was
43
- * announced, for a read back to know what was known.
44
- */
45
- announced: {
46
- name: string;
47
- score: string | undefined;
48
- tags: readonly string[];
49
- at: number;
50
- made: number;
51
- order: number;
52
- }[];
53
44
  hostThen: {
54
45
  fields: Record<string, unknown>;
55
46
  } | undefined;
@@ -60,22 +51,17 @@ export declare class Mixer<I, O> implements Mix<I, O> {
60
51
  prev: O | undefined;
61
52
  prevAt: number;
62
53
  }>;
63
- nextId: number;
64
- /**
65
- * The mix clock: host time at the mix's rate. Host time is the host's timestamp less every gap
66
- * `rebase` has taken out, `u` at the last sync.
67
- */
68
- now: number;
69
- u: number;
54
+ /** The clock this mix plays on, which also holds its tape and the marks announced on it. */
55
+ readonly transport: Transport;
56
+ /** Its place among the mixes on its transport, in the order they joined. */
57
+ slot: number;
58
+ /** Taken off its transport, so it takes no more calls until a seek puts it back. */
59
+ dropped: boolean;
60
+ readonly name: string | undefined;
70
61
  /** This mix's frame among every mix's: moved by a sync, and by a control change or drop within one. */
71
62
  frame: number;
72
- offset: number;
73
- /** The mix's own rate; null while it has never been set, when mix time is host time. */
74
- pace: Pace | null;
75
63
  /** Pending voices whose start the host gave, by its host time, kept where the rate puts it. */
76
64
  pins: Map<Voice<I, O>, number> | null;
77
- last: number;
78
- rebasing: boolean;
79
65
  wantsPose: boolean;
80
66
  /** The pose `pull` folds a subject into where it cannot read straight from the lanes. */
81
67
  scratch: O | undefined;
@@ -100,14 +86,17 @@ export declare class Mixer<I, O> implements Mix<I, O> {
100
86
  stirred: boolean;
101
87
  /** Counts the changes `stir` records, which a frame's record of a probe is current only before. */
102
88
  stirs: number;
89
+ syncing: boolean;
90
+ stirFns: (() => void)[] | null;
103
91
  /** Records a change to the mix's voices or controls. */
104
92
  stir(): void;
93
+ onWake(fn: () => void): () => void;
105
94
  /**
106
95
  * Per subject, the first record of the chain through every live voice that reaches it, or a stub
107
96
  * where none does. Relinked when `version` moves, which is whenever the list or a voice's pending
108
97
  * state changes.
109
98
  */
110
- readonly chains: Store<I, Subject<unknown>>;
99
+ chains: Store<I, Subject<unknown>>;
111
100
  version: number;
112
101
  readonly steps: Steps<Voice<I, O>>;
113
102
  /** Per subject, the voices whose `subjects` name it, in voice order. */
@@ -140,7 +129,9 @@ export declare class Mixer<I, O> implements Mix<I, O> {
140
129
  subject: I;
141
130
  };
142
131
  readonly send: (event: unknown) => void;
143
- /** The weight `influence` found besides the delta, read by the caller at once. */
132
+ /** The moment a seek went back to: what is stepped again up to it was sent the first time. */
133
+ sentTo: number;
134
+ /** The weight `contribution` found besides the delta, read by the caller at once. */
144
135
  w: number;
145
136
  readonly names: Key<O>[];
146
137
  readonly channels: Channel<unknown>[];
@@ -152,13 +143,36 @@ export declare class Mixer<I, O> implements Mix<I, O> {
152
143
  readonly locusScratch: LocusScratch<I, O>[];
153
144
  locusDepth: number;
154
145
  readonly slotOf: Map<string, number>;
155
- readonly lanes: Lanes<I, O> | null;
146
+ lanes: Lanes<I, O> | null;
156
147
  handles: HandleHost<I, O> | null;
157
148
  /** What `book` made, still booking; null while there is none. */
158
149
  bookers: Book<I, O>[] | null;
150
+ /** The fit a span being cued takes, which `cue` hands its voice. */
151
+ fitting: Fitting | null;
159
152
  /** Every owner still in the mix, null until one is cued. */
160
153
  owners: Voice<I, O>[] | null;
154
+ /** With a history store, the key each subject is paged under; null without one. */
155
+ keys: Keys | null;
156
+ /** With a history store, the voices it paged out whose handles are still held; null without one. */
157
+ outs: Outs | null;
161
158
  constructor(kit: Kit<O>, opts: MixOptions);
159
+ /** Throws where the clock is a shared transport's, which only the transport moves. */
160
+ private own;
161
+ get now(): number;
162
+ set now(v: number);
163
+ get u(): number;
164
+ set u(v: number);
165
+ get offset(): number;
166
+ set offset(v: number);
167
+ get pace(): Pace | null;
168
+ set pace(v: Pace | null);
169
+ get announced(): Announced[];
170
+ set announced(v: Announced[]);
171
+ get nextId(): number;
172
+ set nextId(v: number);
173
+ get last(): number;
174
+ get tape(): Tape | undefined;
175
+ get replaying(): boolean;
162
176
  get reduced(): boolean;
163
177
  get band(): {
164
178
  on: number;
@@ -167,16 +181,21 @@ export declare class Mixer<I, O> implements Mix<I, O> {
167
181
  cue(spec: VoiceSpec<I, O>): Handle<I>;
168
182
  blend(patches: readonly Patch<I, O, unknown>[], by: Signal<I>, spec?: Omit<VoiceSpec<I, O>, 'patch' | 'weight' | 'locus'>): Handle<I>[];
169
183
  owns(spec: OwnerSpec<I>): Handle<I>;
184
+ span(spec: SpanSpec<I>): SpanHandle<I>;
170
185
  sync(timestamp: number): void;
171
186
  book(opts: BookOptions): Booker;
172
187
  probe(subject: I, out?: O): O;
173
188
  pull(subjects: Iterable<I>, into: Columns<O>): void;
174
- project(timestamp: number): Projection<I, O>;
189
+ seek(time: number): void;
190
+ prepare(time: number): Promise<void>;
191
+ project(time: number): Projection<I, O>;
175
192
  announce(name: string, opts?: {
176
193
  at?: number;
177
194
  score?: string;
178
195
  tags?: readonly string[];
179
196
  }): void;
197
+ /** Throws for a mix taken off its transport. */
198
+ attached(): void;
180
199
  marks(from: number, to: number): Marked[];
181
200
  atRest(subject: I): boolean;
182
201
  rests(pose: O): boolean;
@@ -221,7 +240,7 @@ declare const methods: {
221
240
  owedBy: typeof owedBy;
222
241
  foldLoci: typeof foldLoci;
223
242
  read: typeof read;
224
- influence: typeof influence;
243
+ contribution: typeof contribution;
225
244
  keyed: typeof keyed;
226
245
  tick: typeof tick;
227
246
  apply: typeof apply;
@@ -244,6 +263,7 @@ declare const methods: {
244
263
  shareKept: typeof shareKept;
245
264
  parting: typeof parting;
246
265
  chain: typeof chain;
266
+ relink: typeof relink;
247
267
  linkable: typeof linkable;
248
268
  aims: typeof aims;
249
269
  held: typeof held;