hyperframes 0.8.106 → 0.8.108

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 (177) hide show
  1. package/dist/{add-QRAI4CAF.js → add-OH75E7FX.js} +16 -16
  2. package/dist/{animatedGifPrep-RZVYVAXD.js → animatedGifPrep-ZDAWSJYL.js} +7 -7
  3. package/dist/{asset-WFBQ5VS6.js → asset-BVDO4DEW.js} +2 -2
  4. package/dist/{assetCataloger-BQREHRS2.js → assetCataloger-FXEHOUA3.js} +3 -3
  5. package/dist/{auth-LVD6TWYG.js → auth-K5GUKO5S.js} +2 -2
  6. package/dist/{autoUpdate-HGE2PUZY.js → autoUpdate-77ROWK5G.js} +2 -2
  7. package/dist/{backgroundChecks-63CSE4XR.js → backgroundChecks-3Q3D5WBJ.js} +3 -3
  8. package/dist/backgroundChecksWorker.js +3 -3
  9. package/dist/{batchRender-AQN5PRXM.js → batchRender-ZTHFMHZY.js} +4 -4
  10. package/dist/{beats-OBCN5OSQ.js → beats-HQZPR6KE.js} +19 -13
  11. package/dist/{benchmark-DYHJSR7W.js → benchmark-BQOWARGU.js} +13 -13
  12. package/dist/{browser-JLYV5T7O.js → browser-45CK7HXI.js} +10 -10
  13. package/dist/{bundleWithLocalizedFonts-JKJKZR2S.js → bundleWithLocalizedFonts-3M2LKRHK.js} +2 -2
  14. package/dist/{capture-5BCJWVC7.js → capture-6IVZXM7G.js} +2 -2
  15. package/dist/{capture-QYLHIYKJ.js → capture-VGEUOP7N.js} +8 -8
  16. package/dist/{catalog-6UYNKENR.js → catalog-VHD7B6FD.js} +16 -16
  17. package/dist/{check-YOGAZ6UE.js → check-UPNZZJXV.js} +32 -31
  18. package/dist/{checkBrowser-M73YHPNM.js → checkBrowser-KWTHKOOP.js} +31 -30
  19. package/dist/{chunk-JYRPUDVZ.js → chunk-5N4KKGSZ.js} +1 -1
  20. package/dist/{normalize-audio-H3SI5V63.js → chunk-5ON5GH3X.js} +101 -209
  21. package/dist/{chunk-NRMYDPFQ.js → chunk-5R5UHSXN.js} +9 -9
  22. package/dist/{chunk-OSZJCBZX.js → chunk-AFGDOKRI.js} +7 -7
  23. package/dist/{chunk-6CN2QLB5.js → chunk-AWUZ3AUD.js} +1 -1
  24. package/dist/{chunk-TEXPOC5V.js → chunk-B25H4M4V.js} +2 -2
  25. package/dist/{chunk-JXXE3SWC.js → chunk-C6XQER6H.js} +28 -14
  26. package/dist/{chunk-Y2CZEJPK.js → chunk-CFC3EEDQ.js} +2 -2
  27. package/dist/{chunk-PB2OX2JY.js → chunk-D7SCIX4D.js} +1 -1
  28. package/dist/{chunk-AXWBDWAV.js → chunk-FZGUZIK5.js} +3 -3
  29. package/dist/{chunk-4WAMN4IF.js → chunk-GYYFNAVA.js} +1 -1
  30. package/dist/{chunk-TYA65W4U.js → chunk-HQGJLZB6.js} +2 -2
  31. package/dist/{chunk-LAHK4P7Q.js → chunk-J7XPPADY.js} +3 -3
  32. package/dist/{chunk-I77CAR4W.js → chunk-KVOWTRD5.js} +2 -2
  33. package/dist/{chunk-GVZYTDOD.js → chunk-KZ5OSG4G.js} +1 -1
  34. package/dist/{chunk-IBCGKQB5.js → chunk-KZJ6V7RT.js} +3 -3
  35. package/dist/{chunk-HUHJYNST.js → chunk-LAQEZHOH.js} +1 -1
  36. package/dist/{chunk-HFFR7TN7.js → chunk-LPXM5L6S.js} +2 -1
  37. package/dist/{chunk-2IZZZJDZ.js → chunk-LTYI4E42.js} +4 -4
  38. package/dist/{chunk-J3Q3YC6P.js → chunk-LZPAZZZP.js} +1 -1
  39. package/dist/{chunk-5TBFBLIX.js → chunk-MGTECHI3.js} +2 -2
  40. package/dist/{chunk-4I6AQUWG.js → chunk-NGVH2QYT.js} +8 -8
  41. package/dist/{chunk-M4KS6MJN.js → chunk-NJLFRKHX.js} +4 -4
  42. package/dist/{chunk-6LPWMCPY.js → chunk-NROJESOK.js} +2 -2
  43. package/dist/{chunk-UVUAU3CH.js → chunk-ONY5CJXS.js} +48 -26
  44. package/dist/{chunk-O5TBFZ7X.js → chunk-OVRFBUXU.js} +2 -2
  45. package/dist/{chunk-6F6EEQNB.js → chunk-PSGDNMM6.js} +1 -1
  46. package/dist/{chunk-AZQLJHAO.js → chunk-PZTEY73C.js} +1 -1
  47. package/dist/{chunk-VW5OMJNG.js → chunk-QB6OM2BP.js} +89 -70
  48. package/dist/{chunk-I6M4GXMC.js → chunk-QBHT234I.js} +1 -1
  49. package/dist/{chunk-TMLEIURT.js → chunk-QRXICW5Q.js} +1 -1
  50. package/dist/{chunk-4NJZZHYT.js → chunk-RPMXMOFU.js} +1 -1
  51. package/dist/{chunk-XZSH5GS7.js → chunk-RSL3XFMO.js} +4 -4
  52. package/dist/{chunk-PUB5XZYL.js → chunk-SIVCJJHE.js} +1 -1
  53. package/dist/{chunk-UUE5BZGE.js → chunk-SQ42NHXP.js} +620 -74
  54. package/dist/{chunk-GOI4GCUB.js → chunk-THVNQFYG.js} +1 -1
  55. package/dist/{chunk-IQ4UCWV7.js → chunk-TIZQC44K.js} +1 -1
  56. package/dist/{chunk-FTXU3TQ4.js → chunk-US7SWKGC.js} +1 -1
  57. package/dist/{chunk-TLYU5625.js → chunk-UUDQD62L.js} +6 -6
  58. package/dist/{chunk-2LCIQS3K.js → chunk-VBXJSCHR.js} +3 -3
  59. package/dist/{chunk-DVCYGZ7R.js → chunk-VLHN34SB.js} +2 -2
  60. package/dist/{chunk-4Z5O7BTD.js → chunk-WEATBQTR.js} +10 -1
  61. package/dist/{chunk-TH4APNRP.js → chunk-X763EUBO.js} +2 -2
  62. package/dist/{chunk-32Y3HRS3.js → chunk-XIGK4LNU.js} +2 -2
  63. package/dist/{chunk-R5RF3LGS.js → chunk-XMAL2A7Y.js} +1 -1
  64. package/dist/{chunk-USWOTTSP.js → chunk-XYVFPDNU.js} +1 -1
  65. package/dist/chunk-YLVI7VL5.js +3541 -0
  66. package/dist/{chunk-YVWILZCO.js → chunk-ZFL6FVQZ.js} +5 -5
  67. package/dist/{clean-GRX3GXKR.js → clean-LCRWNIWO.js} +17 -16
  68. package/dist/cli.js +50 -50
  69. package/dist/{cloud-TQCNBM6H.js → cloud-ITRFE5UN.js} +4 -4
  70. package/dist/{cloudrun-ISE6GSUO.js → cloudrun-LVZ4OPPC.js} +5 -5
  71. package/dist/{compare-QAWB3O4U.js → compare-NPVMUILH.js} +26 -25
  72. package/dist/{compiler-QMEZK6CU.js → compiler-YYOV2BJ7.js} +3 -3
  73. package/dist/{component-NXNNSXN7.js → component-HJFMHPNW.js} +3 -3
  74. package/dist/{compositions-I4PIPJKO.js → compositions-I34RN5WD.js} +12 -12
  75. package/dist/{delete-ZC4ZRBBF.js → delete-WN3J74BD.js} +4 -4
  76. package/dist/{deterministicFonts-XS3PGWH5.js → deterministicFonts-A4CNCSAL.js} +2 -2
  77. package/dist/{dist-E44WU6LH.js → dist-WCMFH74H.js} +1 -1
  78. package/dist/{dist-R24TLUYO.js → dist-YUIPB7OX.js} +9 -3
  79. package/dist/docs/data-attributes.md +1 -1
  80. package/dist/{doctor-EFQ4XNT3.js → doctor-MYC2S3J3.js} +11 -11
  81. package/dist/{events-AVPSJNYU.js → events-7JVV4746.js} +10 -10
  82. package/dist/{events-COIPJKSK.js → events-AEUV2JPA.js} +9 -9
  83. package/dist/{feedback-3DYZDMLC.js → feedback-X7DDSZPU.js} +11 -11
  84. package/dist/{figma-7XPHSMNG.js → figma-ISI4PPTF.js} +3 -3
  85. package/dist/fontLocalizeCli.js +10 -10
  86. package/dist/{get-TSBHDMKL.js → get-IYALAE4I.js} +4 -4
  87. package/dist/{gpuPolicy-BQFPO7UA.js → gpuPolicy-KSWTVU5C.js} +7 -7
  88. package/dist/{grade-compare-5Y4LXQFG.js → grade-compare-YWPIWQLK.js} +26 -25
  89. package/dist/{gsapParser-EZGJSSV5.js → gsapParser-KVMPC2SC.js} +5 -1
  90. package/dist/{help-5YBRP3C4.js → help-S2KJRMAJ.js} +1 -1
  91. package/dist/{history-SRNXKL6D.js → history-CQDDCY4J.js} +17 -16
  92. package/dist/hyperframe-runtime.js +54 -54
  93. package/dist/hyperframe.manifest.json +1 -1
  94. package/dist/hyperframe.runtime.iife.js +54 -54
  95. package/dist/hyperframes-player.global.js +3 -3
  96. package/dist/{info-U4BOXV2I.js → info-4KFNUWYN.js} +12 -12
  97. package/dist/{init-T4JYHIBM.js → init-I7GMRHFW.js} +98 -42
  98. package/dist/{inspect-XYLD2BMM.js → inspect-DUCLCHSD.js} +27 -26
  99. package/dist/{installer-UZSVMUKT.js → installer-NBEN3ZIP.js} +5 -5
  100. package/dist/{keyframes-BGPXWP7O.js → keyframes-F3VDEN66.js} +13 -13
  101. package/dist/{lambda-U4WIJQCJ.js → lambda-BFHJMMCG.js} +6 -6
  102. package/dist/{layout-UREZQ37U.js → layout-RNCXJI6C.js} +27 -26
  103. package/dist/{lint-LSTEZZ6T.js → lint-3NKKYCMH.js} +13 -13
  104. package/dist/{lintProject-4P4C6AN2.js → lintProject-F2OTN2IR.js} +1 -1
  105. package/dist/{list-6VICFTAM.js → list-Q7SOE3NF.js} +4 -4
  106. package/dist/{login-MXDIDOOG.js → login-TGRGWS5E.js} +4 -4
  107. package/dist/{media-treatment-ZVCWEACM.js → media-treatment-5TUXWHWE.js} +13 -13
  108. package/dist/{models-LXUIU5DC.js → models-YJUTM6TH.js} +8 -8
  109. package/dist/{motionShot-2LYUQF3T.js → motionShot-5QUMZ7J3.js} +11 -11
  110. package/dist/normalize-audio-63BI5BPL.js +276 -0
  111. package/dist/{pipeline-OFFKTFXS.js → pipeline-4NN5T7Q3.js} +7 -7
  112. package/dist/{play-P56CWNVC.js → play-SRDESSZI.js} +22 -21
  113. package/dist/{preflight-TVCVP5P2.js → preflight-SVN4PSFO.js} +8 -8
  114. package/dist/{present-ATMOWKMH.js → present-TDYR5LRW.js} +18 -17
  115. package/dist/{preview-7U6HYHYE.js → preview-Z5MFRZUM.js} +18 -18
  116. package/dist/{producer-LGG3TOUI.js → producer-RS7CB3XJ.js} +1 -1
  117. package/dist/{projectConfig-V53SEFIS.js → projectConfig-JHEWPAA5.js} +7 -7
  118. package/dist/{publication-7RKKPKLM.js → publication-7XA2H7UB.js} +3 -3
  119. package/dist/{publish-TRRFCEMQ.js → publish-2R22XX77.js} +9 -9
  120. package/dist/{remove-background-HJFT46Z5.js → remove-background-KT2SWYCC.js} +8 -8
  121. package/dist/{render-TPZ5FXHS.js → render-4C3YKVZI.js} +4 -4
  122. package/dist/{render-YB7BARWL.js → render-7GDLEGXT.js} +15 -15
  123. package/dist/{render-2QZBNE2V.js → render-Y2Y7N5WD.js} +22 -22
  124. package/dist/{render-batch-4ZF5C2LN.js → render-batch-AFDBPDMM.js} +4 -4
  125. package/dist/{renderCancellation-4PYGAN5D.js → renderCancellation-RQ3UVNVJ.js} +7 -7
  126. package/dist/renderSetupWorker.js +1 -1
  127. package/dist/{resolver-4JRJPC6S.js → resolver-S72XBTEQ.js} +5 -5
  128. package/dist/{sherpa-MNCWRFD4.js → sherpa-PR3I4KGM.js} +10 -10
  129. package/dist/{skills-ETBA5B46.js → skills-BEYZZWY6.js} +12 -12
  130. package/dist/{skillsUpdateCheck-DQOUIYV5.js → skillsUpdateCheck-3USXDPWV.js} +3 -3
  131. package/dist/{snapshot-W3HTBAYH.js → snapshot-S77MQOV2.js} +27 -26
  132. package/dist/{src-QX5PPANW.js → src-6R4DC2YI.js} +6 -6
  133. package/dist/{src-QF6RYX76.js → src-IOJXK4VC.js} +9 -9
  134. package/dist/{staticProjectServer-WBXW2CA4.js → staticProjectServer-RXAFGDK7.js} +16 -15
  135. package/dist/{status-C3IDZFDG.js → status-CRS7H6FA.js} +7 -7
  136. package/dist/studio/assets/{hyperframes-player-dl6K6ABp.js → hyperframes-player-BakGew45.js} +1 -1
  137. package/dist/studio/assets/{index-ooaZZhKf.js → index-C5dyUHwk.js} +1 -1
  138. package/dist/studio/assets/{index-CMiYVGv5.js → index-C842tcVa.js} +203 -208
  139. package/dist/studio/assets/{index-DKT5NF1Y.js → index-CPe7d_wO.js} +1 -1
  140. package/dist/studio/assets/{index-lrT-gfHa.css → index-ncVJ5IVu.css} +1 -1
  141. package/dist/studio/chunk-6LUNLTHR.js +611 -0
  142. package/dist/studio/chunk-6LUNLTHR.js.map +1 -0
  143. package/dist/studio/{chunk-ICTZJPQQ.js → chunk-AOWVEVEU.js} +3 -494
  144. package/dist/studio/chunk-AOWVEVEU.js.map +1 -0
  145. package/dist/studio/{chunk-46XP7J3B.js → chunk-PQFEBX32.js} +5 -3
  146. package/dist/studio/chunk-PQFEBX32.js.map +1 -0
  147. package/dist/studio/{domEditingLayers-AQBDFNUC.js → domEditingLayers-JQPQGGT7.js} +3 -3
  148. package/dist/studio/index.d.ts +377 -12
  149. package/dist/studio/index.html +2 -2
  150. package/dist/studio/index.js +13445 -11874
  151. package/dist/studio/index.js.map +1 -1
  152. package/dist/studio/player.js +2 -2
  153. package/dist/studio/styles.css +1 -1
  154. package/dist/{studio-api-6IJPJVG6.js → studio-api-3FH7OSSS.js} +10 -9
  155. package/dist/{studioServer-77CY4XPO.js → studioServer-4E5RRPU7.js} +49 -42
  156. package/dist/{system-OAB2LYBV.js → system-YMANAUAM.js} +7 -7
  157. package/dist/{telemetry-XTN5BO5S.js → telemetry-46XSB2VN.js} +10 -10
  158. package/dist/templates/_shared/AGENTS.md +1 -1
  159. package/dist/templates/_shared/CLAUDE.md +1 -1
  160. package/dist/templates/from-file/index.html +3 -2
  161. package/dist/templates/warm-grain/index.html +2 -10
  162. package/dist/{timeline-YKKTGPL7.js → timeline-XKLKHGD2.js} +17 -16
  163. package/dist/{tokens-LU25F3IJ.js → tokens-JCZKPUPT.js} +2 -2
  164. package/dist/{transcribe-O7OL4RRU.js → transcribe-FIFJ3BBB.js} +13 -13
  165. package/dist/{transcribe-AL3E5MBZ.js → transcribe-FQ4YC2AS.js} +10 -8
  166. package/dist/{updateCheck-MZZML4DL.js → updateCheck-PDIH4GZW.js} +2 -2
  167. package/dist/{upgrade-PQRTEJJY.js → upgrade-TTGO6JCF.js} +2 -2
  168. package/dist/{urlDownloader-U3TNOPD5.js → urlDownloader-32JRHOPN.js} +6 -6
  169. package/dist/{validate-KQETGCIR.js → validate-G5F56ONL.js} +16 -16
  170. package/dist/{video-KAHL76HG.js → video-SGBEMEKA.js} +7 -7
  171. package/package.json +1 -1
  172. package/dist/chunk-FOKUJKBN.js +0 -3420
  173. package/dist/studio/chunk-46XP7J3B.js.map +0 -1
  174. package/dist/studio/chunk-DI4LCJHL.js +0 -102
  175. package/dist/studio/chunk-DI4LCJHL.js.map +0 -1
  176. package/dist/studio/chunk-ICTZJPQQ.js.map +0 -1
  177. /package/dist/studio/{domEditingLayers-AQBDFNUC.js.map → domEditingLayers-JQPQGGT7.js.map} +0 -0
@@ -4,64 +4,21 @@ import { dirname as __hf_dirname } from "node:path";
4
4
  var require = __hf_createRequire(import.meta.url);
5
5
  var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
- import {
8
- resolveProject
9
- } from "./chunk-FTXU3TQ4.js";
10
- import "./chunk-IHFUKJOR.js";
11
- import "./chunk-2LCIQS3K.js";
12
- import "./chunk-LAHK4P7Q.js";
13
- import "./chunk-VWG7OQKU.js";
14
- import {
15
- c
16
- } from "./chunk-ZTZA4UWZ.js";
17
- import "./chunk-PUB5XZYL.js";
18
- import "./chunk-AMKC3AXA.js";
19
- import {
20
- defineCommand
21
- } from "./chunk-S3S4TGEH.js";
22
- import "./chunk-54HJ63Q2.js";
23
- import {
24
- failCommand
25
- } from "./chunk-PBN6GBJE.js";
26
- import "./chunk-VW5OMJNG.js";
27
- import "./chunk-TEXPOC5V.js";
28
- import "./chunk-TLYU5625.js";
29
- import "./chunk-DPVXBVLL.js";
30
- import "./chunk-TH4APNRP.js";
31
7
  import {
32
8
  MAX_AUDIO_GAIN_DB,
33
- formatAudioGain
34
- } from "./chunk-FOKUJKBN.js";
35
- import "./chunk-VC76R6W2.js";
36
- import "./chunk-OFQWTKPW.js";
37
- import "./chunk-TWWSYAKJ.js";
38
- import "./chunk-UVUAU3CH.js";
39
- import "./chunk-HBBJFK6I.js";
9
+ formatAudioGain,
10
+ isAudibleVideoElement
11
+ } from "./chunk-YLVI7VL5.js";
40
12
  import {
41
13
  findFfBinary
42
14
  } from "./chunk-PJ3HDUCY.js";
43
- import "./chunk-TQFG7HTI.js";
44
- import "./chunk-GK4AIFIH.js";
45
- import "./chunk-2PSPARWP.js";
46
- import "./chunk-K4WIOZFP.js";
47
- import "./chunk-XUXGIA7H.js";
48
- import "./chunk-WERLJGIC.js";
49
- import "./chunk-ISN5GRYI.js";
50
- import "./chunk-6LPWMCPY.js";
51
- import "./chunk-KNU5COPB.js";
52
- import "./chunk-3GXQPCJC.js";
53
- import "./chunk-RQVDTPGD.js";
54
- import "./chunk-PMRBLBUP.js";
55
- import "./chunk-M2WBOQ2Q.js";
56
15
 
57
- // src/commands/normalize-audio.ts
16
+ // ../studio-server/dist/chunk-TEYDBVSK.js
58
17
  import { execFile } from "child_process";
59
- import { existsSync, readFileSync, renameSync, writeFileSync } from "fs";
60
18
  import { isAbsolute, relative, resolve } from "path";
61
19
  import { promisify } from "util";
62
20
  var execFileAsync = promisify(execFile);
63
21
  var FFMPEG_TIMEOUT_MS = 12e4;
64
- var DEFAULT_TOLERANCE_LU = 0.5;
65
22
  function authoredNumber(raw, fallback, attribute, id, strictlyPositive = false) {
66
23
  if (raw === void 0) return fallback;
67
24
  const value = Number(raw);
@@ -121,14 +78,28 @@ function commentEnd(html, start) {
121
78
  if (end < 0) throw new Error("Unterminated HTML comment");
122
79
  return end + 3;
123
80
  }
81
+ var isSpaceAt = (html, index) => /\s/.test(html.charAt(index));
82
+ var isWordAt = (html, index) => /\w/.test(html.charAt(index));
83
+ function skipSpaces(html, index) {
84
+ let cursor = index;
85
+ while (cursor < html.length && isSpaceAt(html, cursor)) cursor++;
86
+ return cursor;
87
+ }
124
88
  function parsedStartTag(html, start) {
125
- const match = html.slice(start).match(/^<\s*(\/?)\s*([a-z][a-z\d:-]*)\b/i);
126
- if (!match) return null;
89
+ let cursor = skipSpaces(html, start + 1);
90
+ const closing = html.charAt(cursor) === "/";
91
+ if (closing) cursor = skipSpaces(html, cursor + 1);
92
+ const nameStart = cursor;
93
+ if (!/[a-z]/i.test(html.charAt(cursor))) return null;
94
+ while (/[a-z\d:-]/i.test(html.charAt(cursor + 1))) cursor++;
95
+ let nameEnd = cursor + 1;
96
+ while (nameEnd > nameStart && isWordAt(html, nameEnd - 1) === isWordAt(html, nameEnd)) nameEnd--;
97
+ if (nameEnd === nameStart) return null;
127
98
  return {
128
99
  start,
129
100
  end: startTagEnd(html, start),
130
- closing: match[1] === "/",
131
- name: match[2]?.toLowerCase() ?? ""
101
+ closing,
102
+ name: html.slice(nameStart, nameEnd).toLowerCase()
132
103
  };
133
104
  }
134
105
  function rawTextElementEnd(html, lower, tag) {
@@ -139,20 +110,26 @@ function rawTextElementEnd(html, lower, tag) {
139
110
  }
140
111
  function scanMarkup(html, lower, start) {
141
112
  if (html.startsWith("<!--", start)) {
142
- return { cursor: commentEnd(html, start), audioRange: null };
113
+ return { cursor: commentEnd(html, start), mediaRange: null };
143
114
  }
144
115
  const tag = parsedStartTag(html, start);
145
116
  if (!tag) {
146
117
  const marker = html[start + 1];
147
118
  const cursor = marker === "!" || marker === "?" ? startTagEnd(html, start) : start + 1;
148
- return { cursor, audioRange: null };
119
+ return { cursor, mediaRange: null };
149
120
  }
150
121
  const rawTextEnd = rawTextElementEnd(html, lower, tag);
151
- if (rawTextEnd !== null) return { cursor: rawTextEnd, audioRange: null };
152
- const audioRange = !tag.closing && tag.name === "audio" ? { start, end: tag.end } : null;
153
- return { cursor: tag.end, audioRange };
122
+ if (rawTextEnd !== null) return { cursor: rawTextEnd, mediaRange: null };
123
+ return { cursor: tag.end, mediaRange: mediaRangeOf(tag) };
154
124
  }
155
- function audioTagRanges(html) {
125
+ function mediaRangeOf(tag) {
126
+ if (tag.closing) return null;
127
+ if (tag.name === "audio" || tag.name === "video") {
128
+ return { start: tag.start, end: tag.end, name: tag.name };
129
+ }
130
+ return null;
131
+ }
132
+ function mediaTagRanges(html) {
156
133
  const lower = html.toLowerCase();
157
134
  const ranges = [];
158
135
  let cursor = 0;
@@ -160,7 +137,7 @@ function audioTagRanges(html) {
160
137
  const start = html.indexOf("<", cursor);
161
138
  if (start < 0) break;
162
139
  const scanned = scanMarkup(html, lower, start);
163
- if (scanned.audioRange) ranges.push(scanned.audioRange);
140
+ if (scanned.mediaRange) ranges.push(scanned.mediaRange);
164
141
  cursor = scanned.cursor;
165
142
  }
166
143
  return ranges;
@@ -184,11 +161,27 @@ function requiredAudioIdentity(attributes) {
184
161
  if (!src) throw new Error(`Audio #${id} has no src`);
185
162
  return { id, src };
186
163
  }
187
- function audioTagFromRange(html, range) {
164
+ function hasBareAttribute(html, range, name) {
165
+ const unquoted = html.slice(range.start, range.end).replace(/"[^"]*"|'[^']*'/g, '""');
166
+ return new RegExp(`\\s${name}(?=[\\s/>=])`, "i").test(unquoted);
167
+ }
168
+ function isAudibleVideoTag(html, range, attributes) {
169
+ return isAudibleVideoElement({
170
+ tagName: "video",
171
+ hasAttribute: (name) => attributes.has(name) || hasBareAttribute(html, range, name),
172
+ getAttribute: (name) => attributes.get(name)?.value ?? null
173
+ });
174
+ }
175
+ function inScopeVideo(html, range, attributes) {
176
+ return isAudibleVideoTag(html, range, attributes) && trimmedAttribute(attributes, "id") !== "" && trimmedAttribute(attributes, "src") !== "";
177
+ }
178
+ function mediaTagFromRange(html, range) {
188
179
  const attributes = attributesInTag(html, range.start, range.end);
180
+ if (range.name === "video" && !inScopeVideo(html, range, attributes)) return null;
189
181
  const { id, src } = requiredAudioIdentity(attributes);
190
182
  const volumeAttribute = attributes.get("data-volume") ?? null;
191
183
  return {
184
+ tag: range.name,
192
185
  id,
193
186
  src,
194
187
  volume: authoredNumber(volumeAttribute?.value, 1, "data-volume", id),
@@ -199,6 +192,13 @@ function audioTagFromRange(html, range) {
199
192
  id
200
193
  ),
201
194
  duration: authoredDuration(attributes, id),
195
+ playbackRate: authoredNumber(
196
+ attributes.get("data-playback-rate")?.value,
197
+ 1,
198
+ "data-playback-rate",
199
+ id,
200
+ true
201
+ ),
202
202
  start: range.start,
203
203
  end: range.end,
204
204
  volumeAttribute
@@ -207,8 +207,9 @@ function audioTagFromRange(html, range) {
207
207
  function audioTags(html) {
208
208
  const seen = /* @__PURE__ */ new Set();
209
209
  const tags = [];
210
- for (const range of audioTagRanges(html)) {
211
- const tag = audioTagFromRange(html, range);
210
+ for (const range of mediaTagRanges(html)) {
211
+ const tag = mediaTagFromRange(html, range);
212
+ if (!tag) continue;
212
213
  if (seen.has(tag.id)) throw new Error(`Duplicate audio id "${tag.id}"`);
213
214
  seen.add(tag.id);
214
215
  tags.push(tag);
@@ -305,7 +306,8 @@ function updateAudioVolume(html, id, volume) {
305
306
  function loudnessMeasureArgs(file, tag) {
306
307
  const args = ["-hide_banner", "-nostats"];
307
308
  if (tag.mediaStart > 0) args.push("-ss", String(tag.mediaStart));
308
- if (tag.duration !== null && tag.duration > 0) args.push("-t", String(tag.duration));
309
+ const sourceSpan = tag.duration === null ? null : tag.duration * (tag.playbackRate ?? 1);
310
+ if (sourceSpan !== null && sourceSpan > 0) args.push("-t", String(sourceSpan));
309
311
  args.push("-i", file, "-map", "0:a:0", "-vn", "-af", "ebur128=peak=true", "-f", "null", "-");
310
312
  return args;
311
313
  }
@@ -317,162 +319,52 @@ async function measureAudio(ffmpegPath, file, tag) {
317
319
  });
318
320
  return parseEbur128Summary(result.stderr);
319
321
  }
320
- function fail(message, json, cause) {
321
- if (json) console.log(JSON.stringify({ ok: false, error: message }, null, 2));
322
- else console.error(c.error(message));
323
- failCommand(1, cause);
324
- }
325
- function byId(tags, rawId, role) {
326
- const id = rawId.trim().replace(/^#/, "");
327
- const tag = tags.find((candidate) => candidate.id === id);
328
- if (!tag) throw new Error(`${role} audio #${id} was not found`);
329
- return tag;
330
- }
331
- function selectedTags(html, referenceId, targetId) {
332
- const tags = audioTags(html);
333
- const referenceTag = byId(tags, referenceId, "Reference");
334
- const targetTag = byId(tags, targetId, "Target");
335
- if (referenceTag.id === targetTag.id) {
336
- throw new Error("Reference and target must be different audio elements");
337
- }
338
- return { referenceTag, targetTag };
339
- }
340
322
  function requiredFfmpeg() {
341
323
  const ffmpegPath = findFfBinary("ffmpeg", { configuredMustExist: true });
342
324
  if (!ffmpegPath) throw new Error("FFmpeg is required to measure integrated loudness");
343
325
  return ffmpegPath;
344
326
  }
345
- function existingAudioFile(projectDir, tag) {
346
- const file = resolveLocalAudioPath(projectDir, tag.src);
347
- if (!existsSync(file)) {
348
- throw new Error(`Audio #${tag.id} file was not found: ${relative(projectDir, file)}`);
349
- }
350
- return file;
351
- }
352
- async function measuredPlan(projectDir, referenceTag, targetTag) {
353
- const ffmpegPath = requiredFfmpeg();
354
- const referenceFile = existingAudioFile(projectDir, referenceTag);
355
- const targetFile = existingAudioFile(projectDir, targetTag);
356
- const [referenceMeasurement, targetMeasurement] = await Promise.all([
357
- measureAudio(ffmpegPath, referenceFile, referenceTag),
358
- measureAudio(ffmpegPath, targetFile, targetTag)
359
- ]);
360
- return audioNormalizationPlan(
361
- { id: referenceTag.id, volume: referenceTag.volume, ...referenceMeasurement },
362
- { id: targetTag.id, volume: targetTag.volume, ...targetMeasurement }
363
- );
364
- }
365
- function writeAtomically(path, contents) {
366
- const temporary = `${path}.hf-normalize-${process.pid}.tmp`;
367
- writeFileSync(temporary, contents);
368
- renameSync(temporary, path);
369
- }
370
- function parsedTolerance(raw) {
371
- const tolerance = Number(raw);
372
- if (!Number.isFinite(tolerance) || tolerance < 0) {
373
- throw new Error("--tolerance must be a non-negative number");
374
- }
375
- return tolerance;
376
- }
377
- async function normalizeAudio(options) {
378
- const project = resolveProject(options.dir);
379
- const html = readFileSync(project.indexPath, "utf8");
380
- const { referenceTag, targetTag } = selectedTags(html, options.reference, options.target);
381
- const tolerance = parsedTolerance(options.tolerance);
382
- const plan = await measuredPlan(project.dir, referenceTag, targetTag);
383
- const withinTolerance = Math.abs(plan.referenceLufs - plan.targetLufs) <= tolerance;
384
- const wrote = options.write && !withinTolerance;
385
- if (wrote) {
386
- writeAtomically(
387
- project.indexPath,
388
- updateAudioVolume(readFileSync(project.indexPath, "utf8"), targetTag.id, plan.volume)
389
- );
327
+ var DEFAULT_TARGET_LUFS = -16;
328
+ var NORMALIZE_TRUE_PEAK_CEILING_DBFS = -1.5;
329
+ var SILENCE_LUFS = -70;
330
+ function absoluteLoudnessPlan(track, targetLufs = DEFAULT_TARGET_LUFS) {
331
+ if (track.integratedLufs <= SILENCE_LUFS) {
332
+ throw new Error(`#${track.id} is silent in the played window; there is nothing to normalize`);
390
333
  }
391
- return { ok: true, wrote, withinTolerance, tolerance, indexPath: project.indexPath, ...plan };
392
- }
393
- function printHumanResult(result) {
394
- console.log(
395
- `${c.bold(`#${result.referenceId}`)} ${result.referenceLufs.toFixed(1)} LUFS \u2192 ${c.bold(`#${result.targetId}`)} ${result.targetLufs.toFixed(1)} LUFS`
396
- );
397
- if (result.withinTolerance) {
398
- console.log(
399
- c.success(`Already matched within ${result.tolerance.toFixed(1)} LU; no change needed.`)
400
- );
401
- return;
402
- }
403
- console.log(
404
- `Set #${result.targetId} data-volume ${result.previousVolume.toFixed(3)} \u2192 ${result.volume.toFixed(6)} (${result.changeDb >= 0 ? "+" : ""}${result.changeDb.toFixed(1)} dB).`
405
- );
406
- console.log(
407
- result.wrote ? c.success(`Updated ${relative(process.cwd(), result.indexPath) || "index.html"}.`) : c.dim("Dry run only. Pass --write to persist this gain.")
334
+ const wantedGainDb = targetLufs - track.integratedLufs;
335
+ const peakRoomDb = NORMALIZE_TRUE_PEAK_CEILING_DBFS - track.truePeakDbfs;
336
+ const limits = [
337
+ [null, wantedGainDb],
338
+ ["gain-ceiling", MAX_AUDIO_GAIN_DB],
339
+ ["true-peak", peakRoomDb]
340
+ ];
341
+ const [limitedBy, appliedGainDb] = limits.reduce(
342
+ (lowest, candidate) => candidate[1] < lowest[1] - 1e-9 ? candidate : lowest
408
343
  );
344
+ const previousGainDb = track.volume > 0 ? gainDb(track.volume) : 0;
345
+ return {
346
+ targetId: track.id,
347
+ targetLufs,
348
+ sourceLufs: track.integratedLufs,
349
+ previousVolume: track.volume,
350
+ volume: 10 ** (appliedGainDb / 20),
351
+ gainDb: appliedGainDb,
352
+ changeDb: appliedGainDb - previousGainDb,
353
+ projectedLufs: track.integratedLufs + appliedGainDb,
354
+ projectedTruePeakDbfs: track.truePeakDbfs + appliedGainDb,
355
+ limitedBy
356
+ };
409
357
  }
410
- var examples = [
411
- [
412
- "Measure two authored clips and preview the matching gain",
413
- "hyperframes normalize-audio --reference target-audio --target user-audio"
414
- ],
415
- [
416
- "Persist the measured gain into index.html",
417
- "hyperframes normalize-audio --reference target-audio --target user-audio --write"
418
- ]
419
- ];
420
- var normalize_audio_default = defineCommand({
421
- meta: {
422
- name: "normalize-audio",
423
- description: "Match one local audio clip to another using integrated LUFS"
424
- },
425
- args: {
426
- dir: { type: "positional", description: "Project directory", required: false },
427
- reference: {
428
- type: "string",
429
- description: "Audio element id whose effective loudness should be preserved",
430
- required: true
431
- },
432
- target: {
433
- type: "string",
434
- description: "Audio element id whose data-volume should be matched",
435
- required: true
436
- },
437
- write: {
438
- type: "boolean",
439
- description: "Persist the measured target gain into index.html",
440
- default: false
441
- },
442
- tolerance: {
443
- type: "string",
444
- description: `Skip writes within this many LU (default ${DEFAULT_TOLERANCE_LU})`,
445
- default: String(DEFAULT_TOLERANCE_LU)
446
- },
447
- json: { type: "boolean", description: "Print machine-readable output", default: false }
448
- },
449
- async run({ args }) {
450
- try {
451
- const result = await normalizeAudio({
452
- dir: args.dir,
453
- reference: args.reference,
454
- target: args.target,
455
- tolerance: args.tolerance,
456
- write: args.write
457
- });
458
- if (args.json) {
459
- const { indexPath: _, ...jsonResult } = result;
460
- console.log(JSON.stringify(jsonResult, null, 2));
461
- return;
462
- }
463
- printHumanResult(result);
464
- } catch (error) {
465
- fail(error instanceof Error ? error.message : String(error), Boolean(args.json), error);
466
- }
467
- }
468
- });
358
+
469
359
  export {
470
- audioNormalizationPlan,
471
360
  audioTags,
472
- normalize_audio_default as default,
473
- examples,
474
- loudnessMeasureArgs,
475
- parseEbur128Summary,
476
361
  resolveLocalAudioPath,
477
- updateAudioVolume
362
+ parseEbur128Summary,
363
+ audioNormalizationPlan,
364
+ updateAudioVolume,
365
+ loudnessMeasureArgs,
366
+ measureAudio,
367
+ requiredFfmpeg,
368
+ DEFAULT_TARGET_LUFS,
369
+ absoluteLoudnessPlan
478
370
  };
@@ -8,13 +8,13 @@ import {
8
8
  installPageFunctionGuard,
9
9
  resolveCliChromeGpuMode,
10
10
  seekCompositionTimeline
11
- } from "./chunk-XZSH5GS7.js";
11
+ } from "./chunk-RSL3XFMO.js";
12
12
  import {
13
13
  resolveCompositionViewportFromHtml
14
14
  } from "./chunk-5Z63TBTX.js";
15
15
  import {
16
16
  resolveProject
17
- } from "./chunk-FTXU3TQ4.js";
17
+ } from "./chunk-US7SWKGC.js";
18
18
  import {
19
19
  c
20
20
  } from "./chunk-ZTZA4UWZ.js";
@@ -28,7 +28,7 @@ import {
28
28
  import {
29
29
  printDeprecationNotice,
30
30
  withMeta
31
- } from "./chunk-4NJZZHYT.js";
31
+ } from "./chunk-RPMXMOFU.js";
32
32
  import {
33
33
  normalizeErrorMessage
34
34
  } from "./chunk-KNU5COPB.js";
@@ -217,7 +217,7 @@ function extractCompositionErrorsFromLint(lintResult) {
217
217
  async function localizeRemoteAssets(html) {
218
218
  let dir;
219
219
  try {
220
- const { loadProducer } = await import("./producer-LGG3TOUI.js");
220
+ const { loadProducer } = await import("./producer-RS7CB3XJ.js");
221
221
  const { localizeRemoteMediaSources, localizeRemoteImageSources, localizeRemoteFontFaces } = await loadProducer();
222
222
  dir = mkdtempSync(join(tmpdir(), "hf-validate-assets-"));
223
223
  const assetDir = dir;
@@ -238,10 +238,10 @@ async function localizeRemoteAssets(html) {
238
238
  }
239
239
  async function validateInBrowser(project, opts) {
240
240
  const projectDir = project.dir;
241
- const { bundleToSingleHtml } = await import("./compiler-QMEZK6CU.js");
241
+ const { bundleToSingleHtml } = await import("./compiler-YYOV2BJ7.js");
242
242
  const { ensureBrowser } = await import("./manager-NEVLEZK3.js");
243
- const { serveStaticProjectHtml } = await import("./staticProjectServer-WBXW2CA4.js");
244
- const { lintProject } = await import("./lintProject-4P4C6AN2.js");
243
+ const { serveStaticProjectHtml } = await import("./staticProjectServer-RXAFGDK7.js");
244
+ const { lintProject } = await import("./lintProject-F2OTN2IR.js");
245
245
  const lintResult = await lintProject(projectDir);
246
246
  const compositionErrors = extractCompositionErrorsFromLint(lintResult);
247
247
  const html = await bundleToSingleHtml(projectDir);
@@ -262,13 +262,13 @@ async function validateInBrowser(project, opts) {
262
262
  try {
263
263
  const browser = await ensureBrowser();
264
264
  const puppeteer = await import("puppeteer-core");
265
- const { buildChromeArgs, analyzeClipMediaFit } = await import("./src-QX5PPANW.js");
265
+ const { buildChromeArgs, analyzeClipMediaFit } = await import("./src-6R4DC2YI.js");
266
266
  const requestedGpuMode = resolveCliChromeGpuMode();
267
267
  const {
268
268
  assertWebGpuAdapterAvailable,
269
269
  compositionRequiresWebGpu,
270
270
  resolveCaptureBrowserGpuMode
271
- } = await import("./gpuPolicy-BQFPO7UA.js");
271
+ } = await import("./gpuPolicy-KSWTVU5C.js");
272
272
  const resolvedGpuMode = await resolveCaptureBrowserGpuMode(
273
273
  requestedGpuMode,
274
274
  browser.executablePath
@@ -7,29 +7,29 @@ var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  RegistryCompatibilityError,
9
9
  gateRegistryItemsCompatibility
10
- } from "./chunk-JYRPUDVZ.js";
10
+ } from "./chunk-5N4KKGSZ.js";
11
11
  import {
12
12
  DEFAULT_PROJECT_CONFIG,
13
13
  createProjectConfig,
14
14
  loadProjectConfig,
15
15
  projectConfigPath,
16
16
  recordProjectRegistryItems
17
- } from "./chunk-HUHJYNST.js";
17
+ } from "./chunk-LAQEZHOH.js";
18
18
  import {
19
19
  resolveItemWithDependencies,
20
20
  resolveItemsByTag
21
- } from "./chunk-USWOTTSP.js";
21
+ } from "./chunk-XYVFPDNU.js";
22
22
  import {
23
23
  InvalidVariableValuesError,
24
24
  prepareItem,
25
25
  publishItem
26
- } from "./chunk-TYA65W4U.js";
26
+ } from "./chunk-HQGJLZB6.js";
27
27
  import {
28
28
  DEFAULT_REGISTRY_URL
29
- } from "./chunk-6CN2QLB5.js";
29
+ } from "./chunk-AWUZ3AUD.js";
30
30
  import {
31
31
  trackRegistryItemAdded
32
- } from "./chunk-2LCIQS3K.js";
32
+ } from "./chunk-VBXJSCHR.js";
33
33
  import {
34
34
  c
35
35
  } from "./chunk-ZTZA4UWZ.js";
@@ -41,7 +41,7 @@ import {
41
41
  } from "./chunk-PBN6GBJE.js";
42
42
  import {
43
43
  ITEM_TYPE_DIRS
44
- } from "./chunk-TEXPOC5V.js";
44
+ } from "./chunk-B25H4M4V.js";
45
45
  import {
46
46
  isProjectRootMissing,
47
47
  realpath
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-GMECXFAN.js";
13
13
  import {
14
14
  ITEM_TYPE_DIRS
15
- } from "./chunk-TEXPOC5V.js";
15
+ } from "./chunk-B25H4M4V.js";
16
16
  import {
17
17
  realProjectRoot
18
18
  } from "./chunk-OFQWTKPW.js";
@@ -11,13 +11,13 @@ import {
11
11
  isTextElement,
12
12
  keyframesToGsapAnimations,
13
13
  serializeGsapAnimations
14
- } from "./chunk-TLYU5625.js";
14
+ } from "./chunk-UUDQD62L.js";
15
15
  import {
16
16
  isMediaElement as isMediaElement2,
17
17
  parseStrictFiniteTimingNumber,
18
18
  resolveNaturalMediaTimelineDuration,
19
19
  resolveTimedImageDurationSeconds
20
- } from "./chunk-FOKUJKBN.js";
20
+ } from "./chunk-YLVI7VL5.js";
21
21
  import {
22
22
  COMPOSITION_ATTRIBUTES,
23
23
  parseStartExpression