@hyperframes/core 0.6.97 → 0.6.98
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/dist/beats/beatDetection.d.ts +22 -0
- package/dist/beats/beatDetection.d.ts.map +1 -0
- package/dist/beats/beatDetection.js +246 -0
- package/dist/beats/beatDetection.js.map +1 -0
- package/dist/beats/beatFile.d.ts +18 -0
- package/dist/beats/beatFile.d.ts.map +1 -0
- package/dist/beats/beatFile.js +112 -0
- package/dist/beats/beatFile.js.map +1 -0
- package/dist/beats/index.d.ts +3 -0
- package/dist/beats/index.d.ts.map +1 -0
- package/dist/beats/index.js +3 -0
- package/dist/beats/index.js.map +1 -0
- package/dist/compiler/htmlBundler.d.ts +0 -9
- package/dist/compiler/htmlBundler.d.ts.map +1 -1
- package/dist/compiler/htmlBundler.js +70 -92
- package/dist/compiler/htmlBundler.js.map +1 -1
- package/dist/compiler/rewriteSubCompPaths.d.ts.map +1 -1
- package/dist/compiler/rewriteSubCompPaths.js +3 -11
- package/dist/compiler/rewriteSubCompPaths.js.map +1 -1
- package/dist/core.types.d.ts +0 -5
- package/dist/core.types.d.ts.map +1 -1
- package/dist/core.types.js +0 -15
- package/dist/core.types.js.map +1 -1
- package/dist/fonts/systemFontLocator.d.ts +1 -0
- package/dist/fonts/systemFontLocator.d.ts.map +1 -1
- package/dist/fonts/systemFontLocator.js +8 -2
- package/dist/fonts/systemFontLocator.js.map +1 -1
- package/dist/generated/runtime-inline.js +1 -1
- package/dist/generated/runtime-inline.js.map +1 -1
- package/dist/generators/hyperframes.d.ts.map +1 -1
- package/dist/generators/hyperframes.js +21 -18
- package/dist/generators/hyperframes.js.map +1 -1
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +22 -22
- package/dist/hyperframe.runtime.mjs +22 -22
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lint/hyperframeLinter.d.ts +0 -11
- package/dist/lint/hyperframeLinter.d.ts.map +1 -1
- package/dist/lint/hyperframeLinter.js +0 -73
- package/dist/lint/hyperframeLinter.js.map +1 -1
- package/dist/lint/rules/adapters.d.ts.map +1 -1
- package/dist/lint/rules/adapters.js +9 -15
- package/dist/lint/rules/adapters.js.map +1 -1
- package/dist/lint/rules/composition.d.ts.map +1 -1
- package/dist/lint/rules/composition.js +2 -3
- package/dist/lint/rules/composition.js.map +1 -1
- package/dist/lint/rules/core.d.ts.map +1 -1
- package/dist/lint/rules/core.js +2 -3
- package/dist/lint/rules/core.js.map +1 -1
- package/dist/lint/rules/gsap.d.ts.map +1 -1
- package/dist/lint/rules/gsap.js +13 -67
- package/dist/lint/rules/gsap.js.map +1 -1
- package/dist/lint/utils.d.ts +5 -0
- package/dist/lint/utils.d.ts.map +1 -1
- package/dist/lint/utils.js +64 -0
- package/dist/lint/utils.js.map +1 -1
- package/dist/parsers/gsapParser.d.ts +2 -0
- package/dist/parsers/gsapParser.d.ts.map +1 -1
- package/dist/parsers/gsapParser.js +143 -140
- package/dist/parsers/gsapParser.js.map +1 -1
- package/dist/parsers/gsapSerialize.d.ts +2 -0
- package/dist/parsers/gsapSerialize.d.ts.map +1 -1
- package/dist/parsers/gsapSerialize.js +6 -5
- package/dist/parsers/gsapSerialize.js.map +1 -1
- package/dist/parsers/htmlParser.d.ts.map +1 -1
- package/dist/parsers/htmlParser.js +13 -18
- package/dist/parsers/htmlParser.js.map +1 -1
- package/dist/studio-api/helpers/sourceMutation.d.ts +1 -0
- package/dist/studio-api/helpers/sourceMutation.d.ts.map +1 -1
- package/dist/studio-api/helpers/sourceMutation.js +2 -2
- package/dist/studio-api/helpers/sourceMutation.js.map +1 -1
- package/dist/studio-api/routes/files.d.ts.map +1 -1
- package/dist/studio-api/routes/files.js +60 -48
- package/dist/studio-api/routes/files.js.map +1 -1
- package/dist/studio-api/routes/fonts.d.ts.map +1 -1
- package/dist/studio-api/routes/fonts.js +2 -47
- package/dist/studio-api/routes/fonts.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface MusicBeatAnalysis {
|
|
2
|
+
beatTimes: number[];
|
|
3
|
+
/** Per-beat loudness 0–1 (local RMS / peak), aligned by index with beatTimes. */
|
|
4
|
+
beatStrengths: number[];
|
|
5
|
+
bpm: number | null;
|
|
6
|
+
bpmConfidence: "high" | "low" | "uncertain";
|
|
7
|
+
/** Decoded mono samples — retained so strength can be measured at user-added
|
|
8
|
+
* beats. Audio-file coordinates. May be null if decode data was dropped. */
|
|
9
|
+
channelData: Float32Array | null;
|
|
10
|
+
sampleRate: number;
|
|
11
|
+
/** Reference peak RMS used to normalize beat strengths. */
|
|
12
|
+
peak: number;
|
|
13
|
+
}
|
|
14
|
+
/** Local RMS amplitude at a given audio-file time. */
|
|
15
|
+
export declare function computeRmsAt(channelData: Float32Array, sampleRate: number, time: number): number;
|
|
16
|
+
/** Normalized beat strength (0–1) at an audio-file time, using a track peak. */
|
|
17
|
+
export declare function strengthAtTime(analysis: Pick<MusicBeatAnalysis, "channelData" | "sampleRate" | "peak">, time: number): number;
|
|
18
|
+
export declare function detectBeats(audioBuffer: AudioBuffer): Promise<number[]>;
|
|
19
|
+
export declare function analyzeMusicFromBuffer(audioBuffer: AudioBuffer): Promise<MusicBeatAnalysis>;
|
|
20
|
+
export declare function detectBeatsFromUrl(url: string): Promise<number[]>;
|
|
21
|
+
export declare function analyzeMusicFromUrl(url: string): Promise<MusicBeatAnalysis>;
|
|
22
|
+
//# sourceMappingURL=beatDetection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beatDetection.d.ts","sourceRoot":"","sources":["../../src/beats/beatDetection.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iFAAiF;IACjF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC;IAC5C;iFAC6E;IAC7E,WAAW,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;CACd;AAID,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAWhG;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,IAAI,CAAC,iBAAiB,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAC,EACxE,IAAI,EAAE,MAAM,GACX,MAAM,CAGR;AAGD,wBAAsB,WAAW,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwC7E;AAkGD,wBAAsB,sBAAsB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA6DjG;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUvE;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAUjF"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
let bpmDetectivePromise = null;
|
|
2
|
+
function loadBpmDetective() {
|
|
3
|
+
if (!bpmDetectivePromise) {
|
|
4
|
+
bpmDetectivePromise = import(
|
|
5
|
+
// @ts-ignore -- no type declarations for bpm-detective
|
|
6
|
+
"bpm-detective")
|
|
7
|
+
.then((m) => (m.default ?? m) || null)
|
|
8
|
+
.catch(() => null);
|
|
9
|
+
}
|
|
10
|
+
return bpmDetectivePromise;
|
|
11
|
+
}
|
|
12
|
+
const WINDOW_SIZE = 1024;
|
|
13
|
+
const HOP_SIZE = 512;
|
|
14
|
+
const STRENGTH_WINDOW_S = 0.05; // ±50ms RMS window
|
|
15
|
+
/** Local RMS amplitude at a given audio-file time. */
|
|
16
|
+
export function computeRmsAt(channelData, sampleRate, time) {
|
|
17
|
+
const halfWindow = Math.floor(sampleRate * STRENGTH_WINDOW_S);
|
|
18
|
+
const center = Math.floor(time * sampleRate);
|
|
19
|
+
const start = Math.max(0, center - halfWindow);
|
|
20
|
+
const end = Math.min(channelData.length, center + halfWindow);
|
|
21
|
+
let sum = 0;
|
|
22
|
+
for (let i = start; i < end; i++) {
|
|
23
|
+
const s = channelData[i] ?? 0;
|
|
24
|
+
sum += s * s;
|
|
25
|
+
}
|
|
26
|
+
return Math.sqrt(sum / Math.max(end - start, 1));
|
|
27
|
+
}
|
|
28
|
+
/** Normalized beat strength (0–1) at an audio-file time, using a track peak. */
|
|
29
|
+
export function strengthAtTime(analysis, time) {
|
|
30
|
+
if (!analysis.channelData || analysis.peak <= 0)
|
|
31
|
+
return 0.5;
|
|
32
|
+
return Math.min(1, computeRmsAt(analysis.channelData, analysis.sampleRate, time) / analysis.peak);
|
|
33
|
+
}
|
|
34
|
+
// fallow-ignore-next-line complexity
|
|
35
|
+
export async function detectBeats(audioBuffer) {
|
|
36
|
+
const channelData = audioBuffer.getChannelData(0);
|
|
37
|
+
const sampleRate = audioBuffer.sampleRate;
|
|
38
|
+
const energies = [];
|
|
39
|
+
for (let i = 0; i < channelData.length - WINDOW_SIZE; i += HOP_SIZE) {
|
|
40
|
+
let sum = 0;
|
|
41
|
+
for (let j = 0; j < WINDOW_SIZE; j++) {
|
|
42
|
+
const sample = channelData[i + j];
|
|
43
|
+
sum += sample * sample;
|
|
44
|
+
}
|
|
45
|
+
energies.push(sum / WINDOW_SIZE);
|
|
46
|
+
}
|
|
47
|
+
const beats = [];
|
|
48
|
+
const localWindowSize = 20;
|
|
49
|
+
for (let i = localWindowSize; i < energies.length - localWindowSize; i++) {
|
|
50
|
+
let localMean = 0;
|
|
51
|
+
for (let j = i - localWindowSize; j < i + localWindowSize; j++) {
|
|
52
|
+
localMean += energies[j];
|
|
53
|
+
}
|
|
54
|
+
localMean /= localWindowSize * 2;
|
|
55
|
+
const threshold = localMean * 1.5;
|
|
56
|
+
const current = energies[i];
|
|
57
|
+
if (current > threshold &&
|
|
58
|
+
current > (energies[i - 1] ?? 0) &&
|
|
59
|
+
current > (energies[i + 1] ?? 0)) {
|
|
60
|
+
const timeInSeconds = (i * HOP_SIZE) / sampleRate;
|
|
61
|
+
if (beats.length === 0 || timeInSeconds - beats[beats.length - 1] > 0.1) {
|
|
62
|
+
beats.push(Math.round(timeInSeconds * 1000) / 1000);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return beats;
|
|
67
|
+
}
|
|
68
|
+
function computeBpmFromBeats(beatTimes) {
|
|
69
|
+
if (beatTimes.length < 4)
|
|
70
|
+
return null;
|
|
71
|
+
const iois = [];
|
|
72
|
+
for (let i = 1; i < beatTimes.length; i++) {
|
|
73
|
+
iois.push(beatTimes[i] - beatTimes[i - 1]);
|
|
74
|
+
}
|
|
75
|
+
const sorted = [...iois].sort((a, b) => a - b);
|
|
76
|
+
const mid = Math.floor(sorted.length / 2);
|
|
77
|
+
const medianIoi = sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
78
|
+
if (medianIoi <= 0)
|
|
79
|
+
return null;
|
|
80
|
+
return Math.round((60 / medianIoi) * 10) / 10;
|
|
81
|
+
}
|
|
82
|
+
// Fold into 60–120 for octave-safe BPM comparison
|
|
83
|
+
function canonicalizeBpm(bpm) {
|
|
84
|
+
let b = bpm;
|
|
85
|
+
while (b > 120)
|
|
86
|
+
b /= 2;
|
|
87
|
+
while (b < 60)
|
|
88
|
+
b *= 2;
|
|
89
|
+
return b;
|
|
90
|
+
}
|
|
91
|
+
// Pick the *2/÷2 octave of `bpm` whose beat interval is closest to the onset
|
|
92
|
+
// pulse, so a half-time detective reading (e.g. 174 for an 87bpm song) doesn't
|
|
93
|
+
// produce a double-density grid.
|
|
94
|
+
function octaveAlignBpm(bpm, reference) {
|
|
95
|
+
const candidates = [bpm / 2, bpm, bpm * 2];
|
|
96
|
+
let best = bpm;
|
|
97
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
98
|
+
for (const c of candidates) {
|
|
99
|
+
if (c <= 0)
|
|
100
|
+
continue;
|
|
101
|
+
const dist = Math.abs(c - reference);
|
|
102
|
+
if (dist < bestDist) {
|
|
103
|
+
bestDist = dist;
|
|
104
|
+
best = c;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return best;
|
|
108
|
+
}
|
|
109
|
+
// fallow-ignore-next-line complexity
|
|
110
|
+
function regularizeBeats(rawBeats, bpm, duration) {
|
|
111
|
+
if (rawBeats.length === 0 || bpm <= 0 || duration <= 0)
|
|
112
|
+
return rawBeats;
|
|
113
|
+
const beatInterval = 60 / bpm;
|
|
114
|
+
// Guard against a pathological (octave-misread) tempo producing a millisecond
|
|
115
|
+
// interval → tens of thousands of grid beats that freeze the timeline. 480 BPM
|
|
116
|
+
// (0.125s) is well above any real music tempo; bail to the raw onsets instead.
|
|
117
|
+
if (beatInterval < 0.125)
|
|
118
|
+
return rawBeats;
|
|
119
|
+
const threshold = beatInterval * 0.25;
|
|
120
|
+
// Find phase offset that maximally aligns with raw onsets
|
|
121
|
+
let bestOffset = 0;
|
|
122
|
+
let bestScore = -1;
|
|
123
|
+
for (const anchor of rawBeats.slice(0, 10)) {
|
|
124
|
+
const offset = ((anchor % beatInterval) + beatInterval) % beatInterval;
|
|
125
|
+
let score = 0;
|
|
126
|
+
for (const rb of rawBeats) {
|
|
127
|
+
const phase = ((rb % beatInterval) + beatInterval) % beatInterval;
|
|
128
|
+
const dist = Math.min(Math.abs(phase - offset), beatInterval - Math.abs(phase - offset));
|
|
129
|
+
if (dist < threshold)
|
|
130
|
+
score++;
|
|
131
|
+
}
|
|
132
|
+
if (score > bestScore) {
|
|
133
|
+
bestScore = score;
|
|
134
|
+
bestOffset = offset;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const beats = [];
|
|
138
|
+
for (let t = bestOffset; t <= duration + 0.001; t += beatInterval) {
|
|
139
|
+
beats.push(Math.round(t * 1000) / 1000);
|
|
140
|
+
}
|
|
141
|
+
return beats;
|
|
142
|
+
}
|
|
143
|
+
// Drop beats that fall in silent/near-silent regions (e.g. intro/outro) and
|
|
144
|
+
// score each surviving beat's loudness (local RMS / peak) for brightness.
|
|
145
|
+
function gateBeatsBySilence(beats, channelData, sampleRate) {
|
|
146
|
+
if (beats.length === 0)
|
|
147
|
+
return { times: beats, strengths: [], peak: 1e-6 };
|
|
148
|
+
const energies = beats.map((t) => computeRmsAt(channelData, sampleRate, t));
|
|
149
|
+
const peak = Math.max(...energies, 1e-6);
|
|
150
|
+
const threshold = peak * 0.12;
|
|
151
|
+
const times = [];
|
|
152
|
+
const strengths = [];
|
|
153
|
+
for (let i = 0; i < beats.length; i++) {
|
|
154
|
+
if (energies[i] >= threshold) {
|
|
155
|
+
times.push(beats[i]);
|
|
156
|
+
strengths.push(Math.min(1, energies[i] / peak));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return { times, strengths, peak };
|
|
160
|
+
}
|
|
161
|
+
// fallow-ignore-next-line complexity
|
|
162
|
+
export async function analyzeMusicFromBuffer(audioBuffer) {
|
|
163
|
+
const channelData = audioBuffer.getChannelData(0);
|
|
164
|
+
const sampleRate = audioBuffer.sampleRate;
|
|
165
|
+
const duration = audioBuffer.duration;
|
|
166
|
+
const rawBeats = await detectBeats(audioBuffer);
|
|
167
|
+
const onsetBpm = computeBpmFromBeats(rawBeats);
|
|
168
|
+
let detectiveBpm = null;
|
|
169
|
+
try {
|
|
170
|
+
const detect = await loadBpmDetective();
|
|
171
|
+
if (detect)
|
|
172
|
+
detectiveBpm = detect(audioBuffer);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Not enough peaks or browser context unavailable
|
|
176
|
+
}
|
|
177
|
+
let bpm = onsetBpm;
|
|
178
|
+
let confidence = "uncertain";
|
|
179
|
+
let regularizeBpm = null;
|
|
180
|
+
if (onsetBpm !== null && detectiveBpm !== null) {
|
|
181
|
+
const pctDiff = Math.abs(canonicalizeBpm(onsetBpm) - canonicalizeBpm(detectiveBpm)) /
|
|
182
|
+
canonicalizeBpm(detectiveBpm);
|
|
183
|
+
if (pctDiff < 0.05) {
|
|
184
|
+
// Detective folds tempo into 90–180; re-pick the octave nearest the onset
|
|
185
|
+
// pulse so a half-time track isn't gridded at double density.
|
|
186
|
+
bpm = octaveAlignBpm(detectiveBpm, onsetBpm);
|
|
187
|
+
confidence = "high";
|
|
188
|
+
regularizeBpm = bpm;
|
|
189
|
+
}
|
|
190
|
+
else if (pctDiff < 0.1) {
|
|
191
|
+
bpm = Math.round((onsetBpm + detectiveBpm) / 2);
|
|
192
|
+
confidence = "low";
|
|
193
|
+
regularizeBpm = bpm;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
bpm = onsetBpm;
|
|
197
|
+
confidence = "uncertain";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (onsetBpm !== null) {
|
|
201
|
+
bpm = onsetBpm;
|
|
202
|
+
confidence = "low";
|
|
203
|
+
regularizeBpm = onsetBpm;
|
|
204
|
+
}
|
|
205
|
+
else if (detectiveBpm !== null) {
|
|
206
|
+
bpm = detectiveBpm;
|
|
207
|
+
confidence = "low";
|
|
208
|
+
regularizeBpm = detectiveBpm;
|
|
209
|
+
}
|
|
210
|
+
const gridBeats = regularizeBpm !== null ? regularizeBeats(rawBeats, regularizeBpm, duration) : rawBeats;
|
|
211
|
+
const gated = gateBeatsBySilence(gridBeats, channelData, sampleRate);
|
|
212
|
+
return {
|
|
213
|
+
beatTimes: gated.times,
|
|
214
|
+
beatStrengths: gated.strengths,
|
|
215
|
+
bpm,
|
|
216
|
+
bpmConfidence: confidence,
|
|
217
|
+
channelData,
|
|
218
|
+
sampleRate,
|
|
219
|
+
peak: gated.peak,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
export async function detectBeatsFromUrl(url) {
|
|
223
|
+
const audioContext = new AudioContext();
|
|
224
|
+
try {
|
|
225
|
+
const response = await fetch(url);
|
|
226
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
227
|
+
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
|
|
228
|
+
return detectBeats(audioBuffer);
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
await audioContext.close();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export async function analyzeMusicFromUrl(url) {
|
|
235
|
+
const audioContext = new AudioContext();
|
|
236
|
+
try {
|
|
237
|
+
const response = await fetch(url);
|
|
238
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
239
|
+
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
|
|
240
|
+
return analyzeMusicFromBuffer(audioBuffer);
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
await audioContext.close();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=beatDetection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beatDetection.js","sourceRoot":"","sources":["../../src/beats/beatDetection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Project-relative path of the audio file behind a (possibly absolute) src URL. */
|
|
2
|
+
export declare function audioRelPathForSrc(src: string | null | undefined): string | null;
|
|
3
|
+
/** Path of the beat file for a given audio src, or null if it can't be derived. */
|
|
4
|
+
export declare function beatFilePathForSrc(src: string | null | undefined): string | null;
|
|
5
|
+
export declare function serializeBeats(times: number[], strengths: number[], audio: string): string;
|
|
6
|
+
export declare function parseBeats(content: string): {
|
|
7
|
+
times: number[];
|
|
8
|
+
strengths: number[];
|
|
9
|
+
} | null;
|
|
10
|
+
/**
|
|
11
|
+
* Find the music track's src in composition HTML, applying the SAME rules as the
|
|
12
|
+
* Studio's `isMusicTrack` so the CLI and Studio agree on which `<audio>` is music:
|
|
13
|
+
* the FIRST `<audio>` (in document order) where data-timeline-role="music", or —
|
|
14
|
+
* when no role is set — whose id matches the music regex. An explicit non-music
|
|
15
|
+
* role excludes the element. Returns the raw src attribute, or null.
|
|
16
|
+
*/
|
|
17
|
+
export declare function findMusicAudioSrc(html: string): string | null;
|
|
18
|
+
//# sourceMappingURL=beatFile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beatFile.d.ts","sourceRoot":"","sources":["../../src/beats/beatFile.ts"],"names":[],"mappings":"AAUA,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CA8BhF;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAGhF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAO1F;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAsB3F;AASD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgB7D"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Persistence for beat data: one JSON file per audio file, matched by the
|
|
2
|
+
// audio's project-relative path. Lives under `beats/` in the project so it
|
|
3
|
+
// survives the audio being removed and re-added.
|
|
4
|
+
/** Project-relative path of the audio file behind a (possibly absolute) src URL. */
|
|
5
|
+
export function audioRelPathForSrc(src) {
|
|
6
|
+
if (!src)
|
|
7
|
+
return null;
|
|
8
|
+
// blob:/data: URLs have no stable identity across sessions — not persistable.
|
|
9
|
+
if (/^(blob:|data:)/i.test(src))
|
|
10
|
+
return null;
|
|
11
|
+
// Studio preview URLs: /api/projects/<id>/preview[/comp]/<relpath>.
|
|
12
|
+
// Parsed with indexOf/slice (not a regex) to avoid polynomial backtracking
|
|
13
|
+
// on adversarial inputs (CodeQL js/polynomial-redos).
|
|
14
|
+
let rel = null;
|
|
15
|
+
const PREVIEW = "/preview/";
|
|
16
|
+
const previewIdx = src.indexOf(PREVIEW);
|
|
17
|
+
if (previewIdx !== -1) {
|
|
18
|
+
let after = src.slice(previewIdx + PREVIEW.length);
|
|
19
|
+
// Strip query/hash (single char class — linear, ReDoS-safe).
|
|
20
|
+
const queryOrHash = after.search(/[?#]/);
|
|
21
|
+
if (queryOrHash !== -1)
|
|
22
|
+
after = after.slice(0, queryOrHash);
|
|
23
|
+
if (after.startsWith("comp/"))
|
|
24
|
+
after = after.slice("comp/".length);
|
|
25
|
+
rel = after ? decodeURIComponent(after) : null;
|
|
26
|
+
}
|
|
27
|
+
if (!rel) {
|
|
28
|
+
// Fall back to the FULL pathname (not just basename) so two files with the
|
|
29
|
+
// same name in different folders don't collide on one beat file.
|
|
30
|
+
try {
|
|
31
|
+
rel = decodeURIComponent(new URL(src, "http://_").pathname);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
rel = src;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!rel)
|
|
38
|
+
return null;
|
|
39
|
+
rel = rel.replace(/^\/+/, "");
|
|
40
|
+
return rel || null;
|
|
41
|
+
}
|
|
42
|
+
/** Path of the beat file for a given audio src, or null if it can't be derived. */
|
|
43
|
+
export function beatFilePathForSrc(src) {
|
|
44
|
+
const rel = audioRelPathForSrc(src);
|
|
45
|
+
return rel ? `beats/${rel}.json` : null;
|
|
46
|
+
}
|
|
47
|
+
export function serializeBeats(times, strengths, audio) {
|
|
48
|
+
const beats = times.map((t, i) => ({
|
|
49
|
+
time: Math.round(t * 1000) / 1000,
|
|
50
|
+
strength: Math.round((strengths[i] ?? 0.5) * 1000) / 1000,
|
|
51
|
+
}));
|
|
52
|
+
const data = { version: 1, audio, beats };
|
|
53
|
+
return `${JSON.stringify(data, null, 2)}\n`;
|
|
54
|
+
}
|
|
55
|
+
export function parseBeats(content) {
|
|
56
|
+
try {
|
|
57
|
+
const data = JSON.parse(content);
|
|
58
|
+
// Gate on the schema version so a future v2 file (with changed semantics)
|
|
59
|
+
// isn't silently parsed as v1 — an unknown version is treated as absent.
|
|
60
|
+
if (!data || data.version !== 1 || !Array.isArray(data.beats))
|
|
61
|
+
return null;
|
|
62
|
+
const times = [];
|
|
63
|
+
const strengths = [];
|
|
64
|
+
for (const b of data.beats) {
|
|
65
|
+
if (b && typeof b.time === "number" && Number.isFinite(b.time)) {
|
|
66
|
+
times.push(b.time);
|
|
67
|
+
// Clamp to [0,1] — a hand-edited file could carry an out-of-range or
|
|
68
|
+
// non-finite strength, and the renderers feed it into Math.pow(s, 2.2)
|
|
69
|
+
// (NaN for a negative base).
|
|
70
|
+
const s = typeof b.strength === "number" && Number.isFinite(b.strength) ? b.strength : 0.5;
|
|
71
|
+
strengths.push(Math.max(0, Math.min(1, s)));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { times, strengths };
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const MUSIC_ID_RE = /\b(music|bgm|soundtrack|background[-_]?music)\b/i;
|
|
81
|
+
function attr(tag, name) {
|
|
82
|
+
const m = tag.match(new RegExp(`\\b${name}\\s*=\\s*["']([^"']*)["']`, "i"));
|
|
83
|
+
return m ? m[1] : null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Find the music track's src in composition HTML, applying the SAME rules as the
|
|
87
|
+
* Studio's `isMusicTrack` so the CLI and Studio agree on which `<audio>` is music:
|
|
88
|
+
* the FIRST `<audio>` (in document order) where data-timeline-role="music", or —
|
|
89
|
+
* when no role is set — whose id matches the music regex. An explicit non-music
|
|
90
|
+
* role excludes the element. Returns the raw src attribute, or null.
|
|
91
|
+
*/
|
|
92
|
+
export function findMusicAudioSrc(html) {
|
|
93
|
+
// `[^>]*` spans newlines (it's a negated class, not `.`), so multi-line opening
|
|
94
|
+
// tags are handled. HyperFrames authors src as an attribute on <audio>.
|
|
95
|
+
const tags = html.match(/<audio\b[^>]*>/gi) ?? [];
|
|
96
|
+
for (const tag of tags) {
|
|
97
|
+
const src = attr(tag, "src");
|
|
98
|
+
if (!src)
|
|
99
|
+
continue;
|
|
100
|
+
const role = attr(tag, "data-timeline-role");
|
|
101
|
+
if (role) {
|
|
102
|
+
if (role === "music")
|
|
103
|
+
return src;
|
|
104
|
+
continue; // explicit non-music role excludes
|
|
105
|
+
}
|
|
106
|
+
const id = attr(tag, "id");
|
|
107
|
+
if (id && MUSIC_ID_RE.test(id))
|
|
108
|
+
return src;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=beatFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beatFile.js","sourceRoot":"","sources":["../../src/beats/beatFile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/beats/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/beats/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC"}
|
|
@@ -21,14 +21,5 @@ export interface BundleOptions {
|
|
|
21
21
|
*/
|
|
22
22
|
runtime?: "inline" | "placeholder";
|
|
23
23
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Bundle a project's index.html into a single self-contained HTML file.
|
|
26
|
-
*
|
|
27
|
-
* - Compiles timing attributes and optionally resolves media durations
|
|
28
|
-
* - Injects the HyperFrames runtime script
|
|
29
|
-
* - Inlines local CSS and JS files
|
|
30
|
-
* - Inlines sub-composition HTML fragments (data-composition-src)
|
|
31
|
-
* - Inlines small textual assets as data URLs
|
|
32
|
-
*/
|
|
33
24
|
export declare function bundleToSingleHtml(projectDir: string, options?: BundleOptions): Promise<string>;
|
|
34
25
|
//# sourceMappingURL=htmlBundler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"htmlBundler.d.ts","sourceRoot":"","sources":["../../src/compiler/htmlBundler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"htmlBundler.d.ts","sourceRoot":"","sources":["../../src/compiler/htmlBundler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAsWvE,eAAO,MAAM,gCAAgC,UAW5C,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAmBrE;AA2KD,MAAM,WAAW,aAAa;IAC5B,oGAAoG;IACpG,kBAAkB,CAAC,EAAE,mBAAmB,CAAC;IACzC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,EAAE,QAAQ,GAAG,aAAa,CAAC;CACpC;AAmFD,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,MAAM,CAAC,CAyRjB"}
|