hyperframes 0.8.156 → 0.8.158

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-U35DO2JR.js → add-VBBOJ3RB.js} +14 -14
  2. package/dist/{animatedGifPrep-MRGFHBVF.js → animatedGifPrep-MTJRHJ5G.js} +9 -9
  3. package/dist/api.js +17 -17
  4. package/dist/{asset-HS4Q6LS2.js → asset-3MLXYJCT.js} +2 -2
  5. package/dist/{assetCataloger-SRTQYA6J.js → assetCataloger-DI7FC5KZ.js} +3 -3
  6. package/dist/{auth-HS6GAILF.js → auth-RJCTHSMH.js} +2 -2
  7. package/dist/{autoUpdate-MRQ4ULBI.js → autoUpdate-VD6R34HF.js} +2 -2
  8. package/dist/{backgroundChecks-K2ZMA43S.js → backgroundChecks-CWWIZDTW.js} +3 -3
  9. package/dist/backgroundChecksWorker.js +3 -3
  10. package/dist/{batchRender-CMVCRSWP.js → batchRender-FTZ67377.js} +4 -4
  11. package/dist/{beats-JYECNCTZ.js → beats-6CN4BEXJ.js} +16 -15
  12. package/dist/{benchmark-JGMKJSPN.js → benchmark-4QSNJZXI.js} +11 -11
  13. package/dist/{browser-63WITJVS.js → browser-H7PRFBJV.js} +5 -5
  14. package/dist/{bundleWithLocalizedFonts-5SLYBFXL.js → bundleWithLocalizedFonts-IVO43QBQ.js} +2 -2
  15. package/dist/{capture-T6QSEGKM.js → capture-GZSY7LZJ.js} +2 -2
  16. package/dist/{capture-7MFOIE4K.js → capture-IEEQTPAS.js} +22 -12
  17. package/dist/{catalog-KVE5KJJT.js → catalog-PD25CVG3.js} +14 -14
  18. package/dist/{catch-up-E3WYWSDY.js → catch-up-2TGBK342.js} +6 -6
  19. package/dist/{check-QRP5WCP2.js → check-HFNJEV3O.js} +36 -35
  20. package/dist/{checkBrowser-5XFA6PXF.js → checkBrowser-767LAZKF.js} +34 -32
  21. package/dist/{chunk-KMSS5TOQ.js → chunk-23VDPRQ3.js} +1 -1
  22. package/dist/{chunk-RXTEP3NB.js → chunk-2XUQPJ3W.js} +2 -2
  23. package/dist/{chunk-JKCKXGIC.js → chunk-3FRK53UC.js} +1 -1
  24. package/dist/{chunk-YNFJWJHW.js → chunk-3MQBIZHG.js} +7 -7
  25. package/dist/{chunk-U3BCDVZO.js → chunk-3QATT3QF.js} +1 -1
  26. package/dist/{chunk-VCCOO2TO.js → chunk-3UMNI4XZ.js} +5 -5
  27. package/dist/{chunk-DRNTIYT3.js → chunk-4R6OZQGX.js} +3 -3
  28. package/dist/{chunk-DDSQBREC.js → chunk-4YDQQQY6.js} +2 -2
  29. package/dist/{chunk-DSX7R5M7.js → chunk-56QTFOWH.js} +4 -4
  30. package/dist/{chunk-YOEGUBBY.js → chunk-7F3B5YYT.js} +82 -14
  31. package/dist/{chunk-MBE4SEL7.js → chunk-7FGHFHWD.js} +5 -5
  32. package/dist/{chunk-OBXWIVYN.js → chunk-7KDQAD2W.js} +5 -11
  33. package/dist/{chunk-YZEHYWOH.js → chunk-7ZWOLEGS.js} +1 -1
  34. package/dist/{chunk-VY23BB2D.js → chunk-BB2SFTMY.js} +4 -4
  35. package/dist/{chunk-FSZAFCU7.js → chunk-CBNI34SD.js} +1 -1
  36. package/dist/{chunk-VK5JRYJL.js → chunk-DCQCGE2W.js} +13 -12
  37. package/dist/{chunk-7U27WUMQ.js → chunk-DISITOR6.js} +5 -4
  38. package/dist/{chunk-SCMNFRL5.js → chunk-EDEFAJI5.js} +10 -9
  39. package/dist/{chunk-56AEM2EL.js → chunk-EEEUI3ON.js} +11 -11
  40. package/dist/{chunk-444O62RL.js → chunk-EGKIQS5J.js} +1 -1
  41. package/dist/{chunk-YGLM2DHX.js → chunk-EY6ISRP3.js} +1 -1
  42. package/dist/{chunk-2K5YII2L.js → chunk-FJT35XBA.js} +3 -3
  43. package/dist/{chunk-Q7FDYQR4.js → chunk-GPUVPZRK.js} +1 -1
  44. package/dist/{chunk-WLYSVHZE.js → chunk-H6BWNY56.js} +2 -2
  45. package/dist/{chunk-YUTUYCGK.js → chunk-IRRRH66M.js} +39 -31
  46. package/dist/{chunk-XXTOOXZ7.js → chunk-J4SSEVRU.js} +2 -2
  47. package/dist/{chunk-TLUGPEW4.js → chunk-J6SJCYAQ.js} +5 -5
  48. package/dist/{chunk-SNMMFFKZ.js → chunk-J7WFHOCW.js} +1 -1
  49. package/dist/chunk-KCF6GHJP.js +250 -0
  50. package/dist/{chunk-SCOXM5LP.js → chunk-KEGTYA7V.js} +1 -1
  51. package/dist/{chunk-DDK6E66K.js → chunk-L6AJC7UQ.js} +1 -1
  52. package/dist/{chunk-VPOEKLZL.js → chunk-LAAGHMRC.js} +13 -2
  53. package/dist/{chunk-HBKKW3NL.js → chunk-LAPUMJOC.js} +6 -6
  54. package/dist/chunk-LPOTN5GW.js +3795 -0
  55. package/dist/{chunk-FIL6QPZT.js → chunk-LQXHRO6F.js} +2 -2
  56. package/dist/{chunk-IOBKVP27.js → chunk-NFX4K6OW.js} +1 -1
  57. package/dist/{chunk-HG6H2ICP.js → chunk-NNQP5TNO.js} +3 -3
  58. package/dist/{chunk-OOCONATR.js → chunk-OTG5H2VM.js} +3 -3
  59. package/dist/{chunk-7K3CHJS3.js → chunk-PKHDQELW.js} +10 -10
  60. package/dist/{chunk-COBIO7VC.js → chunk-QH2PL6J4.js} +1 -1
  61. package/dist/{chunk-YLSSI4XB.js → chunk-QRPYTJBW.js} +1 -1
  62. package/dist/{chunk-7FFGZC2X.js → chunk-QWQ6GQTI.js} +1 -1
  63. package/dist/{chunk-SO44ETGW.js → chunk-RU6AIVON.js} +2 -2
  64. package/dist/{chunk-3THJEW7G.js → chunk-SGIZMTWO.js} +2 -2
  65. package/dist/{chunk-JJERZGVE.js → chunk-SHEVPNUR.js} +1 -1
  66. package/dist/{chunk-LZ2PZIVS.js → chunk-SLUFA6UM.js} +2 -2
  67. package/dist/{chunk-QJEHLWM4.js → chunk-SQHWDFTV.js} +1 -1
  68. package/dist/{chunk-M4CRDGC4.js → chunk-T243WV6D.js} +1 -1
  69. package/dist/{chunk-LJHF4SKT.js → chunk-T76NSAXO.js} +2 -2
  70. package/dist/{chunk-HVQQN4NG.js → chunk-W2SNLHKF.js} +1 -1
  71. package/dist/{chunk-C7WALYAY.js → chunk-Y6E2PW7Z.js} +1 -1
  72. package/dist/{chunk-QOP5D3UM.js → chunk-YB26LWR2.js} +2 -2
  73. package/dist/{chunk-GVJ4LG62.js → chunk-YVD5M26L.js} +2 -2
  74. package/dist/{chunk-NV2JPSI4.js → chunk-Z347DFOL.js} +1 -1
  75. package/dist/{chunk-SCXATNSP.js → chunk-ZZ3ZWTOI.js} +3 -3
  76. package/dist/{clean-4HTCYML6.js → clean-FQUVFH6H.js} +18 -18
  77. package/dist/cli.js +52 -52
  78. package/dist/{cloud-HFBG33UU.js → cloud-BHAYVT6F.js} +4 -4
  79. package/dist/{cloudrun-QK56WQY3.js → cloudrun-STLNWUBW.js} +5 -5
  80. package/dist/commands/contrast-audit.browser.js +25 -8
  81. package/dist/commands/layout-audit.browser.js +117 -12
  82. package/dist/{compare-4RYN3LLC.js → compare-2FRBIK5Z.js} +28 -27
  83. package/dist/{compiler-JPA25IUF.js → compiler-VFJVUZWR.js} +5 -5
  84. package/dist/{component-7ARXR4KZ.js → component-DRKXJVXB.js} +3 -3
  85. package/dist/{compositions-DNBHEIGP.js → compositions-D3SN64J3.js} +14 -14
  86. package/dist/{delete-4XYV72EU.js → delete-NA5WC2IR.js} +2 -2
  87. package/dist/{deterministicFonts-EOMDR6ZF.js → deterministicFonts-LNNVHVS2.js} +2 -2
  88. package/dist/{dist-2YYJYYPY.js → dist-2VXSQLXO.js} +1 -1
  89. package/dist/{dist-SKUIM4QJ.js → dist-SVTSOG4Q.js} +3 -3
  90. package/dist/docker/Dockerfile.render +21 -1
  91. package/dist/{doctor-5PHSH7IK.js → doctor-VXCMPOY3.js} +14 -14
  92. package/dist/{events-FOGRN2KV.js → events-QAHWXFFG.js} +4 -4
  93. package/dist/{events-GQCOQY5E.js → events-ZJEPMUWT.js} +5 -5
  94. package/dist/{feedback-6T6ZJOTM.js → feedback-UGOQ57TU.js} +9 -9
  95. package/dist/{ffmpeg-VJXXLKI6.js → ffmpeg-2ROTISBL.js} +2 -2
  96. package/dist/{figma-PZLGUS6C.js → figma-YO2MJZDP.js} +3 -3
  97. package/dist/fontLocalizeCli.js +12 -12
  98. package/dist/{get-XUNYSY2Z.js → get-WMJAYRNF.js} +2 -2
  99. package/dist/{gpuPolicy-SWCZJRZR.js → gpuPolicy-VXNJ4UBN.js} +9 -9
  100. package/dist/{grade-compare-S27N2NRU.js → grade-compare-QZ7BG2AP.js} +28 -28
  101. package/dist/{help-4HZ75YVH.js → help-AR4MX2AH.js} +1 -1
  102. package/dist/{history-NENOG3BT.js → history-NF764OFQ.js} +8 -8
  103. package/dist/hyperframe-runtime.js +15 -15
  104. package/dist/hyperframe.manifest.json +1 -1
  105. package/dist/hyperframe.runtime.iife.js +15 -15
  106. package/dist/hyperframes-player.global.js +1 -1
  107. package/dist/{info-IDEUAYJZ.js → info-476ERK4G.js} +10 -10
  108. package/dist/{init-KWGZEC7F.js → init-M6YUOBBZ.js} +40 -35
  109. package/dist/{inspect-3WLT3EHZ.js → inspect-QYPUG3UZ.js} +29 -28
  110. package/dist/{installer-I3SLBB7G.js → installer-HF5BXXXM.js} +5 -5
  111. package/dist/{keyframes-7HPN5DKO.js → keyframes-MTZRE34W.js} +8 -8
  112. package/dist/{lambda-MJH6U52V.js → lambda-ZCX7KGTY.js} +6 -6
  113. package/dist/{layout-ZEW4RZRP.js → layout-DLX4HQFL.js} +29 -28
  114. package/dist/{lint-3TNKI4PK.js → lint-OQ5QWCHZ.js} +9 -9
  115. package/dist/{lintProject-XQWXJYSC.js → lintProject-JGHKRO5L.js} +1 -1
  116. package/dist/{list-BJR2IXU4.js → list-AZ6OIOIK.js} +2 -2
  117. package/dist/{login-EA27W5T2.js → login-DJPYT4YZ.js} +4 -4
  118. package/dist/{manager-3EUU5UX6.js → manager-JNJE54OQ.js} +3 -3
  119. package/dist/{media-treatment-3JZFCG6I.js → media-treatment-4YKC4LGB.js} +14 -14
  120. package/dist/{models-IRFIJOIW.js → models-WHDUQZQZ.js} +13 -13
  121. package/dist/{motionShot-S4M7QSW3.js → motionShot-KEHC5AMK.js} +16 -15
  122. package/dist/{normalize-audio-IOY3NRHJ.js → normalize-audio-ATAQGUPX.js} +6 -6
  123. package/dist/{open-SCBC3NF5.js → open-4DXBEX2U.js} +6 -6
  124. package/dist/{parakeetRunner-FGTIYDG7.js → parakeetRunner-5PNBGCGH.js} +14 -14
  125. package/dist/{pipeline-JEFEWIZ3.js → pipeline-QA2422UI.js} +10 -10
  126. package/dist/{play-4TCSBDHO.js → play-SKTSHZM5.js} +21 -21
  127. package/dist/{preflight-OIHM57E7.js → preflight-BH2XUQBS.js} +4 -4
  128. package/dist/{present-S6UBG5VI.js → present-KSQ5GASH.js} +17 -17
  129. package/dist/{preview-HBDXDJCV.js → preview-TDD3QDR3.js} +20 -20
  130. package/dist/{producer-KSAUIT6F.js → producer-PQMZ7OYH.js} +1 -1
  131. package/dist/{projectConfig-CNAK65RI.js → projectConfig-EYYDESVO.js} +7 -7
  132. package/dist/{publication-AUWZFGJI.js → publication-MJY3XYYV.js} +3 -3
  133. package/dist/{publish-EMNP3VCC.js → publish-5TZIKVLW.js} +9 -9
  134. package/dist/{remove-background-GICM6TE5.js → remove-background-HT73ZUIG.js} +11 -11
  135. package/dist/{render-DMHQZMV4.js → render-ADBL3C7S.js} +27 -27
  136. package/dist/{render-PHEQSRHV.js → render-KJCDJEGI.js} +11 -11
  137. package/dist/{render-WMRNH7HO.js → render-YTJ3SMCD.js} +4 -4
  138. package/dist/{render-batch-OUTHTWN5.js → render-batch-AFB2XK3I.js} +4 -4
  139. package/dist/renderSetupWorker.js +1 -1
  140. package/dist/{resolver-NTB6HOZC.js → resolver-F2D2YCSQ.js} +5 -5
  141. package/dist/{sherpa-3YJNJ6TF.js → sherpa-IBKSF6GX.js} +13 -13
  142. package/dist/skills/hyperframes/SKILL.md +1 -1
  143. package/dist/skills/hyperframes/references/frame-worker-core.md +1 -1
  144. package/dist/skills/hyperframes/references/intent-interview.md +2 -2
  145. package/dist/skills/hyperframes/references/production-loop.md +11 -11
  146. package/dist/skills/hyperframes/references/review-loop.md +6 -6
  147. package/dist/skills/hyperframes/references/storyboard-format.md +1 -1
  148. package/dist/skills/hyperframes-cli/SKILL.md +1 -1
  149. package/dist/{skills-MKEJGL35.js → skills-E75DFHGG.js} +7 -7
  150. package/dist/{skillsUpdateCheck-RTLARPPP.js → skillsUpdateCheck-EPTKOBR6.js} +3 -3
  151. package/dist/{snapshot-KMLGFZWY.js → snapshot-Z6T4I5TE.js} +31 -31
  152. package/dist/{src-4HB343JW.js → src-4GCHM2LX.js} +11 -11
  153. package/dist/{src-HJ2NF55P.js → src-NDI4KNT3.js} +8 -8
  154. package/dist/{staticProjectServer-4XX72J23.js → staticProjectServer-ITNEQNQ7.js} +15 -15
  155. package/dist/{status-BMXWFO4L.js → status-RGHSK3DJ.js} +2 -2
  156. package/dist/studio/assets/{hyperframes-player-u2w3bDWo.js → hyperframes-player-DX8LgKgb.js} +1 -1
  157. package/dist/studio/assets/{index-D8B6eEBj.js → index-7Ljcoa9s.js} +83 -83
  158. package/dist/studio/assets/{index-BG28fXIT.js → index-BdnuQ7ta.js} +1 -1
  159. package/dist/studio/assets/{index-WD9j53l5.js → index-DB0YwjiT.js} +1 -1
  160. package/dist/studio/index.html +1 -1
  161. package/dist/{studio-api-LPHMA57T.js → studio-api-JMWUSAG7.js} +9 -9
  162. package/dist/{studioServer-P7GSE74X.js → studioServer-MWZNMAVJ.js} +45 -45
  163. package/dist/{system-QRHPVRPP.js → system-VRXC6S4A.js} +2 -2
  164. package/dist/{telemetry-576VTLGI.js → telemetry-D6A2TRK6.js} +5 -5
  165. package/dist/{timeline-BO7LJJ24.js → timeline-VIF4G3IT.js} +17 -17
  166. package/dist/{tokens-TCYANQDA.js → tokens-ORS6MFMG.js} +2 -2
  167. package/dist/{transcribe-6HLMGCL2.js → transcribe-DNRG7OGE.js} +19 -19
  168. package/dist/{transcribe-6PTFIBO6.js → transcribe-DZ6O6EG5.js} +12 -12
  169. package/dist/{updateCheck-ZLYIZPPQ.js → updateCheck-YY4BPYNT.js} +2 -2
  170. package/dist/{upgrade-DZHQE2PV.js → upgrade-CUDVTTF5.js} +2 -2
  171. package/dist/{urlDownloader-PJTOCTJA.js → urlDownloader-INLS5A6I.js} +8 -8
  172. package/dist/{validate-3I45WC7I.js → validate-CQCQVHUX.js} +23 -22
  173. package/dist/{video-AQFXGGKN.js → video-3GLT6U6Z.js} +9 -9
  174. package/package.json +1 -1
  175. package/dist/chunk-NE55C6S5.js +0 -118
  176. package/dist/chunk-OE4WEQMH.js +0 -3795
  177. /package/dist/{chunk-VYKPBRCB.js → chunk-ALLKNYC3.js} +0 -0
@@ -6,12 +6,12 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  parseOutputResolutionFlag
9
- } from "./chunk-FSZAFCU7.js";
9
+ } from "./chunk-CBNI34SD.js";
10
10
  import {
11
11
  reportVariableIssues,
12
12
  resolveVariablesArg,
13
13
  validateVariablesAgainstProject
14
- } from "./chunk-LZ2PZIVS.js";
14
+ } from "./chunk-SLUFA6UM.js";
15
15
  import {
16
16
  readAllowedCompositionFpsFromDir
17
17
  } from "./chunk-WPNE5NEP.js";
@@ -26,11 +26,11 @@ import {
26
26
  import {
27
27
  c
28
28
  } from "./chunk-ZTZA4UWZ.js";
29
- import "./chunk-3THJEW7G.js";
30
- import "./chunk-OE4WEQMH.js";
29
+ import "./chunk-SGIZMTWO.js";
30
+ import "./chunk-LPOTN5GW.js";
31
31
  import "./chunk-VC76R6W2.js";
32
32
  import "./chunk-UJKQWGFF.js";
33
- import "./chunk-VYKPBRCB.js";
33
+ import "./chunk-ALLKNYC3.js";
34
34
  import "./chunk-OFQWTKPW.js";
35
35
  import "./chunk-DPVXBVLL.js";
36
36
  import "./chunk-T76PLPD6.js";
@@ -286,6 +286,16 @@ window.__contrastAuditPrepare = function () {
286
286
  var fontWeight = Number(cs.fontWeight) || 400;
287
287
  var large = fontSize >= 24 || (fontSize >= 19 && fontWeight >= 700);
288
288
 
289
+ // Glyphs sit on this element's own fill. The bounding box also contains
290
+ // border-radius corners and neighbouring pixels, and those read as the
291
+ // panel behind a circular avatar. An opaque background with no image is
292
+ // the fill; pixel sampling stays for transparent text.
293
+ var ownBg = null;
294
+ if ((cs.backgroundImage || "none") === "none") {
295
+ var parsedOwnBg = parseColor(cs.backgroundColor || "");
296
+ if (parsedOwnBg && parsedOwnBg[3] >= 0.99) ownBg = parsedOwnBg;
297
+ }
298
+
289
299
  // Hide this element's OWN text paint so the caller's next screenshot
290
300
  // reveals the true pixels behind the glyphs. Layout-neutral: color/fill
291
301
  // never affect box geometry. `!important` beats any non-!important rule
@@ -341,6 +351,7 @@ window.__contrastAuditPrepare = function () {
341
351
  fontSize: fontSize,
342
352
  fontWeight: fontWeight,
343
353
  large: large,
354
+ ownBg: ownBg,
344
355
  bbox: { x: rect.x, y: rect.y, w: rect.width, h: rect.height },
345
356
  });
346
357
  }
@@ -465,15 +476,21 @@ window.__contrastAuditFinish = async function (imgBase64, time, candidates) {
465
476
  }
466
477
  if (rr.length === 0) continue;
467
478
 
468
- // A transparent sampled backdrop is supplied by the downstream editor,
469
- // not this composition. WCAG contrast cannot be inferred until that live
470
- // video/image is known, so do not invent an opaque browser default and
471
- // hard-fail an otherwise valid alpha overlay.
472
- if (median(aa) < 255) continue;
473
-
474
- var bgR = median(rr),
475
- bgG = median(gg),
479
+ var bgR, bgG, bgB;
480
+ if (c.ownBg && c.ownBg.length >= 4 && c.ownBg[3] >= 0.99) {
481
+ bgR = c.ownBg[0];
482
+ bgG = c.ownBg[1];
483
+ bgB = c.ownBg[2];
484
+ } else {
485
+ // A transparent sampled backdrop is supplied by the downstream editor,
486
+ // not this composition. WCAG contrast cannot be inferred until that live
487
+ // video/image is known, so do not invent an opaque browser default and
488
+ // hard-fail an otherwise valid alpha overlay.
489
+ if (median(aa) < 255) continue;
490
+ bgR = median(rr);
491
+ bgG = median(gg);
476
492
  bgB = median(bb);
493
+ }
477
494
 
478
495
  // Composite foreground alpha over the measured background
479
496
  var fg = c.fg;
@@ -662,10 +662,14 @@
662
662
  }
663
663
 
664
664
  function hasAllowOverlapFlag(element) {
665
- // Overlap intent belongs to the text block that participates in the
666
- // layering. Inheriting this marker from a scene/root would turn one local
667
- // waiver into a blanket exemption for every collision in that subtree.
668
- return element.hasAttribute("data-layout-allow-overlap");
665
+ // The marker applies to the element that carries it and to text inside
666
+ // that container. It stops at the composition root: a waiver on the scene
667
+ // itself would exempt every collision in the subtree.
668
+ for (let current = element; current; current = current.parentElement) {
669
+ if (current.hasAttribute("data-composition-id")) return false;
670
+ if (current.hasAttribute("data-layout-allow-overlap")) return true;
671
+ }
672
+ return false;
669
673
  }
670
674
 
671
675
  function isTransparentColor(color) {
@@ -800,16 +804,48 @@
800
804
  message: "Two text blocks overlap and may render unreadable.",
801
805
  rect: a.rect,
802
806
  fixHint:
803
- "Give each block its own zone, or mark intentional layering with data-layout-allow-overlap.",
807
+ "Give each block its own zone, or put data-layout-allow-overlap on the text or on a container inside the scene. A marker on the scene root does not apply.",
808
+ };
809
+ }
810
+
811
+ function hiddenVisibilityAncestor(element) {
812
+ for (let parent = element.parentElement; parent; parent = parent.parentElement) {
813
+ const visibility = getComputedStyle(parent).visibility;
814
+ if (visibility === "hidden" || visibility === "collapse") return parent;
815
+ }
816
+ return null;
817
+ }
818
+
819
+ function visibilityEscapeIssue(block, hiddenAncestor, time) {
820
+ return {
821
+ code: "visibility_escapes_segment",
822
+ severity: "warning",
823
+ time,
824
+ selector: uniqueSelectorFor(block.element),
825
+ containerSelector: uniqueSelectorFor(hiddenAncestor),
826
+ text: textContentFor(block.element),
827
+ message:
828
+ "This text stays on screen after its segment ends. visibility:visible here overrides an ancestor's visibility:hidden, so the runtime hide does not reach it.",
829
+ rect: block.rect,
830
+ fixHint: "Remove the explicit visibility:visible so this element hides with its ancestor.",
804
831
  };
805
832
  }
806
833
 
807
834
  function contentOverlapIssues(root, time) {
808
835
  const blocks = collectSolidTextBlocks(root);
809
836
  const issues = [];
810
- for (let i = 0; i < blocks.length; i++) {
811
- for (let j = i + 1; j < blocks.length; j++) {
812
- const issue = overlapIssue(blocks[i], blocks[j], time);
837
+ const participating = [];
838
+ for (const block of blocks) {
839
+ const hiddenAncestor = hiddenVisibilityAncestor(block.element);
840
+ if (hiddenAncestor) {
841
+ issues.push(visibilityEscapeIssue(block, hiddenAncestor, time));
842
+ continue;
843
+ }
844
+ participating.push(block);
845
+ }
846
+ for (let i = 0; i < participating.length; i++) {
847
+ for (let j = i + 1; j < participating.length; j++) {
848
+ const issue = overlapIssue(participating[i], participating[j], time);
813
849
  if (issue) issues.push(issue);
814
850
  }
815
851
  }
@@ -820,8 +856,10 @@
820
856
  let imageAlpha = 0;
821
857
  if (style.backgroundImage && style.backgroundImage !== "none") {
822
858
  if (style.backgroundImage.includes("url(")) return true;
823
- // A gradient only occludes as much as its colours — a 4%-alpha grid/scrim must not count.
824
- imageAlpha = gradientLayersAlpha(style.backgroundImage);
859
+ // A gradient only occludes as much as its colours — a 4%-alpha grid/scrim
860
+ // must not count, and neither must a solid-color dot a couple of pixels
861
+ // wide tiled across a much larger background-size.
862
+ imageAlpha = gradientLayersAlpha(style.backgroundImage, style.backgroundSize);
825
863
  }
826
864
  const colorValue = isTransparentColor(style.backgroundColor)
827
865
  ? 0
@@ -831,14 +869,68 @@
831
869
  }
832
870
 
833
871
  // background-image layers stack: two 0.5-alpha gradients paint at 1-(1-.5)^2 = .75.
834
- function gradientLayersAlpha(backgroundImage) {
872
+ function gradientLayersAlpha(backgroundImage, backgroundSize) {
835
873
  let combined = 0;
836
874
  for (const layer of splitTopLevelCommas(backgroundImage)) {
837
- combined = 1 - (1 - combined) * (1 - gradientMaxAlpha(layer));
875
+ const coverage = gradientStopCoverage(layer, backgroundSize);
876
+ combined = 1 - (1 - combined) * (1 - gradientMaxAlpha(layer) * coverage);
838
877
  }
839
878
  return combined;
840
879
  }
841
880
 
881
+ // Share of a radial dot's tile. A linear fill, or an opaque stop after a
882
+ // transparent one, stays fully painted. A 1.6px dot on a 38px tile does not.
883
+ function gradientStopCoverage(layer, backgroundSize) {
884
+ if (!/radial-gradient/i.test(layer) || namesAColor(withoutScoredColors(layer))) return 1;
885
+ const stops = [
886
+ ...layer.matchAll(/(#[0-9a-fA-F]{3,8}|rgba?\([^)]+\)|transparent)\s+([\d.]+)(px|%)/gi),
887
+ ];
888
+ const tile = pxTile(backgroundSize);
889
+ const reach = tile ? leadingOpaqueRadius(stops, tile) : null;
890
+ if (reach === null) return 1;
891
+ return Math.min(1, (Math.PI * reach * reach) / (tile * tile));
892
+ }
893
+
894
+ function pxTile(backgroundSize) {
895
+ const sizeMatch = String(backgroundSize || "").match(/([\d.]+)px/);
896
+ return sizeMatch ? Number(sizeMatch[1]) : 0;
897
+ }
898
+
899
+ function leadingOpaqueRadius(stops, tile) {
900
+ const walked = walkOpaquePrefix(stops, tile);
901
+ if (!walked || !walked.sawOpaque || !walked.sawTransparent) return null;
902
+ return walked.reach;
903
+ }
904
+
905
+ function walkOpaquePrefix(stops, tile) {
906
+ const state = { reach: 0, sawOpaque: false, sawTransparent: false };
907
+ for (const stop of stops) {
908
+ if (!takeRadiusStop(state, stop, tile)) return null;
909
+ }
910
+ return state;
911
+ }
912
+
913
+ function takeRadiusStop(state, stop, tile) {
914
+ if (stopAlpha(stop[1] || "") <= 0.6) {
915
+ state.sawTransparent = true;
916
+ return true;
917
+ }
918
+ if (state.sawTransparent) return false;
919
+ state.sawOpaque = true;
920
+ state.reach = Math.max(state.reach, stopLength(stop, tile));
921
+ return true;
922
+ }
923
+
924
+ function stopAlpha(color) {
925
+ if (color === "transparent") return 0;
926
+ if (color.startsWith("#")) return 1;
927
+ return colorAlpha(color);
928
+ }
929
+
930
+ function stopLength(stop, tile) {
931
+ return stop[3] === "%" ? (Number(stop[2]) / 100) * tile : Number(stop[2]);
932
+ }
933
+
842
934
  function splitTopLevelCommas(value) {
843
935
  const parts = [];
844
936
  let depth = 0;
@@ -862,6 +954,7 @@
862
954
  .replace(/(?:repeating-)?(?:linear|radial|conic)-gradient\(/gi, "(")
863
955
  .replace(/rgba?\([^)]*\)/gi, "");
864
956
  if (/[a-z][a-z-]+\(/i.test(known)) return 1;
957
+ if (namesAColor(known)) return 1;
865
958
  const colors = backgroundImage.match(/rgba?\([^)]*\)|#[0-9a-fA-F]{3,8}\b|\btransparent\b/g);
866
959
  if (!colors) return 1;
867
960
  let max = 0;
@@ -884,6 +977,18 @@
884
977
  return max;
885
978
  }
886
979
 
980
+ function withoutScoredColors(layer) {
981
+ return layer.replace(/rgba?\([^)]*\)|#[0-9a-fA-F]{3,8}\b/g, " ");
982
+ }
983
+
984
+ function namesAColor(known) {
985
+ const words = known.replace(
986
+ /\b(?:to|top|bottom|left|right|center|circle|ellipse|closest-side|farthest-side|closest-corner|farthest-corner|from|deg|rad|turn|grad|transparent|repeating|linear|radial|conic|gradient)\b/gi,
987
+ " ",
988
+ );
989
+ return /\b[a-z]{3,}\b/i.test(words);
990
+ }
991
+
887
992
  const RASTER_TAGS = new Set(["IMG", "VIDEO", "CANVAS"]);
888
993
  const FRAME_MEDIA_TAGS = new Set([...RASTER_TAGS, "SVG"]);
889
994
  const imageAlphaCanvases = new WeakMap();
@@ -15,44 +15,44 @@ import {
15
15
  import "./chunk-MRF4AMKD.js";
16
16
  import {
17
17
  serveStaticProjectHtml
18
- } from "./chunk-DRNTIYT3.js";
18
+ } from "./chunk-4R6OZQGX.js";
19
19
  import "./chunk-XUHOIDKG.js";
20
- import "./chunk-XXTOOXZ7.js";
20
+ import "./chunk-J4SSEVRU.js";
21
21
  import "./chunk-X7MTZ4T2.js";
22
22
  import {
23
23
  openSettledCompositionPage,
24
24
  seekCompositionTimeline
25
- } from "./chunk-MBE4SEL7.js";
25
+ } from "./chunk-7FGHFHWD.js";
26
26
  import "./chunk-FH7WODJH.js";
27
- import "./chunk-VPOEKLZL.js";
28
- import "./chunk-SNMMFFKZ.js";
27
+ import "./chunk-LAAGHMRC.js";
28
+ import "./chunk-J7WFHOCW.js";
29
29
  import "./chunk-WPNE5NEP.js";
30
- import "./chunk-VK5JRYJL.js";
31
- import "./chunk-DSX7R5M7.js";
30
+ import "./chunk-DCQCGE2W.js";
31
+ import "./chunk-56QTFOWH.js";
32
32
  import "./chunk-C6TPGUWD.js";
33
33
  import "./chunk-6PIGOKTE.js";
34
- import "./chunk-7U27WUMQ.js";
34
+ import "./chunk-DISITOR6.js";
35
35
  import "./chunk-FFDC5OWV.js";
36
36
  import "./chunk-K2FLNJVB.js";
37
- import "./chunk-QOP5D3UM.js";
37
+ import "./chunk-YB26LWR2.js";
38
38
  import "./chunk-442JNXRM.js";
39
- import "./chunk-Q7FDYQR4.js";
39
+ import "./chunk-GPUVPZRK.js";
40
40
  import "./chunk-XT7X6QCP.js";
41
41
  import "./chunk-4YYJOFKS.js";
42
42
  import "./chunk-HVW7ABXD.js";
43
- import "./chunk-JKCKXGIC.js";
44
- import "./chunk-FIL6QPZT.js";
45
- import "./chunk-YLSSI4XB.js";
43
+ import "./chunk-3FRK53UC.js";
44
+ import "./chunk-LQXHRO6F.js";
45
+ import "./chunk-QRPYTJBW.js";
46
46
  import "./chunk-AWDFDFI3.js";
47
47
  import "./chunk-P6LJ4Y32.js";
48
48
  import "./chunk-GMECXFAN.js";
49
49
  import "./chunk-5CS4T6C6.js";
50
50
  import {
51
51
  trackCompareSheet
52
- } from "./chunk-RXTEP3NB.js";
53
- import "./chunk-WLYSVHZE.js";
52
+ } from "./chunk-2XUQPJ3W.js";
53
+ import "./chunk-H6BWNY56.js";
54
54
  import "./chunk-VWG7OQKU.js";
55
- import "./chunk-7FFGZC2X.js";
55
+ import "./chunk-QWQ6GQTI.js";
56
56
  import {
57
57
  defineCommand
58
58
  } from "./chunk-S3S4TGEH.js";
@@ -68,31 +68,31 @@ import "./chunk-EOOEC32M.js";
68
68
  import "./chunk-TJSTGSAW.js";
69
69
  import {
70
70
  withMeta
71
- } from "./chunk-COBIO7VC.js";
71
+ } from "./chunk-QH2PL6J4.js";
72
72
  import "./chunk-K4WIOZFP.js";
73
73
  import "./chunk-XUXGIA7H.js";
74
74
  import "./chunk-WERLJGIC.js";
75
75
  import "./chunk-ISN5GRYI.js";
76
- import "./chunk-SO44ETGW.js";
76
+ import "./chunk-RU6AIVON.js";
77
77
  import "./chunk-EOVYQ3IG.js";
78
78
  import "./chunk-XT6MXC7A.js";
79
- import "./chunk-YUTUYCGK.js";
80
- import "./chunk-2K5YII2L.js";
81
- import "./chunk-NE55C6S5.js";
79
+ import "./chunk-IRRRH66M.js";
80
+ import "./chunk-FJT35XBA.js";
81
+ import "./chunk-KCF6GHJP.js";
82
82
  import "./chunk-JYVGYKXG.js";
83
- import "./chunk-OBXWIVYN.js";
84
- import "./chunk-3THJEW7G.js";
85
- import "./chunk-OE4WEQMH.js";
83
+ import "./chunk-7KDQAD2W.js";
84
+ import "./chunk-SGIZMTWO.js";
85
+ import "./chunk-LPOTN5GW.js";
86
86
  import "./chunk-VC76R6W2.js";
87
87
  import "./chunk-UJKQWGFF.js";
88
- import "./chunk-VYKPBRCB.js";
88
+ import "./chunk-ALLKNYC3.js";
89
89
  import "./chunk-OFQWTKPW.js";
90
90
  import "./chunk-DPVXBVLL.js";
91
91
  import "./chunk-T76PLPD6.js";
92
92
  import "./chunk-FXMKHHPO.js";
93
93
  import "./chunk-RQVDTPGD.js";
94
94
  import "./chunk-TWWSYAKJ.js";
95
- import "./chunk-YOEGUBBY.js";
95
+ import "./chunk-7F3B5YYT.js";
96
96
  import "./chunk-IWFLMU2N.js";
97
97
  import "./chunk-3VGU2SH7.js";
98
98
  import "./chunk-VAS6HQX3.js";
@@ -104,6 +104,7 @@ import "./chunk-IXLUTE6N.js";
104
104
  import {
105
105
  normalizeErrorMessage
106
106
  } from "./chunk-KNU5COPB.js";
107
+ import "./chunk-KGPLIH7B.js";
107
108
  import "./chunk-3GXQPCJC.js";
108
109
  import "./chunk-M2WBOQ2Q.js";
109
110
 
@@ -285,7 +286,7 @@ function cleanupPreparedCompareVariants(variants) {
285
286
  }
286
287
  async function renderCompareVariant(variant, opts) {
287
288
  try {
288
- const { bundleToSingleHtml } = await import("./compiler-JPA25IUF.js");
289
+ const { bundleToSingleHtml } = await import("./compiler-VFJVUZWR.js");
289
290
  const html = await bundleToSingleHtml(variant.projectDir);
290
291
  const server = await serveStaticProjectHtml(variant.projectDir, html);
291
292
  try {
@@ -24,8 +24,8 @@ import {
24
24
  scopeCssToComposition,
25
25
  validateHyperframeHtmlContract,
26
26
  wrapScopedCompositionScript
27
- } from "./chunk-2K5YII2L.js";
28
- import "./chunk-NE55C6S5.js";
27
+ } from "./chunk-FJT35XBA.js";
28
+ import "./chunk-KCF6GHJP.js";
29
29
  import {
30
30
  AFTER_FONTS_SCRIPT_TYPE,
31
31
  AUDIO_GROUP_RENDER_ID_ATTR,
@@ -56,13 +56,13 @@ import {
56
56
  shouldClampResolvedMediaDuration,
57
57
  stripEmbeddedRuntimeScripts,
58
58
  styleElementsFor
59
- } from "./chunk-OE4WEQMH.js";
59
+ } from "./chunk-LPOTN5GW.js";
60
60
  import "./chunk-VC76R6W2.js";
61
61
  import "./chunk-UJKQWGFF.js";
62
- import "./chunk-VYKPBRCB.js";
62
+ import "./chunk-ALLKNYC3.js";
63
63
  import "./chunk-OFQWTKPW.js";
64
64
  import "./chunk-DPVXBVLL.js";
65
- import "./chunk-YOEGUBBY.js";
65
+ import "./chunk-7F3B5YYT.js";
66
66
  import "./chunk-IWFLMU2N.js";
67
67
  import "./chunk-3VGU2SH7.js";
68
68
  import "./chunk-VAS6HQX3.js";
@@ -7,7 +7,7 @@ var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  downloadRender,
9
9
  runAssetImport
10
- } from "./chunk-GVJ4LG62.js";
10
+ } from "./chunk-YVD5M26L.js";
11
11
  import {
12
12
  FigmaClientError,
13
13
  createFigmaClient,
@@ -16,7 +16,7 @@ import {
16
16
  readBindings,
17
17
  resolveBindings,
18
18
  withFigmaErrors
19
- } from "./chunk-JJERZGVE.js";
19
+ } from "./chunk-SHEVPNUR.js";
20
20
  import "./chunk-K2FLNJVB.js";
21
21
  import {
22
22
  defineCommand
@@ -159,7 +159,7 @@ var component_default = defineCommand({
159
159
  `${result.unresolved.length} binding(s) reference tokens not yet imported \u2014 colors baked as literals (flagged data-figma-unresolved). Run \`hyperframes figma tokens\` on the source/library file, then re-import to link them.`
160
160
  );
161
161
  }
162
- const { trackFigmaImport } = await import("./telemetry-576VTLGI.js");
162
+ const { trackFigmaImport } = await import("./telemetry-D6A2TRK6.js");
163
163
  trackFigmaImport({
164
164
  phase: "component",
165
165
  unresolvedBindings: result.unresolved.length,
@@ -6,15 +6,15 @@ var __filename = __hf_fileURLToPath(import.meta.url);
6
6
  var __dirname = __hf_dirname(__filename);
7
7
  import {
8
8
  resolveProject
9
- } from "./chunk-DDK6E66K.js";
9
+ } from "./chunk-L6AJC7UQ.js";
10
10
  import "./chunk-K2FLNJVB.js";
11
11
  import {
12
12
  ensureDOMParser
13
13
  } from "./chunk-442JNXRM.js";
14
- import "./chunk-RXTEP3NB.js";
15
- import "./chunk-WLYSVHZE.js";
14
+ import "./chunk-2XUQPJ3W.js";
15
+ import "./chunk-H6BWNY56.js";
16
16
  import "./chunk-VWG7OQKU.js";
17
- import "./chunk-7FFGZC2X.js";
17
+ import "./chunk-QWQ6GQTI.js";
18
18
  import {
19
19
  defineCommand
20
20
  } from "./chunk-S3S4TGEH.js";
@@ -25,25 +25,25 @@ import {
25
25
  } from "./chunk-ZTZA4UWZ.js";
26
26
  import {
27
27
  withMeta
28
- } from "./chunk-COBIO7VC.js";
28
+ } from "./chunk-QH2PL6J4.js";
29
29
  import "./chunk-K4WIOZFP.js";
30
30
  import "./chunk-XUXGIA7H.js";
31
31
  import "./chunk-WERLJGIC.js";
32
32
  import "./chunk-ISN5GRYI.js";
33
- import "./chunk-SO44ETGW.js";
33
+ import "./chunk-RU6AIVON.js";
34
34
  import "./chunk-XT6MXC7A.js";
35
35
  import {
36
36
  resolveReferencedStart
37
- } from "./chunk-YUTUYCGK.js";
38
- import "./chunk-2K5YII2L.js";
39
- import "./chunk-NE55C6S5.js";
37
+ } from "./chunk-IRRRH66M.js";
38
+ import "./chunk-FJT35XBA.js";
39
+ import "./chunk-KCF6GHJP.js";
40
40
  import "./chunk-JYVGYKXG.js";
41
- import "./chunk-OBXWIVYN.js";
42
- import "./chunk-3THJEW7G.js";
43
- import "./chunk-OE4WEQMH.js";
41
+ import "./chunk-7KDQAD2W.js";
42
+ import "./chunk-SGIZMTWO.js";
43
+ import "./chunk-LPOTN5GW.js";
44
44
  import "./chunk-VC76R6W2.js";
45
45
  import "./chunk-UJKQWGFF.js";
46
- import "./chunk-VYKPBRCB.js";
46
+ import "./chunk-ALLKNYC3.js";
47
47
  import "./chunk-OFQWTKPW.js";
48
48
  import "./chunk-DPVXBVLL.js";
49
49
  import "./chunk-T76PLPD6.js";
@@ -52,7 +52,7 @@ import "./chunk-RQVDTPGD.js";
52
52
  import "./chunk-TWWSYAKJ.js";
53
53
  import {
54
54
  resolveCompositionDuration
55
- } from "./chunk-YOEGUBBY.js";
55
+ } from "./chunk-7F3B5YYT.js";
56
56
  import {
57
57
  readProjectFile
58
58
  } from "./chunk-IWFLMU2N.js";
@@ -24,12 +24,12 @@ import {
24
24
  } from "./chunk-ZTZA4UWZ.js";
25
25
  import {
26
26
  withMeta
27
- } from "./chunk-COBIO7VC.js";
27
+ } from "./chunk-QH2PL6J4.js";
28
28
  import "./chunk-K4WIOZFP.js";
29
29
  import "./chunk-XUXGIA7H.js";
30
30
  import "./chunk-WERLJGIC.js";
31
31
  import "./chunk-ISN5GRYI.js";
32
- import "./chunk-SO44ETGW.js";
32
+ import "./chunk-RU6AIVON.js";
33
33
  import "./chunk-BXCMXMJQ.js";
34
34
  import "./chunk-EOVYQ3IG.js";
35
35
  import "./chunk-OFQWTKPW.js";
@@ -20,12 +20,12 @@ import {
20
20
  normalizeSystemFontPrimaryFamilies,
21
21
  parseFontFamilyValue,
22
22
  resolveFontFamilyDeclarationFamilies
23
- } from "./chunk-U3BCDVZO.js";
23
+ } from "./chunk-3QATT3QF.js";
24
24
  import "./chunk-FI4I7CME.js";
25
25
  import "./chunk-TJSTGSAW.js";
26
26
  import {
27
27
  FONT_ALIAS_KEYS
28
- } from "./chunk-VYKPBRCB.js";
28
+ } from "./chunk-ALLKNYC3.js";
29
29
  import "./chunk-DPVXBVLL.js";
30
30
  import "./chunk-SDYDNHEE.js";
31
31
  import "./chunk-TYXH3EKP.js";
@@ -11,7 +11,7 @@ import {
11
11
  lintMediaUrls,
12
12
  lintProject,
13
13
  shouldBlockRender
14
- } from "./chunk-YOEGUBBY.js";
14
+ } from "./chunk-7F3B5YYT.js";
15
15
  import "./chunk-IWFLMU2N.js";
16
16
  import "./chunk-3VGU2SH7.js";
17
17
  import "./chunk-VAS6HQX3.js";
@@ -72,7 +72,7 @@ import {
72
72
  serializeVfxChain,
73
73
  toFps,
74
74
  validateVariables
75
- } from "./chunk-3THJEW7G.js";
75
+ } from "./chunk-SGIZMTWO.js";
76
76
  import {
77
77
  AUDIO_GROUP_RENDER_ID_ATTR,
78
78
  COMPOSITION_SOURCE_URL,
@@ -128,7 +128,7 @@ import {
128
128
  sourceTimeAt,
129
129
  stripEmbeddedRuntimeScripts,
130
130
  timeAtSourceTime
131
- } from "./chunk-OE4WEQMH.js";
131
+ } from "./chunk-LPOTN5GW.js";
132
132
  import "./chunk-VC76R6W2.js";
133
133
  import {
134
134
  AUDIBLE_MEDIA_SELECTOR,
@@ -162,7 +162,7 @@ import {
162
162
  updateElementInHtml,
163
163
  validateCompositionGsap,
164
164
  validateCompositionHtml
165
- } from "./chunk-VYKPBRCB.js";
165
+ } from "./chunk-ALLKNYC3.js";
166
166
  import {
167
167
  ProjectRootMissingError,
168
168
  folderGone,
@@ -14,7 +14,7 @@ ARG TARGETARCH=amd64
14
14
  ARG PLAYWRIGHT_VERSION=1.61.1
15
15
 
16
16
  RUN apt-get update && apt-get install -y --no-install-recommends \
17
- ca-certificates curl unzip ffmpeg chromium \
17
+ ca-certificates curl unzip xz-utils chromium \
18
18
  libgbm1 libnss3 libatk-bridge2.0-0 libdrm2 libxcomposite1 \
19
19
  libxdamage1 libxrandr2 libcups2 libasound2 libpangocairo-1.0-0 \
20
20
  libxshmfence1 libgtk-3-0 \
@@ -23,6 +23,26 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
23
23
  fontconfig \
24
24
  && rm -rf /var/lib/apt/lists/* && apt-get clean && fc-cache -fv
25
25
 
26
+ # One pinned static FFmpeg build (BtbN n8.0.1, per arch) instead of Debian's apt
27
+ # ffmpeg, so regression baselines and the shipped images use the same version.
28
+ # Bump the URLs and sha256s together, and keep in sync with the other Dockerfiles
29
+ # and .github/actions/install-ffmpeg-linux/action.yml.
30
+ ARG FFMPEG_RELEASE=https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-02-28-12-59
31
+ ARG FFMPEG_BUILD=ffmpeg-n8.0.1-66-g27b8d1a017
32
+ ARG FFMPEG_SHA256_AMD64=26d2ecd0cefba99f9d1ea92252a3a4f743a58df4c1c3cf9f8bbaaa40b1fca5b0
33
+ ARG FFMPEG_SHA256_ARM64=d72cc324cb65dd92a9ffe699cc95ccbacfef4def8d3ad9fe2b5164a6a71b9595
34
+ RUN case "$TARGETARCH" in \
35
+ amd64) FF_ARCH=linux64; FF_SHA256="$FFMPEG_SHA256_AMD64" ;; \
36
+ arm64) FF_ARCH=linuxarm64; FF_SHA256="$FFMPEG_SHA256_ARM64" ;; \
37
+ *) echo "unsupported TARGETARCH '$TARGETARCH'" >&2; exit 1 ;; \
38
+ esac \
39
+ && curl -fsSL -o /tmp/ffmpeg.tar.xz "$FFMPEG_RELEASE/$FFMPEG_BUILD-$FF_ARCH-gpl-8.0.tar.xz" \
40
+ && echo "$FF_SHA256 /tmp/ffmpeg.tar.xz" | sha256sum -c - \
41
+ && tar -xJf /tmp/ffmpeg.tar.xz -C /usr/local/bin --strip-components=2 --wildcards '*/bin/ffmpeg' '*/bin/ffprobe' \
42
+ && rm /tmp/ffmpeg.tar.xz \
43
+ && ffmpeg -version | grep -F "ffmpeg version ${FFMPEG_BUILD#ffmpeg-}" \
44
+ && ffprobe -version | grep -F "ffprobe version ${FFMPEG_BUILD#ffmpeg-}"
45
+
26
46
  ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
27
47
  ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
28
48
  ENV CONTAINER=true