@real-music-packages/web-core 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/audio.d.ts +36 -0
- package/dist/audio.js +55 -0
- package/dist/audio.js.map +1 -1
- package/dist/scene/headless.d.ts +10 -0
- package/dist/scene/headless.js +108 -0
- package/dist/scene/headless.js.map +1 -0
- package/dist/scene/index.d.ts +605 -87
- package/dist/scene/index.js +1625 -296
- package/dist/scene/index.js.map +1 -1
- package/package.json +5 -1
package/dist/scene/index.d.ts
CHANGED
|
@@ -69,15 +69,6 @@ interface ScoreFromMusicXMLOpts {
|
|
|
69
69
|
*/
|
|
70
70
|
declare function scoreFromMusicXML(xml: string, opts?: ScoreFromMusicXMLOpts): Promise<Score>;
|
|
71
71
|
|
|
72
|
-
/**
|
|
73
|
-
* Install jsdom globals + a fake 2D canvas context so OSMD can `load()` a score
|
|
74
|
-
* headlessly. Idempotent. Call once before constructing an OSMD instance in Node.
|
|
75
|
-
*
|
|
76
|
-
* No-ops if `window`/`document` already exist (e.g. a real browser, or a vitest
|
|
77
|
-
* jsdom environment), so it is safe to call unconditionally.
|
|
78
|
-
*/
|
|
79
|
-
declare function setupHeadlessDom(): Promise<void>;
|
|
80
|
-
|
|
81
72
|
/**
|
|
82
73
|
* Audio clock the runner exposes to layers. `nowMs` is the current playback
|
|
83
74
|
* position in milliseconds (audio-clock-driven, NOT wall-clock). During an
|
|
@@ -149,6 +140,83 @@ interface LayerFactory<P = unknown> {
|
|
|
149
140
|
validateProps(props: unknown): string[];
|
|
150
141
|
}
|
|
151
142
|
|
|
143
|
+
/** One scheduled audio event, in seconds RELATIVE to the schedule start. */
|
|
144
|
+
interface AudioEvent {
|
|
145
|
+
/** Offset from schedule start, seconds. */
|
|
146
|
+
atSec: number;
|
|
147
|
+
/** Pitch (note name or frequency) for tonal hits; omitted for noise clicks. */
|
|
148
|
+
note?: string | number;
|
|
149
|
+
/** Duration, seconds. Default short. */
|
|
150
|
+
durSec?: number;
|
|
151
|
+
/** Linear gain 0..1. Default 1. */
|
|
152
|
+
gain?: number;
|
|
153
|
+
/** Tag for tests/debugging: "count" | "click" | "drone". */
|
|
154
|
+
kind: 'count' | 'click' | 'drone';
|
|
155
|
+
}
|
|
156
|
+
interface CountInOpts {
|
|
157
|
+
/** Beats to count (default 4 — a full bar of 4/4). */
|
|
158
|
+
beats?: number;
|
|
159
|
+
/** Tempo for the count, bpm. */
|
|
160
|
+
bpm: number;
|
|
161
|
+
/** Accent the downbeat (beat 1) with a higher pitch. Default true. */
|
|
162
|
+
accentDownbeat?: boolean;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* The count-in schedule: one click per beat, starting at t=0, ending exactly on
|
|
166
|
+
* the downbeat of bar 1 (i.e. the music starts at `beats * 60/bpm` seconds).
|
|
167
|
+
* Pure.
|
|
168
|
+
*/
|
|
169
|
+
declare function countInSchedule(opts: CountInOpts): AudioEvent[];
|
|
170
|
+
/** Seconds after t=0 that the music should start, for a given count-in. */
|
|
171
|
+
declare function countInLeadSec(opts: CountInOpts): number;
|
|
172
|
+
interface ClickTrackOpts {
|
|
173
|
+
bpm: number;
|
|
174
|
+
/** Total duration to fill with clicks, seconds. */
|
|
175
|
+
durationSec: number;
|
|
176
|
+
/** Beats per bar, for downbeat accents. Default 4. */
|
|
177
|
+
beatsPerBar?: number;
|
|
178
|
+
/** Start offset, seconds. Default 0. */
|
|
179
|
+
startSec?: number;
|
|
180
|
+
}
|
|
181
|
+
/** A click on every beat across `durationSec`, accenting each bar's downbeat. */
|
|
182
|
+
declare function clickTrackSchedule(opts: ClickTrackOpts): AudioEvent[];
|
|
183
|
+
interface DroneOpts {
|
|
184
|
+
/** Root pitch of the pad (e.g. "C2"). */
|
|
185
|
+
root: string;
|
|
186
|
+
/** Pad duration, seconds. */
|
|
187
|
+
durationSec: number;
|
|
188
|
+
/** Add a perfect fifth above the root. Default true. */
|
|
189
|
+
fifth?: boolean;
|
|
190
|
+
/** Bed gain 0..1. Default 0.15 (sits well under the melody). */
|
|
191
|
+
gain?: number;
|
|
192
|
+
}
|
|
193
|
+
/** A sustained root (+fifth) pad for the whole clip. */
|
|
194
|
+
declare function droneSchedule(opts: DroneOpts): AudioEvent[];
|
|
195
|
+
interface DuckWindow {
|
|
196
|
+
/** Voice-over window start, seconds. */
|
|
197
|
+
startSec: number;
|
|
198
|
+
/** Voice-over window end, seconds. */
|
|
199
|
+
endSec: number;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Gain envelope for a music/bed bus that ducks under voice-over windows. Returns
|
|
203
|
+
* the linear gain 0..1 at time `tSec`: `floor` inside a window (after a short
|
|
204
|
+
* attack ramp), 1 outside (after a release ramp). Pure — feed it to a Tone
|
|
205
|
+
* Gain's `.gain.value` per frame, or sample it to build a ramp automation.
|
|
206
|
+
*/
|
|
207
|
+
declare function duckGainAt(windows: DuckWindow[], tSec: number, floor?: number, rampSec?: number): number;
|
|
208
|
+
/**
|
|
209
|
+
* Trigger a computed schedule on a Tone instrument at `startTime` (audio-clock
|
|
210
|
+
* seconds, e.g. `Tone.now()` or sampler.audioNow()). Thin glue over the existing
|
|
211
|
+
* sampler/synth — no new mastering bus. Tonal events use triggerAttackRelease;
|
|
212
|
+
* the instrument is whatever the caller wires into the promo mastering chain.
|
|
213
|
+
*
|
|
214
|
+
* Returns the number of events fired (handy for tests/gate sanity).
|
|
215
|
+
*/
|
|
216
|
+
declare function applySchedule(instrument: {
|
|
217
|
+
triggerAttackRelease: (note: any, dur: any, time?: any, velocity?: any) => void;
|
|
218
|
+
}, schedule: AudioEvent[], startTime: number): number;
|
|
219
|
+
|
|
152
220
|
declare const clamp: (x: number, lo: number, hi: number) => number;
|
|
153
221
|
declare const lerp: (a: number, b: number, t: number) => number;
|
|
154
222
|
/** Inverse-lerp: where does `x` sit in [a,b] as 0..1 (clamped, a===b -> 0). */
|
|
@@ -218,10 +286,52 @@ interface SpecLayer {
|
|
|
218
286
|
/** Props passed to the layer's init(). */
|
|
219
287
|
p?: unknown;
|
|
220
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* Optional per-segment audio. Lets a segment SCHEDULE sound at its own start
|
|
291
|
+
* time during capture — the seam that lets per-scene / sequential-audio apps
|
|
292
|
+
* (RET templates schedule `engine.playNote` in a scene's `onEnter`; whozart's
|
|
293
|
+
* "listen" scenes play a phrase when the scene begins) run on the same runner
|
|
294
|
+
* instead of staying bespoke. Everything here is OPTIONAL and the runner stays
|
|
295
|
+
* pure-visual when it's absent (fully backward-compatible).
|
|
296
|
+
*
|
|
297
|
+
* Two complementary forms, both resolved against the CAPTURE clock (not
|
|
298
|
+
* wall-clock) so they fire at the right offset in an offline/deterministic
|
|
299
|
+
* render:
|
|
300
|
+
* - `schedule`: declarative `AudioEvent`s whose `atSec` is relative to the
|
|
301
|
+
* segment's start. Played through the same Tone sampler/mastering bus via the
|
|
302
|
+
* existing `applySchedule` glue (so timing == captureStart + segStart + atSec).
|
|
303
|
+
* - `onEnter(audioClock, ctx)`: an imperative escape hatch fired once at the
|
|
304
|
+
* segment's start time, handed the audio clock anchored to that start (its
|
|
305
|
+
* `nowMs()` returns the segment's absolute start ms) so the callback can do
|
|
306
|
+
* its own `triggerAttackRelease(note, dur, audioClock.nowMs()/1000 + …)`.
|
|
307
|
+
*/
|
|
308
|
+
interface SegmentAudio {
|
|
309
|
+
/** Declarative events; `atSec` is relative to the segment's start. */
|
|
310
|
+
schedule?: AudioEvent[];
|
|
311
|
+
/** Imperative hook fired once at the segment's start during capture. */
|
|
312
|
+
onEnter?: (audioClock: AudioClock, ctx: SegmentAudioCtx) => void;
|
|
313
|
+
}
|
|
314
|
+
/** Context handed to a `SegmentAudio.onEnter` callback. */
|
|
315
|
+
interface SegmentAudioCtx {
|
|
316
|
+
/** The Tone instrument wired into the promo mastering chain (has
|
|
317
|
+
* `triggerAttackRelease`). Same target `applySchedule` plays through. */
|
|
318
|
+
instrument: ScheduleTarget;
|
|
319
|
+
/** Absolute capture-clock seconds at which this segment starts (= the audio
|
|
320
|
+
* base time + the segment's resolved start). Add your own offsets to this. */
|
|
321
|
+
startSec: number;
|
|
322
|
+
/** The render Score, if any (timing/pitch source). */
|
|
323
|
+
score?: Score;
|
|
324
|
+
}
|
|
325
|
+
/** Minimal Tone-instrument surface the audio scheduler needs. */
|
|
326
|
+
interface ScheduleTarget {
|
|
327
|
+
triggerAttackRelease: (note: unknown, dur: unknown, time?: unknown, velocity?: unknown) => void;
|
|
328
|
+
}
|
|
221
329
|
interface TimelineSegment {
|
|
222
330
|
/** [start, end] in SECONDS; end may be "end" / "end-N". */
|
|
223
331
|
at: [number, TimeAnchor];
|
|
224
332
|
layers: SpecLayer[];
|
|
333
|
+
/** Optional sound scheduled at this segment's start (see SegmentAudio). */
|
|
334
|
+
audio?: SegmentAudio;
|
|
225
335
|
}
|
|
226
336
|
interface SceneSpec {
|
|
227
337
|
/** [width, height] px. */
|
|
@@ -246,6 +356,7 @@ interface ResolvedSegment {
|
|
|
246
356
|
startMs: number;
|
|
247
357
|
endMs: number;
|
|
248
358
|
layers: SpecLayer[];
|
|
359
|
+
audio?: SegmentAudio;
|
|
249
360
|
}
|
|
250
361
|
/** Resolve every segment's [start,end] to ms against the total clip length. */
|
|
251
362
|
declare function resolveTimeline(spec: SceneSpec, totalSec: number): ResolvedSegment[];
|
|
@@ -263,6 +374,17 @@ interface BuiltScene {
|
|
|
263
374
|
dispose(): void;
|
|
264
375
|
/** The resolved timeline (for the gate / diagnostics). */
|
|
265
376
|
resolved: ResolvedSegment[];
|
|
377
|
+
/**
|
|
378
|
+
* Schedule every segment's optional audio against the CAPTURE clock. Call once
|
|
379
|
+
* at capture start, passing the Tone instrument (the promo sampler) and the
|
|
380
|
+
* audio-clock base time in SECONDS (e.g. `sampler.audioNow()` / `Tone.now()`).
|
|
381
|
+
* Each segment's events fire at `baseSec + segStartMs/1000 + atSec`; each
|
|
382
|
+
* `onEnter` fires once with an AudioClock anchored to its segment start.
|
|
383
|
+
* Deterministic w.r.t. the supplied base time (no wall-clock). No-op for specs
|
|
384
|
+
* that declare no segment audio. Returns the count of events scheduled (handy
|
|
385
|
+
* for tests/gate sanity).
|
|
386
|
+
*/
|
|
387
|
+
scheduleAudio(instrument: ScheduleTarget, baseSec: number): number;
|
|
266
388
|
}
|
|
267
389
|
interface BuildSceneOpts {
|
|
268
390
|
spec: SceneSpec;
|
|
@@ -289,6 +411,21 @@ interface RecordSceneSpecOpts {
|
|
|
289
411
|
onProgress?: RecordOpts['onProgress'];
|
|
290
412
|
/** Inject the recorder for tests. Defaults to recordScenes. */
|
|
291
413
|
record?: (scenes: Scene[], o: RecordOpts) => Promise<Blob>;
|
|
414
|
+
/**
|
|
415
|
+
* OPTIONAL per-segment audio scheduling. When a spec declares segment audio
|
|
416
|
+
* (SegmentAudio), pass the Tone instrument (the promo sampler) and a clock so
|
|
417
|
+
* the runner can schedule each segment's sound against the capture timeline.
|
|
418
|
+
* `audioNow()` returns the audio-clock seconds at capture start (e.g.
|
|
419
|
+
* `sampler.audioNow()` / `Tone.now()`); `lookaheadSec` (default 0.1) shifts
|
|
420
|
+
* the whole schedule forward a touch so the first event isn't already in the
|
|
421
|
+
* past when the recorder spins up. Omit entirely → pure-visual capture
|
|
422
|
+
* (unchanged behavior).
|
|
423
|
+
*/
|
|
424
|
+
segmentAudio?: {
|
|
425
|
+
instrument: ScheduleTarget;
|
|
426
|
+
audioNow: () => number;
|
|
427
|
+
lookaheadSec?: number;
|
|
428
|
+
};
|
|
292
429
|
}
|
|
293
430
|
/**
|
|
294
431
|
* Capture a built scene to a Blob by wrapping the whole timeline as a SINGLE
|
|
@@ -373,83 +510,6 @@ interface CaptionStyle {
|
|
|
373
510
|
*/
|
|
374
511
|
declare function drawCaption(ctx: CanvasRenderingContext2D, script: CaptionScript, tMs: number, safe: SafeBox, theme: PromoTheme, style?: CaptionStyle): void;
|
|
375
512
|
|
|
376
|
-
/** One scheduled audio event, in seconds RELATIVE to the schedule start. */
|
|
377
|
-
interface AudioEvent {
|
|
378
|
-
/** Offset from schedule start, seconds. */
|
|
379
|
-
atSec: number;
|
|
380
|
-
/** Pitch (note name or frequency) for tonal hits; omitted for noise clicks. */
|
|
381
|
-
note?: string | number;
|
|
382
|
-
/** Duration, seconds. Default short. */
|
|
383
|
-
durSec?: number;
|
|
384
|
-
/** Linear gain 0..1. Default 1. */
|
|
385
|
-
gain?: number;
|
|
386
|
-
/** Tag for tests/debugging: "count" | "click" | "drone". */
|
|
387
|
-
kind: 'count' | 'click' | 'drone';
|
|
388
|
-
}
|
|
389
|
-
interface CountInOpts {
|
|
390
|
-
/** Beats to count (default 4 — a full bar of 4/4). */
|
|
391
|
-
beats?: number;
|
|
392
|
-
/** Tempo for the count, bpm. */
|
|
393
|
-
bpm: number;
|
|
394
|
-
/** Accent the downbeat (beat 1) with a higher pitch. Default true. */
|
|
395
|
-
accentDownbeat?: boolean;
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* The count-in schedule: one click per beat, starting at t=0, ending exactly on
|
|
399
|
-
* the downbeat of bar 1 (i.e. the music starts at `beats * 60/bpm` seconds).
|
|
400
|
-
* Pure.
|
|
401
|
-
*/
|
|
402
|
-
declare function countInSchedule(opts: CountInOpts): AudioEvent[];
|
|
403
|
-
/** Seconds after t=0 that the music should start, for a given count-in. */
|
|
404
|
-
declare function countInLeadSec(opts: CountInOpts): number;
|
|
405
|
-
interface ClickTrackOpts {
|
|
406
|
-
bpm: number;
|
|
407
|
-
/** Total duration to fill with clicks, seconds. */
|
|
408
|
-
durationSec: number;
|
|
409
|
-
/** Beats per bar, for downbeat accents. Default 4. */
|
|
410
|
-
beatsPerBar?: number;
|
|
411
|
-
/** Start offset, seconds. Default 0. */
|
|
412
|
-
startSec?: number;
|
|
413
|
-
}
|
|
414
|
-
/** A click on every beat across `durationSec`, accenting each bar's downbeat. */
|
|
415
|
-
declare function clickTrackSchedule(opts: ClickTrackOpts): AudioEvent[];
|
|
416
|
-
interface DroneOpts {
|
|
417
|
-
/** Root pitch of the pad (e.g. "C2"). */
|
|
418
|
-
root: string;
|
|
419
|
-
/** Pad duration, seconds. */
|
|
420
|
-
durationSec: number;
|
|
421
|
-
/** Add a perfect fifth above the root. Default true. */
|
|
422
|
-
fifth?: boolean;
|
|
423
|
-
/** Bed gain 0..1. Default 0.15 (sits well under the melody). */
|
|
424
|
-
gain?: number;
|
|
425
|
-
}
|
|
426
|
-
/** A sustained root (+fifth) pad for the whole clip. */
|
|
427
|
-
declare function droneSchedule(opts: DroneOpts): AudioEvent[];
|
|
428
|
-
interface DuckWindow {
|
|
429
|
-
/** Voice-over window start, seconds. */
|
|
430
|
-
startSec: number;
|
|
431
|
-
/** Voice-over window end, seconds. */
|
|
432
|
-
endSec: number;
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Gain envelope for a music/bed bus that ducks under voice-over windows. Returns
|
|
436
|
-
* the linear gain 0..1 at time `tSec`: `floor` inside a window (after a short
|
|
437
|
-
* attack ramp), 1 outside (after a release ramp). Pure — feed it to a Tone
|
|
438
|
-
* Gain's `.gain.value` per frame, or sample it to build a ramp automation.
|
|
439
|
-
*/
|
|
440
|
-
declare function duckGainAt(windows: DuckWindow[], tSec: number, floor?: number, rampSec?: number): number;
|
|
441
|
-
/**
|
|
442
|
-
* Trigger a computed schedule on a Tone instrument at `startTime` (audio-clock
|
|
443
|
-
* seconds, e.g. `Tone.now()` or sampler.audioNow()). Thin glue over the existing
|
|
444
|
-
* sampler/synth — no new mastering bus. Tonal events use triggerAttackRelease;
|
|
445
|
-
* the instrument is whatever the caller wires into the promo mastering chain.
|
|
446
|
-
*
|
|
447
|
-
* Returns the number of events fired (handy for tests/gate sanity).
|
|
448
|
-
*/
|
|
449
|
-
declare function applySchedule(instrument: {
|
|
450
|
-
triggerAttackRelease: (note: any, dur: any, time?: any, velocity?: any) => void;
|
|
451
|
-
}, schedule: AudioEvent[], startTime: number): number;
|
|
452
|
-
|
|
453
513
|
interface GateError {
|
|
454
514
|
check: 'av-duration' | 'placement' | 'fonts' | 'spec' | 'output';
|
|
455
515
|
message: string;
|
|
@@ -947,4 +1007,462 @@ interface PromoCardsDemoOpts {
|
|
|
947
1007
|
/** Build the demo SceneSpec wiring the S4 wrapper layers across a timeline. */
|
|
948
1008
|
declare function promoCardsDemoSpec(opts?: PromoCardsDemoOpts): SceneSpec;
|
|
949
1009
|
|
|
950
|
-
|
|
1010
|
+
interface StaffKeyboardRayProps {
|
|
1011
|
+
/** Layer key of the notation layer to link (forward-compat; v1 uses the single
|
|
1012
|
+
* published engraving). Default "notation". */
|
|
1013
|
+
notationKey?: string;
|
|
1014
|
+
/** Layer key of the keyboard layer to link. Default "keyboard". */
|
|
1015
|
+
keyboardKey?: string;
|
|
1016
|
+
/** Ray reveal/grow + fade duration, ms. Default 180. */
|
|
1017
|
+
fadeMs?: number;
|
|
1018
|
+
/** Line width, world px. Default 4. */
|
|
1019
|
+
width?: number;
|
|
1020
|
+
/** Ray colour (default per-note hand colour via the theme accent). */
|
|
1021
|
+
color?: string;
|
|
1022
|
+
/** Number of segments to approximate the curve. Default 24. */
|
|
1023
|
+
segments?: number;
|
|
1024
|
+
}
|
|
1025
|
+
declare const staffKeyboardRayFactory: LayerFactory<StaffKeyboardRayProps>;
|
|
1026
|
+
|
|
1027
|
+
interface RayEndpoints {
|
|
1028
|
+
/** Staff-end point (screen px). */
|
|
1029
|
+
staff: {
|
|
1030
|
+
x: number;
|
|
1031
|
+
y: number;
|
|
1032
|
+
};
|
|
1033
|
+
/** Keyboard-end point (screen px) = the top-centre of the key. */
|
|
1034
|
+
keyboard: {
|
|
1035
|
+
x: number;
|
|
1036
|
+
y: number;
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* The staff-end anchor for an audio progress `t01` (0..1 over the clip), using the
|
|
1041
|
+
* playhead sweep across the notation's mapped measure columns. Mirrors
|
|
1042
|
+
* notationGeometry.playheadLine's x/y derivation so the ray starts exactly where
|
|
1043
|
+
* the playhead is. Returns null when the layout has no measures/systems.
|
|
1044
|
+
*/
|
|
1045
|
+
declare function staffAnchor(layout: NotationLayout, t01: number): {
|
|
1046
|
+
x: number;
|
|
1047
|
+
y: number;
|
|
1048
|
+
} | null;
|
|
1049
|
+
/**
|
|
1050
|
+
* Full ray endpoints for a note's pitch + an audio progress, given both layouts.
|
|
1051
|
+
* The keyboard end is the top-centre of the note's key. Pure.
|
|
1052
|
+
*/
|
|
1053
|
+
declare function rayEndpoints(notation: NotationLayout, keyboard: KeyboardLayout, pitchMidi: number, t01: number): RayEndpoints | null;
|
|
1054
|
+
/**
|
|
1055
|
+
* A point along a quadratic Bézier from staff→keyboard, bulged toward the side, at
|
|
1056
|
+
* parameter `u` 0..1. Used to draw a gently curved ray (a straight line reads as a
|
|
1057
|
+
* cursor; a curve reads as a connector). Pure.
|
|
1058
|
+
*/
|
|
1059
|
+
declare function rayPointAt(ends: RayEndpoints, u: number, bulge?: number): {
|
|
1060
|
+
x: number;
|
|
1061
|
+
y: number;
|
|
1062
|
+
};
|
|
1063
|
+
|
|
1064
|
+
interface CountingTrackProps {
|
|
1065
|
+
/** Subdivisions per beat shown: 1 (just numbers), 2 ("&"), 4 ("e & a"). Default 1. */
|
|
1066
|
+
subdiv?: 1 | 2 | 4;
|
|
1067
|
+
/** Override time signature (else Score.timeSig, else 4/4). */
|
|
1068
|
+
timeSig?: string;
|
|
1069
|
+
/** Override bpm (else Score.tempoMap, else 100). */
|
|
1070
|
+
bpm?: number;
|
|
1071
|
+
/** Track baseline (world y) the ball lands on. Default safeBox.bottom - 120. */
|
|
1072
|
+
trackY?: number;
|
|
1073
|
+
/** Bounce height in world px. Default 110. */
|
|
1074
|
+
bounce?: number;
|
|
1075
|
+
/** Syllable font size, world px. Default 34. */
|
|
1076
|
+
size?: number;
|
|
1077
|
+
/** Ball radius, world px. Default 22. */
|
|
1078
|
+
ballRadius?: number;
|
|
1079
|
+
/** Count-in offset, ms (first beat lands here). Default 0. */
|
|
1080
|
+
startMs?: number;
|
|
1081
|
+
}
|
|
1082
|
+
declare const countingTrackFactory: LayerFactory<CountingTrackProps>;
|
|
1083
|
+
|
|
1084
|
+
interface BeatGridOpts {
|
|
1085
|
+
/** Constant bpm of the QUARTER-note beat (tempoMap.segments[0].bpm). */
|
|
1086
|
+
bpm: number;
|
|
1087
|
+
/** Beats per bar (time-sig numerator). Default 4. */
|
|
1088
|
+
beatsPerBar?: number;
|
|
1089
|
+
/** Time-sig denominator (note value of one beat). Default 4. */
|
|
1090
|
+
beatUnit?: number;
|
|
1091
|
+
/** Subdivisions per beat for the syllable row: 1, 2 ("&"), or 4 ("e & a"). Default 1. */
|
|
1092
|
+
subdiv?: 1 | 2 | 4;
|
|
1093
|
+
/** Total length to cover, ms. */
|
|
1094
|
+
durationMs: number;
|
|
1095
|
+
/** Count-in offset: first beat lands at this ms (default 0). */
|
|
1096
|
+
startMs?: number;
|
|
1097
|
+
}
|
|
1098
|
+
interface BeatTick {
|
|
1099
|
+
/** Onset time, ms. */
|
|
1100
|
+
tMs: number;
|
|
1101
|
+
/** 0-based beat index across the whole clip. */
|
|
1102
|
+
index: number;
|
|
1103
|
+
/** 1-based beat number within the bar (the big counted number). */
|
|
1104
|
+
beatInBar: number;
|
|
1105
|
+
/** Subdivision index within the beat (0 = on the beat). */
|
|
1106
|
+
sub: number;
|
|
1107
|
+
/** The counting syllable ("1","e","&","a", "2", …). */
|
|
1108
|
+
syllable: string;
|
|
1109
|
+
/** True on the downbeat (beatInBar === 1, sub === 0). */
|
|
1110
|
+
downbeat: boolean;
|
|
1111
|
+
}
|
|
1112
|
+
/** ms between quarter beats; the beat-unit scales it (eighth beat = half a quarter). */
|
|
1113
|
+
declare function msPerBeat(bpm: number, beatUnit: number): number;
|
|
1114
|
+
/** Build the full beat+subdivision schedule across the clip. Pure. */
|
|
1115
|
+
declare function beatGrid(opts: BeatGridOpts): BeatTick[];
|
|
1116
|
+
/** The TempoMap's first-segment bpm (v1 single-tempo helper). */
|
|
1117
|
+
declare function bpmOf(tempoMap: TempoMap | undefined, fallback?: number): number;
|
|
1118
|
+
/**
|
|
1119
|
+
* Phase 0..1 within the current beat at time `tMs` (0 = on the beat). Pure.
|
|
1120
|
+
* Used by the bouncing ball's vertical position.
|
|
1121
|
+
*/
|
|
1122
|
+
declare function beatPhase(bpm: number, beatUnit: number, tMs: number, startMs?: number): number;
|
|
1123
|
+
/**
|
|
1124
|
+
* The bouncing ball's vertical offset 0..1 (0 = at the track line / floor, 1 =
|
|
1125
|
+
* top of the arc). A parabola that touches 0 exactly ON each beat and peaks at
|
|
1126
|
+
* mid-beat — so the ball "lands" on the count. Pure.
|
|
1127
|
+
*/
|
|
1128
|
+
declare function ballArc(phase01: number): number;
|
|
1129
|
+
/** Horizontal x (world) of the ball at time t, sweeping left→right across the
|
|
1130
|
+
* counting track in step with the beats. Pure. */
|
|
1131
|
+
declare function ballX(ticks: BeatTick[], tMs: number, xOf: (tick: BeatTick) => number): number;
|
|
1132
|
+
/** Parse a "n/d" time signature string into [numerator, denominator]. */
|
|
1133
|
+
declare function parseTimeSig(ts: string | undefined): [number, number];
|
|
1134
|
+
|
|
1135
|
+
type LabelMode = 'degree' | 'solfege';
|
|
1136
|
+
interface DegreeLabel {
|
|
1137
|
+
/** Diatonic degree 1..7 (the letter-distance from the tonic letter). */
|
|
1138
|
+
degree: number;
|
|
1139
|
+
/** Chromatic inflection in semitones vs the diatonic degree (−1 flat, +1 sharp, 0 natural). */
|
|
1140
|
+
alter: number;
|
|
1141
|
+
/** The display text for the chosen mode. */
|
|
1142
|
+
text: string;
|
|
1143
|
+
}
|
|
1144
|
+
/** Parse a key string ("Eb major" / "C# minor" / "F") into a tonic letter + mode. */
|
|
1145
|
+
declare function parseKey(key: string | undefined): {
|
|
1146
|
+
tonicLetter: string;
|
|
1147
|
+
tonicPc: number;
|
|
1148
|
+
minor: boolean;
|
|
1149
|
+
};
|
|
1150
|
+
/**
|
|
1151
|
+
* Compute the scale-degree label for a note, from its NOTATED spelling.
|
|
1152
|
+
*
|
|
1153
|
+
* `degree` = the letter distance (1..7) from the tonic letter to the note's
|
|
1154
|
+
* letter, which is the enharmonically-correct diatonic degree. `alter` = how the
|
|
1155
|
+
* note's actual pitch class differs from that degree's pitch in the key
|
|
1156
|
+
* (so D♯ vs D♭ in C give the same degree 2 but +1 / −1). For MINOR keys the
|
|
1157
|
+
* reference scale is natural minor (so the lowered 3/6/7 read as natural degrees,
|
|
1158
|
+
* matching how movable-do "la-based minor" is taught only in MAJOR; here we use
|
|
1159
|
+
* do-based, i.e. degrees relative to the major scale of the tonic — see note).
|
|
1160
|
+
*
|
|
1161
|
+
* Pure.
|
|
1162
|
+
*/
|
|
1163
|
+
declare function degreeLabel(step: string, alter: number, pitchMidi: number, key: string | undefined, mode: LabelMode): DegreeLabel;
|
|
1164
|
+
|
|
1165
|
+
interface DegreeLabelsProps {
|
|
1166
|
+
/** "degree" = scale-degree numbers (1..7, ♯/♭ chromatics); "solfege" =
|
|
1167
|
+
* movable-do syllables (do re mi …, di ra …). Default "degree". */
|
|
1168
|
+
mode?: LabelMode;
|
|
1169
|
+
/** Override the Score's key (e.g. for an excerpt in a different key). */
|
|
1170
|
+
key?: string;
|
|
1171
|
+
/** Label font size in world px. Default 30. */
|
|
1172
|
+
size?: number;
|
|
1173
|
+
/** Fade in/out of a label, ms. Default 120. */
|
|
1174
|
+
fadeMs?: number;
|
|
1175
|
+
/** Text colour. Default theme.ink on a translucent chip. */
|
|
1176
|
+
color?: string;
|
|
1177
|
+
}
|
|
1178
|
+
declare const degreeLabelsFactory: LayerFactory<DegreeLabelsProps>;
|
|
1179
|
+
|
|
1180
|
+
type HarmonicFunction = 'T' | 'S' | 'D' | 'other';
|
|
1181
|
+
interface ChordSpan {
|
|
1182
|
+
/** Span start, ms. */
|
|
1183
|
+
startMs: number;
|
|
1184
|
+
/** Span end, ms. */
|
|
1185
|
+
endMs: number;
|
|
1186
|
+
/** Tonal function. */
|
|
1187
|
+
fn: HarmonicFunction;
|
|
1188
|
+
/** Optional display label (roman numeral / chord symbol), drawn by the layer. */
|
|
1189
|
+
label?: string;
|
|
1190
|
+
}
|
|
1191
|
+
/** Default function colours (warm tonic / cool subdominant / tense dominant). */
|
|
1192
|
+
interface FunctionColors {
|
|
1193
|
+
T: string;
|
|
1194
|
+
S: string;
|
|
1195
|
+
D: string;
|
|
1196
|
+
other: string;
|
|
1197
|
+
}
|
|
1198
|
+
declare const DEFAULT_FUNCTION_COLORS: FunctionColors;
|
|
1199
|
+
/** The chord span active at time `tMs` (first whose [start,end) contains t), or null. */
|
|
1200
|
+
declare function activeChord(track: ChordSpan[], tMs: number): ChordSpan | null;
|
|
1201
|
+
/** Colour for a function. Pure. */
|
|
1202
|
+
declare function functionColor(fn: HarmonicFunction, colors: FunctionColors): string;
|
|
1203
|
+
/**
|
|
1204
|
+
* Validate a chord track (used by the layer's prop validator). Returns []
|
|
1205
|
+
* when valid, else human-readable errors. Exported so the gate message is precise.
|
|
1206
|
+
*/
|
|
1207
|
+
declare function validateChordTrack(track: unknown): string[];
|
|
1208
|
+
|
|
1209
|
+
type HarmonyMode = 'band' | 'keys' | 'wash';
|
|
1210
|
+
interface FunctionalHarmonyProps {
|
|
1211
|
+
/** REQUIRED: the timed chord spans (function + optional label). Host-supplied. */
|
|
1212
|
+
chordTrack: ChordSpan[];
|
|
1213
|
+
/** Which renderings to draw. Default ["band"]. */
|
|
1214
|
+
modes?: HarmonyMode[];
|
|
1215
|
+
/** Override the function→colour map. */
|
|
1216
|
+
colors?: FunctionColors;
|
|
1217
|
+
/** Band height (world px). Default 64. */
|
|
1218
|
+
bandHeight?: number;
|
|
1219
|
+
/** Band top (world y). Default safeBox.top. */
|
|
1220
|
+
bandTop?: number;
|
|
1221
|
+
/** Cross-fade between spans, ms. Default 200. */
|
|
1222
|
+
fadeMs?: number;
|
|
1223
|
+
/** Wash opacity at full intensity. Default 0.12. */
|
|
1224
|
+
washAlpha?: number;
|
|
1225
|
+
}
|
|
1226
|
+
declare const functionalHarmonyFactory: LayerFactory<FunctionalHarmonyProps>;
|
|
1227
|
+
|
|
1228
|
+
interface QuizOption {
|
|
1229
|
+
/** Option text (e.g. "Major 3rd", "Beethoven"). */
|
|
1230
|
+
text: string;
|
|
1231
|
+
}
|
|
1232
|
+
interface Quiz {
|
|
1233
|
+
/** The prompt ("Which interval?" / "Name this piece"). */
|
|
1234
|
+
question: string;
|
|
1235
|
+
/** 2–4 options. */
|
|
1236
|
+
options: QuizOption[];
|
|
1237
|
+
/** Index into options of the correct answer (0-based). */
|
|
1238
|
+
correctIndex: number;
|
|
1239
|
+
/** When the card starts asking (absolute ms). Default 0. */
|
|
1240
|
+
askMs?: number;
|
|
1241
|
+
/** When the correct option is revealed (absolute ms). REQUIRED. */
|
|
1242
|
+
revealMs: number;
|
|
1243
|
+
/** When the card finishes (absolute ms). REQUIRED. */
|
|
1244
|
+
endMs: number;
|
|
1245
|
+
/** Optional per-option poll percentages (0..100), shown as bars. Length must
|
|
1246
|
+
* match options. Host-supplied (e.g. real community votes); not fabricated. */
|
|
1247
|
+
poll?: number[];
|
|
1248
|
+
}
|
|
1249
|
+
type QuizPhase = 'before' | 'question' | 'reveal' | 'after';
|
|
1250
|
+
/** Resolve the card phase at time `tMs`. Pure. */
|
|
1251
|
+
declare function quizPhase(quiz: Quiz, tMs: number): QuizPhase;
|
|
1252
|
+
/**
|
|
1253
|
+
* Countdown fraction remaining 0..1 across [askMs, revealMs] (1 at ask, 0 at
|
|
1254
|
+
* reveal), clamped outside. Drives the countdown ring/bar. Pure.
|
|
1255
|
+
*/
|
|
1256
|
+
declare function countdownRemaining(quiz: Quiz, tMs: number): number;
|
|
1257
|
+
/**
|
|
1258
|
+
* Integer seconds remaining on the countdown (ceil), for the big number. Pure.
|
|
1259
|
+
*/
|
|
1260
|
+
declare function countdownSeconds(quiz: Quiz, tMs: number): number;
|
|
1261
|
+
/**
|
|
1262
|
+
* Reveal progress 0..1 across a short window after revealMs (for a pop/fade of
|
|
1263
|
+
* the correct option). `windowMs` default 350. Pure.
|
|
1264
|
+
*/
|
|
1265
|
+
declare function revealProgress(quiz: Quiz, tMs: number, windowMs?: number): number;
|
|
1266
|
+
/**
|
|
1267
|
+
* Validate a Quiz prop (used by the layer's validator + the pre-render gate).
|
|
1268
|
+
* Returns [] when valid, else human-readable errors. The card REQUIRES this prop;
|
|
1269
|
+
* it has no data otherwise.
|
|
1270
|
+
*/
|
|
1271
|
+
declare function validateQuiz(quiz: unknown): string[];
|
|
1272
|
+
|
|
1273
|
+
interface Section {
|
|
1274
|
+
/** Section start, ms. */
|
|
1275
|
+
startMs: number;
|
|
1276
|
+
/** Section end, ms. */
|
|
1277
|
+
endMs: number;
|
|
1278
|
+
/** Display label ("Verse", "A", "Exposition"). */
|
|
1279
|
+
label?: string;
|
|
1280
|
+
}
|
|
1281
|
+
/** Progress 0..1 along the clip at time t. Pure. */
|
|
1282
|
+
declare function progress01(durationMs: number, tMs: number): number;
|
|
1283
|
+
/** x of a time on a [left, left+width] bar across [0, durationMs]. Pure. */
|
|
1284
|
+
declare function timeToX(left: number, width: number, durationMs: number, tMs: number): number;
|
|
1285
|
+
/** The section containing time t (first whose [start,end) holds t), or null. Pure. */
|
|
1286
|
+
declare function activeSection(sections: Section[], tMs: number): Section | null;
|
|
1287
|
+
/**
|
|
1288
|
+
* Build uniform measure-span sections from a measure count + total duration (a
|
|
1289
|
+
* fallback when no explicit sections are given but a measure count is). Each
|
|
1290
|
+
* section is one measure, labelled by 1-based measure number. Pure.
|
|
1291
|
+
*/
|
|
1292
|
+
declare function measureSpans(measureCount: number, durationMs: number): Section[];
|
|
1293
|
+
/**
|
|
1294
|
+
* Validate a sections array (used by the layer validator). Returns [] when valid.
|
|
1295
|
+
*/
|
|
1296
|
+
declare function validateSections(sections: unknown): string[];
|
|
1297
|
+
|
|
1298
|
+
interface ExtendedDemoOpts {
|
|
1299
|
+
size?: [number, number];
|
|
1300
|
+
theme?: string;
|
|
1301
|
+
}
|
|
1302
|
+
/** Counting track + bouncing ball + scale-degree labels over a keyboard. */
|
|
1303
|
+
declare function countingDegreeDemoSpec(opts?: ExtendedDemoOpts & {
|
|
1304
|
+
subdiv?: 1 | 2 | 4;
|
|
1305
|
+
labelMode?: LabelMode;
|
|
1306
|
+
range?: '88' | 'auto';
|
|
1307
|
+
}): SceneSpec;
|
|
1308
|
+
/** Staff↔keyboard ray over a (pre-rendered) notation + keyboard. */
|
|
1309
|
+
declare function staffRayDemoSpec(rendered: RenderedNotation, opts?: ExtendedDemoOpts & {
|
|
1310
|
+
range?: '88' | 'auto';
|
|
1311
|
+
}): SceneSpec;
|
|
1312
|
+
/** Functional-harmony coloring (band + keys) over a keyboard, driven by a chord track. */
|
|
1313
|
+
declare function harmonyDemoSpec(chordTrack: ChordSpan[], opts?: ExtendedDemoOpts & {
|
|
1314
|
+
range?: '88' | 'auto';
|
|
1315
|
+
}): SceneSpec;
|
|
1316
|
+
/** MCQ poll card over a plain background (RET quiz / whozart name-that-piece). */
|
|
1317
|
+
declare function mcqDemoSpec(quiz: Quiz, opts?: ExtendedDemoOpts): SceneSpec;
|
|
1318
|
+
/** Circle-of-fifths widget (optionally animating a modulation). */
|
|
1319
|
+
declare function circleOfFifthsDemoSpec(opts?: ExtendedDemoOpts & {
|
|
1320
|
+
toKey?: string;
|
|
1321
|
+
fromMs?: number;
|
|
1322
|
+
toMs?: number;
|
|
1323
|
+
}): SceneSpec;
|
|
1324
|
+
/** Pitch-contour line over the melody (Score.notes) + a section minimap. */
|
|
1325
|
+
declare function contourMinimapDemoSpec(opts?: ExtendedDemoOpts & {
|
|
1326
|
+
sections?: Section[];
|
|
1327
|
+
measureCount?: number;
|
|
1328
|
+
}): SceneSpec;
|
|
1329
|
+
|
|
1330
|
+
interface McqCardProps {
|
|
1331
|
+
/** REQUIRED: the host-supplied quiz (question/options/correctIndex/timings). */
|
|
1332
|
+
quiz: Quiz;
|
|
1333
|
+
/** Accent for the correct reveal (default theme.accent). */
|
|
1334
|
+
correctColor?: string;
|
|
1335
|
+
/** Show the poll bars (only if quiz.poll is present). Default true. */
|
|
1336
|
+
showPoll?: boolean;
|
|
1337
|
+
}
|
|
1338
|
+
declare const mcqCardFactory: LayerFactory<McqCardProps>;
|
|
1339
|
+
|
|
1340
|
+
interface CircleOfFifthsProps {
|
|
1341
|
+
/** Override the highlighted key (else Score.key, else C). */
|
|
1342
|
+
key?: string;
|
|
1343
|
+
/** Animate the highlight to this key (modulation target). Host-supplied. */
|
|
1344
|
+
toKey?: string;
|
|
1345
|
+
/** Modulation start time (ms). Required if toKey is set. */
|
|
1346
|
+
fromMs?: number;
|
|
1347
|
+
/** Modulation end time (ms). Required if toKey is set. */
|
|
1348
|
+
toMs?: number;
|
|
1349
|
+
/** Widget centre [x,y] (world). Default centred in the safe box. */
|
|
1350
|
+
center?: [number, number];
|
|
1351
|
+
/** Outer radius (world px). Default min(safe.w, safe.h) * 0.32. */
|
|
1352
|
+
radius?: number;
|
|
1353
|
+
/** Show the relative-minor inner ring. Default true. */
|
|
1354
|
+
showMinor?: boolean;
|
|
1355
|
+
/** Highlight colour (default theme.accent). */
|
|
1356
|
+
color?: string;
|
|
1357
|
+
}
|
|
1358
|
+
declare const circleOfFifthsFactory: LayerFactory<CircleOfFifthsProps>;
|
|
1359
|
+
|
|
1360
|
+
/** Major-key labels around the circle, clockwise from the top. */
|
|
1361
|
+
declare const FIFTHS_MAJOR: string[];
|
|
1362
|
+
/** Relative-minor labels (inner ring), aligned to the same slots. */
|
|
1363
|
+
declare const FIFTHS_MINOR: string[];
|
|
1364
|
+
/** Pitch class at circle slot i (0..11), clockwise fifths from C. */
|
|
1365
|
+
declare function slotPc(i: number): number;
|
|
1366
|
+
/** The circle slot (0..11) for a tonic pitch class. Pure. */
|
|
1367
|
+
declare function pcToSlot(pc: number): number;
|
|
1368
|
+
/** The circle slot for a key string ("G major" / "Eb"). Pure. */
|
|
1369
|
+
declare function keySlot(key: string | undefined): number;
|
|
1370
|
+
/** Angle (radians, 0 = up/12-o'clock, clockwise +) of circle slot i. Pure. */
|
|
1371
|
+
declare function slotAngle(i: number): number;
|
|
1372
|
+
interface CirclePoint {
|
|
1373
|
+
x: number;
|
|
1374
|
+
y: number;
|
|
1375
|
+
}
|
|
1376
|
+
/** Cartesian point for a slot on a circle of radius r centred at (cx,cy).
|
|
1377
|
+
* 0 rad = straight up, increasing clockwise. Pure. */
|
|
1378
|
+
declare function slotPoint(cx: number, cy: number, r: number, i: number): CirclePoint;
|
|
1379
|
+
/**
|
|
1380
|
+
* Animated highlight slot as a fractional position from a source slot to a target
|
|
1381
|
+
* slot over progress `t01`, taking the SHORTEST way around the wheel. Returns a
|
|
1382
|
+
* fractional slot (e.g. 1.5 = between G and D). Pure.
|
|
1383
|
+
*/
|
|
1384
|
+
declare function animatedSlot(fromSlot: number, toSlot: number, t01: number): number;
|
|
1385
|
+
/** Cartesian point for a FRACTIONAL slot (e.g. mid-modulation) on the circle.
|
|
1386
|
+
* Pure. */
|
|
1387
|
+
declare function fracSlotPoint(cx: number, cy: number, r: number, frac: number): CirclePoint;
|
|
1388
|
+
|
|
1389
|
+
interface PitchContourProps {
|
|
1390
|
+
/** Plot band top (world y). Default safeBox.top + safeBox.h * 0.15. */
|
|
1391
|
+
top?: number;
|
|
1392
|
+
/** Plot band height (world px). Default safeBox.h * 0.35. */
|
|
1393
|
+
height?: number;
|
|
1394
|
+
/** Line width (world px). Default 5. */
|
|
1395
|
+
width?: number;
|
|
1396
|
+
/** Line colour (default theme.accent). */
|
|
1397
|
+
color?: string;
|
|
1398
|
+
/** Show the moving dot at the current pitch. Default true. */
|
|
1399
|
+
dot?: boolean;
|
|
1400
|
+
/** Dot radius (world px). Default 14. */
|
|
1401
|
+
dotRadius?: number;
|
|
1402
|
+
}
|
|
1403
|
+
declare const pitchContourFactory: LayerFactory<PitchContourProps>;
|
|
1404
|
+
|
|
1405
|
+
interface ContourPoint {
|
|
1406
|
+
/** Onset time, ms. */
|
|
1407
|
+
tMs: number;
|
|
1408
|
+
/** MIDI pitch of the melody note at that onset. */
|
|
1409
|
+
pitchMidi: number;
|
|
1410
|
+
}
|
|
1411
|
+
interface ContourPlot {
|
|
1412
|
+
left: number;
|
|
1413
|
+
right: number;
|
|
1414
|
+
top: number;
|
|
1415
|
+
bottom: number;
|
|
1416
|
+
minPitch: number;
|
|
1417
|
+
maxPitch: number;
|
|
1418
|
+
durationMs: number;
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Reduce notes to one melody point per distinct onset = the highest sounding
|
|
1422
|
+
* pitch at that onset. Returns points sorted by time. Pure.
|
|
1423
|
+
*/
|
|
1424
|
+
declare function contourPoints(notes: ScoreNote[]): ContourPoint[];
|
|
1425
|
+
/** Pitch range [min,max] of the points (with a 1-semitone pad, min span 2). Pure. */
|
|
1426
|
+
declare function pitchRange(points: ContourPoint[]): {
|
|
1427
|
+
min: number;
|
|
1428
|
+
max: number;
|
|
1429
|
+
};
|
|
1430
|
+
/** Project a (time,pitch) onto plot pixels. y is inverted (high pitch = up). Pure. */
|
|
1431
|
+
declare function projectPoint(plot: ContourPlot, tMs: number, pitchMidi: number): {
|
|
1432
|
+
x: number;
|
|
1433
|
+
y: number;
|
|
1434
|
+
};
|
|
1435
|
+
/** The full pixel polyline for the contour. Pure. */
|
|
1436
|
+
declare function contourPolyline(points: ContourPoint[], plot: ContourPlot): {
|
|
1437
|
+
x: number;
|
|
1438
|
+
y: number;
|
|
1439
|
+
}[];
|
|
1440
|
+
/**
|
|
1441
|
+
* The melody pitch sounding at time `tMs`: the pitch of the most recent onset
|
|
1442
|
+
* at-or-before t (step interpolation — a melody holds until the next note). Returns
|
|
1443
|
+
* null before the first onset. Pure.
|
|
1444
|
+
*/
|
|
1445
|
+
declare function pitchAt(points: ContourPoint[], tMs: number): number | null;
|
|
1446
|
+
/** The moving-dot position at time t (rides the contour at the current pitch). Pure. */
|
|
1447
|
+
declare function dotAt(points: ContourPoint[], plot: ContourPlot, tMs: number): {
|
|
1448
|
+
x: number;
|
|
1449
|
+
y: number;
|
|
1450
|
+
} | null;
|
|
1451
|
+
|
|
1452
|
+
interface SectionMinimapProps {
|
|
1453
|
+
/** Host-supplied section spans. Takes precedence over measureCount. */
|
|
1454
|
+
sections?: Section[];
|
|
1455
|
+
/** Fallback: split the clip into this many uniform measure bands. */
|
|
1456
|
+
measureCount?: number;
|
|
1457
|
+
/** Bar baseline (world y). Default safeBox.bottom - 40. */
|
|
1458
|
+
barY?: number;
|
|
1459
|
+
/** Bar thickness (world px). Default 10. */
|
|
1460
|
+
barHeight?: number;
|
|
1461
|
+
/** Show the active section's label above the bar. Default true. */
|
|
1462
|
+
showLabel?: boolean;
|
|
1463
|
+
/** Accent for the played portion + dot (default theme.accent). */
|
|
1464
|
+
color?: string;
|
|
1465
|
+
}
|
|
1466
|
+
declare const sectionMinimapFactory: LayerFactory<SectionMinimapProps>;
|
|
1467
|
+
|
|
1468
|
+
export { type Affine, type AudioClock, type AudioEvent, type BackgroundProps, type BeatGridOpts, type BeatTick, type BrandingProps, type BuildSceneOpts, type BuiltScene, type CameraState, type CaptionCue, type CaptionProps, type CaptionScript, type CaptionStyle, type ChordSpan, type CircleOfFifthsProps, type CirclePoint, type ClickTrackOpts, type ColorBy, type ContourPlot, type ContourPoint, type CountInOpts, type CountingTrackProps, type CtaProps, DEFAULT_FUNCTION_COLORS, type DegreeLabel, type DegreeLabelsProps, type DroneOpts, type DuckWindow, type Easing, type ExtendedDemoOpts, FIFTHS_MAJOR, FIFTHS_MINOR, FOLLOW_BARS, FOLLOW_PAD, type FallingKeyboardDemoOpts, type FallingNotesProps, type FunctionColors, type FunctionalHarmonyProps, type GateError, type GateInput, type HandColors, type HarmonicFunction, type HarmonyMode, type HighlightRegion, type HookProps, type KeyRect, type KeyboardLayout, type KeyboardLayoutOpts, type KeyboardProps, type LabelMode, type Layer, type LayerFactory, type McqCardProps, type NotationEngraving, type NotationLayout, type NotationLayoutOpts, type NotationProps, type NotationRect, type OutputProbe, PIANO_HIGH, PIANO_LOW, type PitchContourProps, type Placement, type PlayheadLine, type PortraitProps, type PromoCardsDemoOpts, type Quiz, type QuizOption, type QuizPhase, type RayEndpoints, type RecordSceneSpecOpts, type Rect, type RenderCtx, type ResolvedSegment, type RevealProps, type SafeGuidesProps, type SceneSpec, type ScheduleTarget, type Score, type ScoreFromMusicXMLOpts, type ScoreNote, type ScrollCursorProps, type Section, type SectionMinimapProps, type SegmentAudio, type SegmentAudioCtx, type SpecLayer, type SpectrumInput, type SpectrumProps, type StaffKeyboardRayProps, type TempoMap, type TimeAnchor, type TimelineSegment, activeChord, activeCue, activeSection, animatedSlot, applySchedule, applyToContext, assertGate, ballArc, ballX, beatGrid, beatPhase, blackKeys, bpmOf, brandingFactory, buildScene, cameraForFollow, cameraTransform, circleOfFifthsDemoSpec, circleOfFifthsFactory, clamp, clickTrackSchedule, contourMinimapDemoSpec, contourPoints, contourPolyline, countInLeadSec, countInSchedule, countdownRemaining, countdownSeconds, countingDegreeDemoSpec, countingTrackFactory, cropAroundBox, ctaFactory, cubicEaseInOut, cueOpacity, degreeLabel, degreeLabelsFactory, dotAt, drawCaption, drawHighlight, droneSchedule, duckGainAt, easeIn, easeInOut, easeOut, fallingKeyboardDemoScore, fallingKeyboardDemoSpec, fallingNotesFactory, firstMeasureBox, followBoxAt, followSrcBox, followWindowStart, fracSlotPoint, frameRect, functionColor, functionalHarmonyFactory, getKeyboardLayout, getLayerFactory, getNotationEngraving, harmonyDemoSpec, highlightIntensity, hookFactory, identityCamera, inRange, invLerp, isBlackKey, kenBurns, keyCenterX, keyColumnWidth, keyRect, keySlot, keyboardFactory, keyboardLayout, lerp, lerpBox, lerpCamera, linear, mapBoxThroughLayout, mcqCardFactory, mcqDemoSpec, measureColumnsFromLayout, measureCount, measureSpanBox, measureSpans, timeToX as minimapTimeToX, msPerBeat, notationFactory, notationLayout, noteColor, noteSetXRange, parseKey, parseTimeSig, pcToSlot, pitchAt, pitchContourFactory, pitchRange, playheadLine, portraitFactory, progress01, projectPoint, promoCardsDemoSpec, quizPhase, rayEndpoints, rayPointAt, recordSceneSpec, registerLayer, registeredKeys, resolveAnchor, resolveKeyboardLayout, resolveTimeline, revealFactory, revealProgress, runGate, safeGuidesFactory, scoreFromMusicXML, scorePitchSpan, scrollCursorFactory, sectionMinimapFactory, setFollowLayoutProvider, setKeyboardLayout, setNotationEngraving, slotAngle, slotPc, slotPoint, spectrumFactory, staffAnchor, staffKeyboardRayFactory, staffRayDemoSpec, validateChordTrack, validateQuiz, validateSections, visualTimelineMs, whiteKeys, worldToViewport };
|