hyperframes 0.8.159 → 0.8.160

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 (171) hide show
  1. package/README.md +10 -0
  2. package/dist/{add-7UMRT6IJ.js → add-OGBTJCU4.js} +11 -11
  3. package/dist/{animatedGifPrep-COFZMEVD.js → animatedGifPrep-YAJTDXB7.js} +6 -6
  4. package/dist/api.js +16 -16
  5. package/dist/{asset-N37XIJTB.js → asset-DKQFFGPP.js} +2 -2
  6. package/dist/{assetCataloger-ZOQ67MGR.js → assetCataloger-BIDQA34M.js} +2 -2
  7. package/dist/audio-GK4OVVTH.js +2086 -0
  8. package/dist/{auth-GKFS2PL6.js → auth-AQMRAFXN.js} +1 -1
  9. package/dist/{autoUpdate-V4PLREDQ.js → autoUpdate-NFQB7V2X.js} +2 -2
  10. package/dist/{backgroundChecks-TVOKARY2.js → backgroundChecks-7JKE2FIU.js} +3 -3
  11. package/dist/backgroundChecksWorker.js +3 -3
  12. package/dist/{batchRender-IARQXQHN.js → batchRender-C2JCG5EK.js} +3 -3
  13. package/dist/{beats-FY4UDXBL.js → beats-C3ZSK2R2.js} +12 -12
  14. package/dist/{benchmark-ZJYFRFYF.js → benchmark-RRU67WEY.js} +8 -8
  15. package/dist/{browser-WRZOH4PD.js → browser-K4TP4ZM2.js} +5 -5
  16. package/dist/{bundleWithLocalizedFonts-SFHKZZAX.js → bundleWithLocalizedFonts-SLBVWQ7O.js} +2 -2
  17. package/dist/{capture-LLLIHYEF.js → capture-T2TBROMS.js} +2 -2
  18. package/dist/{capture-KFYPMVTT.js → capture-ZPRK3TOZ.js} +10 -10
  19. package/dist/{catalog-QO762U7V.js → catalog-IMIHQ4KX.js} +11 -11
  20. package/dist/{catch-up-MELHNTGB.js → catch-up-UY5MJWOG.js} +4 -4
  21. package/dist/{check-RX3LTKYB.js → check-6NAJSJHQ.js} +129 -118
  22. package/dist/{checkBrowser-EUUMEILI.js → checkBrowser-JWNQFYTY.js} +32 -30
  23. package/dist/{chunk-YIJMVFEJ.js → chunk-22QHO26F.js} +1 -1
  24. package/dist/{chunk-7F3B5YYT.js → chunk-2742O5DO.js} +178 -23
  25. package/dist/{chunk-HEEN6X6O.js → chunk-2ZLYSXZC.js} +8 -8
  26. package/dist/{chunk-5HNZQSO4.js → chunk-37LNY2EC.js} +1 -1
  27. package/dist/{chunk-6TDZJ43G.js → chunk-3XPVZLAR.js} +1 -1
  28. package/dist/{chunk-5RSV6DWB.js → chunk-4ID635FL.js} +1 -1
  29. package/dist/{chunk-4IKI2RYR.js → chunk-4VYNMVMC.js} +10 -10
  30. package/dist/chunk-6JR2XUEE.js +127 -0
  31. package/dist/{chunk-4D5RBIX6.js → chunk-6MCASYIS.js} +7 -7
  32. package/dist/{chunk-7XEVZDKU.js → chunk-7OFNPEKR.js} +7 -7
  33. package/dist/{chunk-BB2SFTMY.js → chunk-A2DMF2Q6.js} +6 -5
  34. package/dist/{chunk-MMYY4KV3.js → chunk-B5FZ2CQM.js} +1 -1
  35. package/dist/{chunk-IWOEAWIP.js → chunk-B7RUGHBT.js} +1 -1
  36. package/dist/{chunk-IJ7JPX4W.js → chunk-D2WGLWIK.js} +3 -3
  37. package/dist/{chunk-7RTTPSXG.js → chunk-D33YJZOH.js} +1 -1
  38. package/dist/{chunk-54DMWFQZ.js → chunk-D3ZWBHZP.js} +2 -15
  39. package/dist/{chunk-K5BMHQOU.js → chunk-D46G5IQH.js} +11 -11
  40. package/dist/{chunk-WWMFR4SH.js → chunk-DJZEIVAP.js} +3 -3
  41. package/dist/{chunk-EGJVFPUX.js → chunk-ERTJPFCH.js} +1 -1
  42. package/dist/{chunk-FEKRMXT6.js → chunk-EVRUR7DW.js} +1 -1
  43. package/dist/{chunk-DLQQA25O.js → chunk-FRGYHRP6.js} +1 -1
  44. package/dist/{chunk-UK4KRTIX.js → chunk-G642IIVK.js} +2 -2
  45. package/dist/{chunk-AEQWF7PE.js → chunk-GG37I7B3.js} +1 -1
  46. package/dist/chunk-GJQHHAAX.js +336 -0
  47. package/dist/{chunk-BEW7RCCW.js → chunk-GOASXWDD.js} +2 -2
  48. package/dist/{chunk-IKDBT5WT.js → chunk-GOTCGKX6.js} +3 -3
  49. package/dist/{chunk-HO3SITVT.js → chunk-ICZVCVD3.js} +1 -1
  50. package/dist/{chunk-5GPX4X4L.js → chunk-IGTGLGML.js} +2 -2
  51. package/dist/{chunk-KEGTYA7V.js → chunk-IK3SOMZ4.js} +5 -3
  52. package/dist/{chunk-6PIGOKTE.js → chunk-JGYHWVXQ.js} +339 -67
  53. package/dist/{chunk-NCVGBBWC.js → chunk-KRE55WLI.js} +1 -1
  54. package/dist/{chunk-JZLFHF2M.js → chunk-KWRBEDJI.js} +3 -3
  55. package/dist/{chunk-INNBWSZK.js → chunk-LYIG2GZ5.js} +2 -2
  56. package/dist/{chunk-ESOAYGIT.js → chunk-MMV6IY6U.js} +2 -2
  57. package/dist/{chunk-4DEBDQD4.js → chunk-MP676E4B.js} +2 -2
  58. package/dist/{chunk-24N3BB5M.js → chunk-MYGXKD7A.js} +5 -5
  59. package/dist/{chunk-3W3MOLRL.js → chunk-N2NDDTYW.js} +2 -2
  60. package/dist/{chunk-GGDCBVXK.js → chunk-OMJA7JP6.js} +5 -5
  61. package/dist/chunk-P47XYVEQ.js +3795 -0
  62. package/dist/{chunk-NIGOOCVS.js → chunk-P4QE7SSN.js} +1 -1
  63. package/dist/{chunk-AQXJC64X.js → chunk-PBNV5V5G.js} +1 -1
  64. package/dist/{chunk-A5RDOXZE.js → chunk-PINFPWRV.js} +5 -119
  65. package/dist/{chunk-2CEH75X3.js → chunk-PLEMSN3E.js} +2 -2
  66. package/dist/{chunk-DVAEX52Q.js → chunk-PPF65XAF.js} +1 -1
  67. package/dist/{chunk-V5J4XEBG.js → chunk-Q3TFX4OZ.js} +1 -1
  68. package/dist/{chunk-XSEGMQYA.js → chunk-QABAVWEX.js} +26 -3
  69. package/dist/{chunk-76NO4ZRM.js → chunk-RTS7BGEC.js} +1 -1
  70. package/dist/{chunk-H6BKVVU4.js → chunk-SB5DX6AD.js} +2 -2
  71. package/dist/{chunk-5YCFHCD4.js → chunk-SHVDJON6.js} +2 -2
  72. package/dist/{chunk-EWAAH7AU.js → chunk-TTFDAWCS.js} +1 -1
  73. package/dist/{chunk-MTUC2Z32.js → chunk-TU2CQJO3.js} +2 -2
  74. package/dist/{chunk-AFYZWHR7.js → chunk-V2FQQILJ.js} +2 -2
  75. package/dist/{chunk-ODE7HHNN.js → chunk-VD7WQYTO.js} +11 -9
  76. package/dist/{chunk-YITZFHRJ.js → chunk-VZ6LCTOZ.js} +1 -1
  77. package/dist/{chunk-SQHWDFTV.js → chunk-X3SCQP2A.js} +1 -1
  78. package/dist/{chunk-LBT4AMSF.js → chunk-XRKMITSS.js} +1 -1
  79. package/dist/{chunk-5O6I5ZV7.js → chunk-XTLV6UVP.js} +3 -3
  80. package/dist/{clean-RW7Z4XM6.js → clean-RRE6PMKZ.js} +18 -17
  81. package/dist/cli.js +54 -53
  82. package/dist/{cloud-EEOV7JKB.js → cloud-OIR6K7TS.js} +4 -4
  83. package/dist/{cloudrun-EZAXYVXG.js → cloudrun-BIQXBUDO.js} +3 -3
  84. package/dist/{compare-5UARQFXX.js → compare-E57W737I.js} +25 -24
  85. package/dist/{compiler-THI7BXZU.js → compiler-57M6W5WY.js} +3 -3
  86. package/dist/{component-AYOFPL33.js → component-I2O4AX56.js} +3 -3
  87. package/dist/{compositions-XJNJBOMG.js → compositions-B6NKZHIN.js} +10 -10
  88. package/dist/{delete-653AOR25.js → delete-DTUNBC6K.js} +2 -2
  89. package/dist/{dist-DLR4X3KN.js → dist-4JFB3WAR.js} +2 -2
  90. package/dist/{dist-2VXSQLXO.js → dist-ROVMAL74.js} +1 -1
  91. package/dist/{doctor-WA6VRRE7.js → doctor-SCNB73Z3.js} +12 -12
  92. package/dist/{events-XXBCP2I4.js → events-6LQNRKHZ.js} +3 -3
  93. package/dist/{events-U5COLUWT.js → events-Q37UJL36.js} +2 -2
  94. package/dist/{feedback-DX6Q3LN7.js → feedback-FOEBE2OW.js} +7 -7
  95. package/dist/{ffmpeg-2ROTISBL.js → ffmpeg-7BYARPLM.js} +4 -2
  96. package/dist/{figma-LCQVLBXF.js → figma-54MRTBKH.js} +3 -3
  97. package/dist/fontLocalizeCli.js +8 -8
  98. package/dist/{get-UYNPFMHX.js → get-EPGHM2SA.js} +2 -2
  99. package/dist/{gpuPolicy-YIW3HL3B.js → gpuPolicy-VGE3I5J4.js} +6 -6
  100. package/dist/{grade-compare-YQEYATJV.js → grade-compare-LOJWX6SK.js} +27 -26
  101. package/dist/{help-FDURC7WR.js → help-6FPZI3WP.js} +2 -1
  102. package/dist/{history-EU5UZLHT.js → history-GRXSUA5R.js} +8 -7
  103. package/dist/hyperframe-runtime.js +55 -55
  104. package/dist/hyperframe.manifest.json +1 -1
  105. package/dist/hyperframe.runtime.iife.js +55 -55
  106. package/dist/hyperframes-player.global.js +3 -3
  107. package/dist/{info-7T6CK6CL.js → info-LV7DFCLD.js} +7 -7
  108. package/dist/{init-KQYSKFVU.js → init-3J7BSAC3.js} +28 -28
  109. package/dist/{inspect-HQBV7VHS.js → inspect-5RON554C.js} +26 -25
  110. package/dist/{installer-OKKPQNKS.js → installer-T3STEB4U.js} +4 -4
  111. package/dist/{keyframes-SK74JHOA.js → keyframes-KHXTHI5C.js} +6 -6
  112. package/dist/{lambda-S2N4VTRO.js → lambda-4KCSMIM6.js} +4 -4
  113. package/dist/{layout-MTE5Y6DE.js → layout-DVWWT2TR.js} +26 -25
  114. package/dist/{lint-FJGGJYB7.js → lint-Q5WFB5ST.js} +7 -7
  115. package/dist/{lintProject-JGHKRO5L.js → lintProject-BGDYHF3F.js} +1 -1
  116. package/dist/{list-MBPALK5U.js → list-RFEUTW6N.js} +2 -2
  117. package/dist/{login-HDN4T5E4.js → login-WBHWA4M2.js} +4 -4
  118. package/dist/{manager-JNJE54OQ.js → manager-B6MVBM2E.js} +3 -3
  119. package/dist/{manager-ZLJD3EAY.js → manager-HEUPD2YB.js} +2 -2
  120. package/dist/{media-treatment-IP34DXWN.js → media-treatment-WRHVNWLS.js} +12 -11
  121. package/dist/{models-W5TASRHD.js → models-OA4MXEYG.js} +12 -12
  122. package/dist/{motionShot-2WYEMOPJ.js → motionShot-BZLRN3SS.js} +13 -13
  123. package/dist/{normalize-audio-F4NQPXII.js → normalize-audio-4YXE3RIF.js} +4 -4
  124. package/dist/{open-DRXNALDE.js → open-MCGYEFML.js} +4 -4
  125. package/dist/{parakeetRunner-VISBF2EA.js → parakeetRunner-DBLHMD5T.js} +13 -13
  126. package/dist/{pipeline-A2XOVZOM.js → pipeline-FSY65OQ4.js} +8 -8
  127. package/dist/{play-W2QELQX7.js → play-WXOV3BD7.js} +19 -18
  128. package/dist/{preflight-BH2XUQBS.js → preflight-G5KP7ZKA.js} +4 -4
  129. package/dist/{present-NHYRS4F4.js → present-RVG4J6CJ.js} +15 -14
  130. package/dist/{preview-SMJVUPXE.js → preview-PDUQR2JQ.js} +18 -18
  131. package/dist/{producer-276O3CKW.js → producer-C5V2A3YL.js} +1 -1
  132. package/dist/{projectConfig-FXFUHFPZ.js → projectConfig-X2IEHCSK.js} +6 -6
  133. package/dist/{publication-SSQO6ECV.js → publication-JEANCWBW.js} +2 -2
  134. package/dist/{publish-UHDKDXZI.js → publish-VX5OH4ST.js} +9 -9
  135. package/dist/{remove-background-IG6U56HC.js → remove-background-IXCISD26.js} +9 -9
  136. package/dist/{render-ZJPSLTKV.js → render-5BGU3FXU.js} +29 -28
  137. package/dist/{render-XQONIJEJ.js → render-ISUT7Q3X.js} +3 -3
  138. package/dist/{render-6P5RSFS3.js → render-JNJVFBFF.js} +9 -9
  139. package/dist/{render-batch-MH3Z6IPT.js → render-batch-2C6RUP3F.js} +3 -3
  140. package/dist/renderSetupWorker.js +4 -4
  141. package/dist/{resolver-JMSGO2JF.js → resolver-KTNKZVIB.js} +4 -4
  142. package/dist/{sherpa-64JLV4YM.js → sherpa-GFRG3TMM.js} +12 -12
  143. package/dist/skills/hyperframes-cli/SKILL.md +5 -4
  144. package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +8 -0
  145. package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +1 -1
  146. package/dist/{skills-UXOL62PY.js → skills-LKJA27ZN.js} +5 -5
  147. package/dist/{skillsUpdateCheck-5Y6676K6.js → skillsUpdateCheck-RFZJKZC4.js} +3 -3
  148. package/dist/{snapshot-SQBPCXOV.js → snapshot-EOYA4MLG.js} +40 -30
  149. package/dist/{src-N42CT3YR.js → src-GPUDUKY6.js} +5 -5
  150. package/dist/{src-RQMK5INS.js → src-IMCQRH4P.js} +7 -7
  151. package/dist/{staticProjectServer-AQXVWMLU.js → staticProjectServer-S3NK3V4S.js} +15 -14
  152. package/dist/studio/assets/{hyperframes-player-kqB1psAJ.js → hyperframes-player-CXL23NEv.js} +1 -1
  153. package/dist/studio/assets/{index-C3AZLr-0.js → index-Bl_xrA5T.js} +1 -1
  154. package/dist/studio/assets/{index-BrViH8hj.js → index-CejKvBNw.js} +1 -1
  155. package/dist/studio/assets/{index-X_d1b5vz.js → index-D7BvLHtZ.js} +7 -7
  156. package/dist/studio/index.html +1 -1
  157. package/dist/{studio-api-GY5D7RAP.js → studio-api-YM5HLXUS.js} +13 -8
  158. package/dist/{studioServer-O3VONODG.js → studioServer-CEXJK5TC.js} +45 -44
  159. package/dist/{telemetry-V2K5P7CI.js → telemetry-7AWYECPL.js} +3 -3
  160. package/dist/{timeline-YU3YPLKB.js → timeline-G7H373XX.js} +42 -347
  161. package/dist/{tokens-NPSSSG2A.js → tokens-GYH7NXXA.js} +2 -2
  162. package/dist/{transcribe-FNBDG24U.js → transcribe-CIC7WAT5.js} +17 -17
  163. package/dist/{transcribe-BXJNS3RZ.js → transcribe-FL6NGWHF.js} +11 -11
  164. package/dist/{updateCheck-MB3RHSVK.js → updateCheck-MQ44KGUR.js} +2 -2
  165. package/dist/{upgrade-5VNRUR37.js → upgrade-OL47SID3.js} +2 -2
  166. package/dist/{urlDownloader-WCT7FMLA.js → urlDownloader-KDJGLR2Y.js} +5 -5
  167. package/dist/{usage-EC3KFUIJ.js → usage-HG4WMM7A.js} +33 -5
  168. package/dist/{validate-UXSXRCE6.js → validate-TDCH6X3C.js} +20 -19
  169. package/dist/{video-NRNQBZMV.js → video-AHO4CDCK.js} +6 -6
  170. package/package.json +1 -1
  171. package/dist/chunk-TWBTXEDZ.js +0 -3795
@@ -48,6 +48,7 @@ import {
48
48
  } from "./chunk-SDYDNHEE.js";
49
49
  import {
50
50
  parse,
51
+ parseExpressionAt,
51
52
  simple
52
53
  } from "./chunk-TYXH3EKP.js";
53
54
  import {
@@ -3763,10 +3764,12 @@ function trackKindOf(node) {
3763
3764
  // ../lint/dist/index.js
3764
3765
  import { createHash } from "crypto";
3765
3766
  import { existsSync as existsSync2, readFileSync, readdirSync } from "fs";
3766
- import { dirname, extname, join as join2, relative, resolve } from "path";
3767
+ import { dirname as dirname2, extname, join as join3, relative as relative2, resolve } from "path";
3767
3768
  import { execFile } from "child_process";
3768
3769
  import { existsSync } from "fs";
3769
3770
  import { join } from "path";
3771
+ import { realpathSync } from "fs";
3772
+ import { dirname, join as join2, relative } from "path";
3770
3773
  var COMPOSITION_ID_IN_CSS_PATTERN = /\[data-composition-id=["']([^"']+)["']\]/g;
3771
3774
  var TIMELINE_REGISTRY_INIT_PATTERN = /window\.__timelines\s*=\s*window\.__timelines\s*\|\|\s*\{\}|window\.__timelines\s*=\s*\{\}|window\.__timelines\s*\?\?=\s*\{\}/i;
3772
3775
  var TIMELINE_REGISTRY_OBJECT_LITERAL_PATTERN = /window\.__timelines\s*=\s*\{\s*(?:["'][^"']+["']|[A-Za-z_$][\w$]*)\s*:/i;
@@ -5249,10 +5252,10 @@ var coreRules = [
5249
5252
  }
5250
5253
  ];
5251
5254
  for (const script of scripts) {
5252
- const withoutComments = stripJsComments(script.content);
5253
- const executable = stripStringLiterals(withoutComments);
5255
+ const withoutComments2 = stripJsComments(script.content);
5256
+ const executable = stripStringLiterals(withoutComments2);
5254
5257
  for (const { pattern, label, hint, scansStrings } of patterns) {
5255
- const match = pattern.exec(scansStrings ? withoutComments : executable);
5258
+ const match = pattern.exec(scansStrings ? withoutComments2 : executable);
5256
5259
  if (match) {
5257
5260
  findings.push({
5258
5261
  ...locate(script, match.index),
@@ -7608,8 +7611,8 @@ function collectStaticCssVariableDefinitions(tags, styles) {
7608
7611
  ];
7609
7612
  const definitionPattern = /(?:^|[;{])\s*(--[A-Za-z0-9_-]+)\s*:/gm;
7610
7613
  for (const source of sources) {
7611
- const withoutComments = source.replace(/\/\*[\s\S]*?\*\//g, " ");
7612
- for (const match of withoutComments.matchAll(definitionPattern)) {
7614
+ const withoutComments2 = source.replace(/\/\*[\s\S]*?\*\//g, " ");
7615
+ for (const match of withoutComments2.matchAll(definitionPattern)) {
7613
7616
  if (match[1]) definitions.add(match[1]);
7614
7617
  }
7615
7618
  }
@@ -7803,8 +7806,8 @@ function targetedSelectorTokens(selector) {
7803
7806
  const compounds = group.trim().split(/[\s>+~]+/).filter(Boolean);
7804
7807
  const last = compounds[compounds.length - 1];
7805
7808
  if (!last) continue;
7806
- const simple2 = last.match(/[#.][A-Za-z0-9_-]+/g);
7807
- if (simple2) for (const token of simple2) tokens.add(token);
7809
+ const simple3 = last.match(/[#.][A-Za-z0-9_-]+/g);
7810
+ if (simple3) for (const token of simple3) tokens.add(token);
7808
7811
  }
7809
7812
  return tokens;
7810
7813
  }
@@ -8006,8 +8009,8 @@ function firstParamMemberAccessHazard(fn) {
8006
8009
  while ((match = pattern.exec(fn.body)) !== null) {
8007
8010
  const member = match[1] ?? "";
8008
8011
  const after = fn.body.slice(match.index + match[0].length);
8009
- const isCall = /^\s*\(/.test(after);
8010
- if (isCall && NUMBER_METHODS.has(member)) continue;
8012
+ const isCall2 = /^\s*\(/.test(after);
8013
+ if (isCall2 && NUMBER_METHODS.has(member)) continue;
8011
8014
  return member;
8012
8015
  }
8013
8016
  return null;
@@ -10068,6 +10071,110 @@ var structureRules = [
10068
10071
  ];
10069
10072
  }
10070
10073
  ];
10074
+ function withoutComments(source) {
10075
+ return source.replace(/\/\*[\s\S]*?\*\/|\/\/[^\r\n]*/g, (text) => text.replace(/[^\r\n]/g, " "));
10076
+ }
10077
+ function staticShaders(source) {
10078
+ const shaders = [];
10079
+ try {
10080
+ const ast = parse(source, {
10081
+ ecmaVersion: "latest",
10082
+ sourceType: "module",
10083
+ allowReturnOutsideFunction: true
10084
+ });
10085
+ simple(ast, {
10086
+ Literal(node) {
10087
+ if (typeof node.value !== "string") return;
10088
+ shaders.push({
10089
+ text: node.value,
10090
+ start: node.start + 1,
10091
+ exactOffsets: source.slice(node.start + 1, node.end - 1) === node.value
10092
+ });
10093
+ },
10094
+ TemplateLiteral(node) {
10095
+ if (node.expressions.length !== 0) return;
10096
+ const value = node.quasis[0]?.value;
10097
+ if (value?.cooked == null) return;
10098
+ shaders.push({
10099
+ text: value.cooked,
10100
+ start: node.start + 1,
10101
+ exactOffsets: source.slice(node.start + 1, node.end - 1) === value.cooked
10102
+ });
10103
+ }
10104
+ });
10105
+ } catch {
10106
+ }
10107
+ return shaders.filter(({ text }) => /\bvoid\s+main\s*\(/.test(withoutComments(text)));
10108
+ }
10109
+ function isNumber(node, value) {
10110
+ return node?.type === "Literal" && node.value === value;
10111
+ }
10112
+ function isCall(node, name) {
10113
+ return node?.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === name;
10114
+ }
10115
+ function unboundedCosine(node) {
10116
+ if (node.type !== "CallExpression") return false;
10117
+ if (isCall(node, "dot")) return node.arguments.length === 2;
10118
+ if (!isCall(node, "max") || node.arguments.length !== 2) return false;
10119
+ const a = argumentAt(node, 0);
10120
+ const b = argumentAt(node, 1);
10121
+ return zeroFlooredDot(a, b) || zeroFlooredDot(b, a);
10122
+ }
10123
+ function argumentAt(call, index) {
10124
+ const node = call.arguments[index];
10125
+ return node?.type === "SpreadElement" ? void 0 : node;
10126
+ }
10127
+ function zeroFlooredDot(a, b) {
10128
+ return isCall(a, "dot") && isNumber(b, 0);
10129
+ }
10130
+ function unsafeCosinePower(call) {
10131
+ if (call.arguments.length !== 2) return false;
10132
+ const [base] = call.arguments;
10133
+ return base?.type === "BinaryExpression" && base.operator === "-" && base.left.type !== "PrivateIdentifier" && isNumber(base.left, 1) && unboundedCosine(base.right);
10134
+ }
10135
+ function unsafePowOffsets(source) {
10136
+ const offsets = [];
10137
+ const masked = withoutComments(source);
10138
+ for (const match of masked.matchAll(/\bpow\s*\(/g)) {
10139
+ try {
10140
+ const expression = parseExpressionAt(masked, match.index, { ecmaVersion: "latest" });
10141
+ simple(expression, {
10142
+ CallExpression(node) {
10143
+ if (node.start === match.index && unsafeCosinePower(node)) offsets.push(node.start);
10144
+ }
10145
+ });
10146
+ } catch {
10147
+ }
10148
+ }
10149
+ return offsets;
10150
+ }
10151
+ function shaderDomainOffsets(source, glsl = false) {
10152
+ const shaders = glsl ? [{ text: source, start: 0, exactOffsets: true }] : staticShaders(source);
10153
+ return shaders.flatMap(
10154
+ ({ text, start, exactOffsets }) => unsafePowOffsets(text).map((offset) => exactOffsets ? start + offset : void 0)
10155
+ );
10156
+ }
10157
+ function shaderDomainWarning() {
10158
+ return {
10159
+ code: "shader_unbounded_cosine_pow",
10160
+ severity: "warning",
10161
+ message: "Shader pow(1 - dot(...), ...) can receive a negative base when the cosine exceeds 1, including through GPU rounding. Undefined GLSL results can spread through glow or transmission textures as black artifacts.",
10162
+ fixHint: "Bound the cosine on both sides: pow(1.0 - clamp(dot(normal, view), 0.0, 1.0), exponent). A lower-only max(dot(...), 0.0) does not bound the upper end. Inspect the affected frames on the target GPU."
10163
+ };
10164
+ }
10165
+ var shaderRules = [
10166
+ ({ scripts, locate }) => scripts.flatMap((script) => {
10167
+ const tag = `<script ${script.attrs}>`;
10168
+ if (readAttr(tag, "src") !== null) return [];
10169
+ const type = readAttr(tag, "type") ?? "";
10170
+ const glsl = /^(?:x-shader\/x-(?:fragment|vertex)|text\/glsl)$/i.test(type);
10171
+ if (type && !glsl && !/^(?:module|(?:text|application)\/javascript)$/i.test(type)) return [];
10172
+ return shaderDomainOffsets(script.content, glsl).map((offset) => ({
10173
+ ...shaderDomainWarning(),
10174
+ ...locate(script, offset)
10175
+ }));
10176
+ })
10177
+ ];
10071
10178
  var RULE_GROUPS = [
10072
10179
  { group: "core", rules: coreRules },
10073
10180
  { group: "media", rules: mediaRules },
@@ -10078,7 +10185,8 @@ var RULE_GROUPS = [
10078
10185
  { group: "textures", rules: textureRules },
10079
10186
  { group: "fonts", rules: fontRules },
10080
10187
  { group: "slideshow", rules: slideshowRules },
10081
- { group: "structure", rules: structureRules }
10188
+ { group: "structure", rules: structureRules },
10189
+ { group: "shaders", rules: shaderRules }
10082
10190
  ];
10083
10191
  var LINT_RULE_COUNT = RULE_GROUPS.reduce((n, g) => n + g.rules.length, 0);
10084
10192
  var LINT_RULE_GROUP_COUNTS = Object.fromEntries(
@@ -10090,7 +10198,8 @@ function dedupeKeyFor(finding) {
10090
10198
  finding.severity,
10091
10199
  finding.selector || "",
10092
10200
  finding.elementId || "",
10093
- finding.message
10201
+ finding.message,
10202
+ ...finding.code === "shader_unbounded_cosine_pow" ? [finding.line, finding.column] : []
10094
10203
  ].join("|");
10095
10204
  }
10096
10205
  async function runRules(ctx, filePath) {
@@ -10128,7 +10237,7 @@ async function lintHyperframeHtml(html, options = {}) {
10128
10237
  const { findings: rawFindings, timings } = await runRules(ctx, options.filePath);
10129
10238
  const locate = createSourceLocator(html);
10130
10239
  const findings = rawFindings.map((finding) => {
10131
- if (finding.line !== void 0 || finding.code === "invalid_inline_script_syntax" || finding.code === "non_deterministic_code" || [
10240
+ if (finding.line !== void 0 || finding.code === "shader_unbounded_cosine_pow" || finding.code === "invalid_inline_script_syntax" || finding.code === "non_deterministic_code" || [
10132
10241
  "gsap_infinite_repeat",
10133
10242
  "gsap_repeat_ceil_overshoot",
10134
10243
  "gsap_repeat_floor_unclamped"
@@ -10438,6 +10547,51 @@ async function lintHevcPreviewCodec(candidates) {
10438
10547
  }
10439
10548
  ];
10440
10549
  }
10550
+ function isAuthoredScript(path) {
10551
+ return /\.(?:js|mjs|cjs)$/i.test(path) && !/(?:\.min\.js$|(?:^|[/\\])(?:vendor|node_modules)[/\\])/i.test(path);
10552
+ }
10553
+ function localScript(projectDir, src, compSrcPath) {
10554
+ if (/^(?:[a-z][a-z\d+.-]*:|\/\/|#)/i.test(src)) return;
10555
+ const besideFile = src.startsWith("/") ? src : join2(dirname(compSrcPath ?? "index.html"), src);
10556
+ const asset = resolveExistingLocalAsset(projectDir, besideFile);
10557
+ if (!asset) return;
10558
+ try {
10559
+ const file = realpathSync(asset.resolved);
10560
+ if (!isWithinProjectRoot(realpathSync(projectDir), file)) return;
10561
+ if (!isAuthoredScript(relative(projectDir, file))) return;
10562
+ return file;
10563
+ } catch {
10564
+ return;
10565
+ }
10566
+ }
10567
+ function linkedScripts(projectDir, { html, compSrcPath }) {
10568
+ const files = [];
10569
+ for (const script of parseHtmlStructure(html).scripts) {
10570
+ const tag = `<script ${script.attrs}>`;
10571
+ const type = readDecodedAttr(tag, "type") ?? "";
10572
+ if (type && !/^(?:module|(?:text|application)\/javascript)$/i.test(type)) continue;
10573
+ const src = readDecodedAttr(tag, "src");
10574
+ if (!src) continue;
10575
+ const file = localScript(projectDir, src, compSrcPath);
10576
+ if (file) files.push(file);
10577
+ }
10578
+ return files;
10579
+ }
10580
+ function lintProjectShaderScripts(projectDir, sources) {
10581
+ const files = new Set(sources.flatMap((source) => linkedScripts(projectDir, source)));
10582
+ const findings = [];
10583
+ for (const file of files) {
10584
+ const read = readProjectFile(file);
10585
+ if (read.kind !== "file") continue;
10586
+ for (const offset of shaderDomainOffsets(read.text)) {
10587
+ findings.push({
10588
+ ...shaderDomainWarning(),
10589
+ ...offset === void 0 ? { file } : sourcePosition(read.text, offset, file)
10590
+ });
10591
+ }
10592
+ }
10593
+ return findings;
10594
+ }
10441
10595
  function parseSubCompHtml(html) {
10442
10596
  return parseHTML(html).document;
10443
10597
  }
@@ -10468,7 +10622,7 @@ function collectLocalStylesheets(projectDir, document, compSrcPath) {
10468
10622
  if (!rel.split(/\s+/).some((part) => part.toLowerCase() === "stylesheet")) continue;
10469
10623
  const href = link.getAttribute("href") ?? "";
10470
10624
  if (!isLocalStylesheetHref(href)) continue;
10471
- const besideFile = compSrcPath ? join2(dirname(compSrcPath), href) : href;
10625
+ const besideFile = compSrcPath ? join3(dirname2(compSrcPath), href) : href;
10472
10626
  const stylesheet = resolveExistingLocalAsset(projectDir, besideFile) ?? (compSrcPath && staysInsideProjectRoot(href) ? resolveExistingLocalAsset(projectDir, href) : null);
10473
10627
  if (!stylesheet) continue;
10474
10628
  const read = readProjectFile(stylesheet.resolved);
@@ -10485,7 +10639,7 @@ function collectExternalStyles(projectDir, html, compSrcPath) {
10485
10639
  document,
10486
10640
  compSrcPath
10487
10641
  )) {
10488
- styles.push({ href, content, file: join2(projectDir, rootRelativePath), rootRelativePath });
10642
+ styles.push({ href, content, file: join3(projectDir, rootRelativePath), rootRelativePath });
10489
10643
  }
10490
10644
  return styles;
10491
10645
  }
@@ -10512,12 +10666,12 @@ function collectCssSources(projectDir, html, compSrcPath) {
10512
10666
  function resolveCssAssetCandidates(projectDir, url, htmlCompSrcPath, cssRootRelativePath) {
10513
10667
  if (url.startsWith("/")) return resolveLocalAssetCandidates(projectDir, url);
10514
10668
  if (cssRootRelativePath) {
10515
- return resolveLocalAssetCandidates(projectDir, join2(dirname(cssRootRelativePath), url));
10669
+ return resolveLocalAssetCandidates(projectDir, join3(dirname2(cssRootRelativePath), url));
10516
10670
  }
10517
10671
  if (htmlCompSrcPath) {
10518
10672
  return resolveLocalAssetCandidates(
10519
10673
  projectDir,
10520
- rewriteAssetPath(htmlCompSrcPath, url, (path) => existsSync2(join2(projectDir, path)))
10674
+ rewriteAssetPath(htmlCompSrcPath, url, (path) => existsSync2(join3(projectDir, path)))
10521
10675
  );
10522
10676
  }
10523
10677
  return resolveLocalAssetCandidates(projectDir, url);
@@ -10527,7 +10681,7 @@ async function lintProject(projectDir, entryFile, hostOptions = {}) {
10527
10681
  if (entryFile && !isWithinProjectRoot(projectDir, indexPath)) {
10528
10682
  throw new Error(`Explicit lint entry is outside the project directory: ${entryFile}`);
10529
10683
  }
10530
- const rootFile = relative(resolve(projectDir), indexPath).replace(/\\/g, "/") || "index.html";
10684
+ const rootFile = relative2(resolve(projectDir), indexPath).replace(/\\/g, "/") || "index.html";
10531
10685
  const rootCompSrcPath = rootFile === "index.html" ? void 0 : rootFile;
10532
10686
  const results = [];
10533
10687
  let totalErrors = 0;
@@ -10553,7 +10707,7 @@ async function lintProject(projectDir, entryFile, hostOptions = {}) {
10553
10707
  const relPath = rel ? `${rel}/${entry.name}` : entry.name;
10554
10708
  if (entry.isDirectory()) {
10555
10709
  if (!rel && entry.name === "components") continue;
10556
- out.push(...collectHtmlFiles(join2(dir, entry.name), relPath));
10710
+ out.push(...collectHtmlFiles(join3(dir, entry.name), relPath));
10557
10711
  } else if (entry.isFile() && entry.name.endsWith(".html") && !entry.name.startsWith("._")) {
10558
10712
  out.push(relPath);
10559
10713
  }
@@ -10562,7 +10716,7 @@ async function lintProject(projectDir, entryFile, hostOptions = {}) {
10562
10716
  };
10563
10717
  const files = collectHtmlFiles(compositionsDir, "").sort();
10564
10718
  for (const file of files) {
10565
- const filePath = join2(compositionsDir, file);
10719
+ const filePath = join3(compositionsDir, file);
10566
10720
  const html = readFileSync(filePath, "utf-8");
10567
10721
  const compSrcPath = `compositions/${file}`;
10568
10722
  allHtmlSources.push({ html, compSrcPath });
@@ -10585,6 +10739,7 @@ async function lintProject(projectDir, entryFile, hostOptions = {}) {
10585
10739
  }
10586
10740
  }
10587
10741
  const projectFindings = [
10742
+ ...lintProjectShaderScripts(projectDir, allHtmlSources),
10588
10743
  ...lintProjectAudioFiles(projectDir, allHtmlSources),
10589
10744
  ...lintAudioSrcNotFound(projectDir, allHtmlSources),
10590
10745
  ...lintMissingLocalAsset(projectDir, allHtmlSources),
@@ -10680,7 +10835,7 @@ function lintAudioSrcNotFound(projectDir, htmlSources) {
10680
10835
  const src = mediaSrcOf(match);
10681
10836
  if (/^(https?:|data:|blob:)/i.test(src)) continue;
10682
10837
  if (isUnresolvedAssetPlaceholder(src)) continue;
10683
- const rootRelative = compSrcPath ? rewriteAssetPath(compSrcPath, src, (path) => existsSync2(join2(projectDir, path))) : src;
10838
+ const rootRelative = compSrcPath ? rewriteAssetPath(compSrcPath, src, (path) => existsSync2(join3(projectDir, path))) : src;
10684
10839
  if (!existsSync2(resolveProjectRelativeSrc(rootRelative, projectDir))) {
10685
10840
  const file = sourceFile(projectDir, compSrcPath);
10686
10841
  missingByFile.set(file, (missingByFile.get(file) ?? /* @__PURE__ */ new Set()).add(src));
@@ -10714,7 +10869,7 @@ function lintMissingLocalAsset(projectDir, htmlSources) {
10714
10869
  const src = cleanAssetUrl(rawSrc);
10715
10870
  if (!src) continue;
10716
10871
  if (isRemoteOrInlineUrl(src)) continue;
10717
- const rootRelative = compSrcPath ? rewriteAssetPath(compSrcPath, src, (path) => existsSync2(join2(projectDir, path))) : src;
10872
+ const rootRelative = compSrcPath ? rewriteAssetPath(compSrcPath, src, (path) => existsSync2(join3(projectDir, path))) : src;
10718
10873
  const resolvedAsset = resolveExistingLocalAsset(projectDir, rootRelative);
10719
10874
  if (resolvedAsset) continue;
10720
10875
  const resolvedKey = resolve(projectDir, rootRelative);
@@ -10783,7 +10938,7 @@ function lintMultipleRootCompositions(projectDir) {
10783
10938
  const rootCompositions = [];
10784
10939
  for (const file of rootHtmlFiles) {
10785
10940
  if (file === "caption-skin.html") continue;
10786
- const content = readFileSync(join2(projectDir, file), "utf-8");
10941
+ const content = readFileSync(join3(projectDir, file), "utf-8");
10787
10942
  if (/data-composition-id/i.test(content)) {
10788
10943
  rootCompositions.push(file);
10789
10944
  }
@@ -16,7 +16,7 @@ import {
16
16
  EncoderInterruptedError,
17
17
  encoderFailureError,
18
18
  prepareAnimatedGifInputs
19
- } from "./chunk-ESOAYGIT.js";
19
+ } from "./chunk-MMV6IY6U.js";
20
20
  import {
21
21
  parseEncoderOptions
22
22
  } from "./chunk-KLIKCX6Q.js";
@@ -151,7 +151,7 @@ import {
151
151
  validateEngineConfigSnapshot,
152
152
  verifyDiskDrawElementSamples,
153
153
  writeCapturedFrame
154
- } from "./chunk-2CEH75X3.js";
154
+ } from "./chunk-PLEMSN3E.js";
155
155
  import {
156
156
  assignBundledRuntimeCompositionIds,
157
157
  buildVariablesByCompScript,
@@ -164,7 +164,7 @@ import {
164
164
  isTemplateEntry,
165
165
  parsesAsScript,
166
166
  prepareFlattenedInnerRoot
167
- } from "./chunk-INNBWSZK.js";
167
+ } from "./chunk-LYIG2GZ5.js";
168
168
  import {
169
169
  LOW_MEMORY_TOTAL_MB_THRESHOLD,
170
170
  getCgroupMemoryLimitMb,
@@ -188,7 +188,7 @@ import {
188
188
  resolveAbsoluteMediaStartSeconds,
189
189
  resolveAuthoredTimingWindow,
190
190
  toFps
191
- } from "./chunk-V5J4XEBG.js";
191
+ } from "./chunk-Q3TFX4OZ.js";
192
192
  import {
193
193
  COMPOSITION_SOURCE_URL,
194
194
  HF_COLOR_GRADING_ATTR,
@@ -216,7 +216,7 @@ import {
216
216
  shouldClampResolvedMediaDuration,
217
217
  sourceTimeAt,
218
218
  styleElementsFor
219
- } from "./chunk-TWBTXEDZ.js";
219
+ } from "./chunk-P47XYVEQ.js";
220
220
  import {
221
221
  MAX_AUDIO_GAIN
222
222
  } from "./chunk-UJKQWGFF.js";
@@ -240,7 +240,7 @@ import {
240
240
  } from "./chunk-TWWSYAKJ.js";
241
241
  import {
242
242
  lintHyperframeHtml
243
- } from "./chunk-7F3B5YYT.js";
243
+ } from "./chunk-2742O5DO.js";
244
244
  import {
245
245
  isUnresolvedAssetPlaceholder,
246
246
  readProjectFile,
@@ -14422,7 +14422,7 @@ function startServer(options = {}) {
14422
14422
  });
14423
14423
  async function shutdown(signal) {
14424
14424
  log.info(`Received ${signal}, shutting down`);
14425
- const { drainBrowserPool } = await import("./src-N42CT3YR.js");
14425
+ const { drainBrowserPool } = await import("./src-GPUDUKY6.js");
14426
14426
  await drainBrowserPool().catch(() => {
14427
14427
  });
14428
14428
  const handle = await Promise.race([
@@ -15609,7 +15609,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
15609
15609
  if (probeResult.fileServer) closeFileServerSafely(probeResult.fileServer, "plan", log);
15610
15610
  if (probeResult.probeSession) {
15611
15611
  try {
15612
- const { closeCaptureSession: closeCaptureSession2 } = await import("./src-N42CT3YR.js");
15612
+ const { closeCaptureSession: closeCaptureSession2 } = await import("./src-GPUDUKY6.js");
15613
15613
  await closeCaptureSession2(probeResult.probeSession);
15614
15614
  } catch (err) {
15615
15615
  log.warn("[plan] probe session close failed", {
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-K2FLNJVB.js";
10
10
  import {
11
11
  trackCommandFailure
12
- } from "./chunk-NCVGBBWC.js";
12
+ } from "./chunk-KRE55WLI.js";
13
13
  import {
14
14
  failCommand
15
15
  } from "./chunk-PBN6GBJE.js";
@@ -6,7 +6,7 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  VERSION
9
- } from "./chunk-MTUC2Z32.js";
9
+ } from "./chunk-TU2CQJO3.js";
10
10
 
11
11
  // src/registry/compatibility.ts
12
12
  import { compareVersions } from "compare-versions";
@@ -9,7 +9,7 @@ import {
9
9
  formatPreviewProxyBox,
10
10
  hdrToSdrToneMapFilter,
11
11
  parseFirstFrameColour
12
- } from "./chunk-V5J4XEBG.js";
12
+ } from "./chunk-Q3TFX4OZ.js";
13
13
  import {
14
14
  decodeAuthoredAttribute,
15
15
  scanHtmlOpeningTags
@@ -10,20 +10,20 @@ import {
10
10
  seekCompositionTimeline,
11
11
  waitForCompositionFonts,
12
12
  waitForRuntimeReady
13
- } from "./chunk-4D5RBIX6.js";
13
+ } from "./chunk-6MCASYIS.js";
14
14
  import {
15
15
  launchManagedBrowser,
16
16
  resolveManagedGpuMode
17
- } from "./chunk-MMYY4KV3.js";
17
+ } from "./chunk-B5FZ2CQM.js";
18
18
  import {
19
19
  resolveDiagnosticNavigationTimeoutMs
20
- } from "./chunk-EGJVFPUX.js";
20
+ } from "./chunk-ERTJPFCH.js";
21
21
  import {
22
22
  resolveProject
23
- } from "./chunk-5HNZQSO4.js";
23
+ } from "./chunk-37LNY2EC.js";
24
24
  import {
25
25
  serveStaticProjectHtml
26
- } from "./chunk-IKDBT5WT.js";
26
+ } from "./chunk-GOTCGKX6.js";
27
27
  import {
28
28
  defineCommand
29
29
  } from "./chunk-S3S4TGEH.js";
@@ -37,7 +37,7 @@ import {
37
37
  import {
38
38
  printDeprecationNotice,
39
39
  withMeta
40
- } from "./chunk-DLQQA25O.js";
40
+ } from "./chunk-FRGYHRP6.js";
41
41
  import {
42
42
  normalizeErrorMessage
43
43
  } from "./chunk-KNU5COPB.js";
@@ -708,7 +708,7 @@ async function collectTweenBoundaries(page) {
708
708
  });
709
709
  }
710
710
  async function bundleProjectHtml(projectDir) {
711
- const { bundleToSingleHtml } = await import("./compiler-THI7BXZU.js");
711
+ const { bundleToSingleHtml } = await import("./compiler-57M6W5WY.js");
712
712
  return bundleToSingleHtml(projectDir);
713
713
  }
714
714
  async function alignViewportToComposition(page, url) {
@@ -728,15 +728,15 @@ async function alignViewportToComposition(page, url) {
728
728
  });
729
729
  }
730
730
  async function runLayoutAudit(projectDir, opts) {
731
- const { ensureBrowser } = await import("./manager-ZLJD3EAY.js");
731
+ const { ensureBrowser } = await import("./manager-HEUPD2YB.js");
732
732
  const puppeteer = await import("puppeteer-core");
733
- const { buildChromeArgs } = await import("./src-N42CT3YR.js");
733
+ const { buildChromeArgs } = await import("./src-GPUDUKY6.js");
734
734
  const {
735
735
  assertWebGpuAdapterAvailable,
736
736
  compositionRequiresWebGpu,
737
737
  resolveLocalBrowserGpuMode,
738
738
  resolveLocalWebGpu
739
- } = await import("./gpuPolicy-YIW3HL3B.js");
739
+ } = await import("./gpuPolicy-VGE3I5J4.js");
740
740
  const html = await bundleProjectHtml(projectDir);
741
741
  const server = await serveStaticProjectHtml(
742
742
  projectDir,
@@ -0,0 +1,127 @@
1
+ import { createRequire as __hf_createRequire } from "node:module";
2
+ import { fileURLToPath as __hf_fileURLToPath } from "node:url";
3
+ import { dirname as __hf_dirname } from "node:path";
4
+ var require = __hf_createRequire(import.meta.url);
5
+ var __filename = __hf_fileURLToPath(import.meta.url);
6
+ var __dirname = __hf_dirname(__filename);
7
+ import {
8
+ readMediaOffsetSeconds
9
+ } from "./chunk-BSQ7XANM.js";
10
+
11
+ // ../core/dist/mediaLink.js
12
+ var MEDIA_LINK_ATTR = "data-link";
13
+ function readNumber(el, names, fallback) {
14
+ for (const name of names) {
15
+ const raw = el.getAttribute(name);
16
+ if (raw === null || raw.trim() === "")
17
+ continue;
18
+ const value = Number(raw);
19
+ if (Number.isFinite(value))
20
+ return value;
21
+ }
22
+ return fallback;
23
+ }
24
+ function readLinkTiming(el) {
25
+ return {
26
+ start: readNumber(el, ["data-start"], 0),
27
+ duration: readNumber(el, ["data-duration"], 0),
28
+ mediaStart: readMediaOffsetSeconds((name) => el.getAttribute(name)),
29
+ playbackRate: readNumber(el, ["data-playback-rate"], 1)
30
+ };
31
+ }
32
+ var LINK_SCOPE_SELECTOR = "[data-composition-id], [data-composition-file]";
33
+ function mintLinkId(taken) {
34
+ const used = new Set(taken);
35
+ let n = 1;
36
+ while (used.has(`lk-${n}`))
37
+ n += 1;
38
+ return `lk-${n}`;
39
+ }
40
+ function takenLinkIds(doc) {
41
+ return Array.from(doc.querySelectorAll(`[id], [${MEDIA_LINK_ATTR}], [${SYNC_ORIGIN_ATTR}]`)).flatMap((el) => [
42
+ el.id,
43
+ el.getAttribute(MEDIA_LINK_ATTR) ?? "",
44
+ el.getAttribute(SYNC_ORIGIN_ATTR) ?? ""
45
+ ]);
46
+ }
47
+ function renameShared(doc, ids, attr, taken) {
48
+ const renamed = /* @__PURE__ */ new Map();
49
+ for (const id of ids) {
50
+ const el = doc.getElementById(id);
51
+ const old = el?.getAttribute(attr);
52
+ if (!el || !old)
53
+ continue;
54
+ let fresh = renamed.get(old);
55
+ if (!fresh) {
56
+ fresh = mintLinkId(taken);
57
+ taken.add(fresh);
58
+ renamed.set(old, fresh);
59
+ }
60
+ el.setAttribute(attr, fresh);
61
+ }
62
+ }
63
+ function relinkSplitHalves(doc, rightHalfIds) {
64
+ const taken = new Set(takenLinkIds(doc));
65
+ renameShared(doc, rightHalfIds, MEDIA_LINK_ATTR, taken);
66
+ renameShared(doc, idsWithBothSidesCut(doc, rightHalfIds), SYNC_ORIGIN_ATTR, taken);
67
+ }
68
+ function idsWithBothSidesCut(doc, rightHalfIds) {
69
+ const tagsByOrigin = /* @__PURE__ */ new Map();
70
+ const originOf = (id) => doc.getElementById(id)?.getAttribute(SYNC_ORIGIN_ATTR) ?? null;
71
+ for (const id of rightHalfIds) {
72
+ const origin = originOf(id);
73
+ const tag = doc.getElementById(id)?.tagName.toLowerCase();
74
+ if (!origin || !tag)
75
+ continue;
76
+ tagsByOrigin.set(origin, (tagsByOrigin.get(origin) ?? /* @__PURE__ */ new Set()).add(tag));
77
+ }
78
+ return rightHalfIds.filter((id) => {
79
+ const tags = tagsByOrigin.get(originOf(id) ?? "");
80
+ return tags?.has("video") === true && tags.has("audio");
81
+ });
82
+ }
83
+ var SYNC_ORIGIN_ATTR = "data-sync-origin";
84
+ var rateOf = (timing) => timing.playbackRate > 0 ? timing.playbackRate : 1;
85
+ function sourceZeroTime(timing) {
86
+ return timing.start - timing.mediaStart / rateOf(timing);
87
+ }
88
+ function syncOffsetFrames(clip, partner, fps) {
89
+ if (Math.abs(rateOf(clip) - rateOf(partner)) > 1e-6)
90
+ return null;
91
+ const frames = Math.round((sourceZeroTime(clip) - sourceZeroTime(partner)) * fps);
92
+ return Object.is(frames, -0) ? 0 : frames;
93
+ }
94
+ function sharedSeconds(a, b) {
95
+ return Math.min(a.start + a.duration, b.start + b.duration) - Math.max(a.start, b.start);
96
+ }
97
+ function sameOriginInScope(el, tag, origin) {
98
+ const scopeOf = (node) => node.closest(LINK_SCOPE_SELECTOR) ?? el.ownerDocument;
99
+ const scope = scopeOf(el);
100
+ return Array.from(scope.querySelectorAll(tag)).filter((candidate) => candidate.getAttribute(SYNC_ORIGIN_ATTR) === origin && scopeOf(candidate) === scope);
101
+ }
102
+ function findSyncPartner(el) {
103
+ const origin = el.getAttribute(SYNC_ORIGIN_ATTR);
104
+ const tag = el.tagName.toLowerCase();
105
+ if (!origin || tag !== "video" && tag !== "audio")
106
+ return null;
107
+ const partnerTag = tag === "video" ? "audio" : "video";
108
+ const own = readLinkTiming(el);
109
+ let best = null;
110
+ for (const candidate of sameOriginInScope(el, partnerTag, origin)) {
111
+ const timing = readLinkTiming(candidate);
112
+ const shared = sharedSeconds(own, timing);
113
+ const distance = Math.abs(timing.start - own.start);
114
+ if (!best || shared > best.shared || shared === best.shared && distance < best.distance) {
115
+ best = { el: candidate, shared, distance };
116
+ }
117
+ }
118
+ return best?.el ?? null;
119
+ }
120
+
121
+ export {
122
+ MEDIA_LINK_ATTR,
123
+ readLinkTiming,
124
+ relinkSplitHalves,
125
+ syncOffsetFrames,
126
+ findSyncPartner
127
+ };