@vfrey/vfrey 0.0.1 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (603) hide show
  1. package/LICENSE +33 -0
  2. package/README.md +78 -3
  3. package/accounts.example.json +61 -0
  4. package/accounts.first-run.json +41 -0
  5. package/bin/vfrey.mjs +36 -0
  6. package/integration-tools/README.md +43 -0
  7. package/integration-tools/image/pillow.md +32 -0
  8. package/integration-tools/image/playwright.md +33 -0
  9. package/integration-tools/image/resvg.md +36 -0
  10. package/integration-tools/image/satori.md +36 -0
  11. package/integration-tools/image/sharp.md +38 -0
  12. package/integration-tools/video/blender.md +34 -0
  13. package/integration-tools/video/ffmpeg.md +41 -0
  14. package/integration-tools/video/manim.md +37 -0
  15. package/integration-tools/video/motion-canvas.md +37 -0
  16. package/integration-tools/video/remotion.md +50 -0
  17. package/integration-tools/video/revideo.md +32 -0
  18. package/package.json +74 -6
  19. package/skills/vfrey-orchestrator/SKILL.md +15 -0
  20. package/skills/vfrey-orchestrator/channel-video/SKILL.md +41 -0
  21. package/skills/vfrey-product/SKILL.md +63 -0
  22. package/skills/vfrey-product/examples/concurrency-vs-parallelism/framey/cook-one.svg +14 -0
  23. package/skills/vfrey-product/examples/concurrency-vs-parallelism/framey/cook-two.svg +22 -0
  24. package/skills/vfrey-product/examples/concurrency-vs-parallelism/framey/index.html +70 -0
  25. package/skills/vfrey-product/examples/concurrency-vs-parallelism/remotion/cook-one.svg +14 -0
  26. package/skills/vfrey-product/examples/concurrency-vs-parallelism/remotion/cook-two.svg +22 -0
  27. package/skills/vfrey-product/examples/concurrency-vs-parallelism/remotion/index.tsx +49 -0
  28. package/skills/vfrey-product/examples/concurrency-vs-parallelism/script.json +15 -0
  29. package/skills/vfrey-product/examples/octopus-facts/index.html +60 -0
  30. package/skills/vfrey-product/examples/octopus-facts/octopus.svg +8 -0
  31. package/skills/vfrey-product/examples/octopus-facts/script.json +14 -0
  32. package/skills/vfrey-product/push/SKILL.md +15 -0
  33. package/skills/vfrey-product/scenes/NOTICE +5 -0
  34. package/skills/vfrey-product/scenes/blocks.md +57 -0
  35. package/skills/vfrey-product/scenes/craft.md +118 -0
  36. package/skills/vfrey-product/scenes/motion.md +88 -0
  37. package/src/analytics/dashboard.ts +109 -0
  38. package/src/analytics/index.ts +260 -0
  39. package/src/api/client.ts +282 -0
  40. package/src/api/commands.ts +330 -0
  41. package/src/api/config.ts +34 -0
  42. package/src/api/creators.ts +463 -0
  43. package/src/api/credentials.ts +152 -0
  44. package/src/api/mail.ts +333 -0
  45. package/src/api/topics.ts +207 -0
  46. package/src/api/types.ts +205 -0
  47. package/src/cli.ts +467 -0
  48. package/src/cloud/executor.ts +281 -0
  49. package/src/cloud/job.ts +106 -0
  50. package/src/cloud/render-job.ts +187 -0
  51. package/src/config.ts +309 -0
  52. package/src/dashboard-link.ts +180 -0
  53. package/src/dashboard-start.ts +103 -0
  54. package/src/desk/channel.ts +64 -0
  55. package/src/desk/cli.ts +216 -0
  56. package/src/desk/creators-route.ts +129 -0
  57. package/src/desk/fonts/JetBrainsMono-OFL.txt +93 -0
  58. package/src/desk/fonts/google-sans-flex-latin.woff2 +0 -0
  59. package/src/desk/fonts/jetbrains-mono-medium.woff2 +0 -0
  60. package/src/desk/http.ts +460 -0
  61. package/src/desk/mail-route.ts +103 -0
  62. package/src/desk/overlay.ts +112 -0
  63. package/src/desk/preview.ts +422 -0
  64. package/src/desk/screens.ts +149 -0
  65. package/src/desk/secrets.ts +143 -0
  66. package/src/desk/series.ts +127 -0
  67. package/src/desk/state.ts +77 -0
  68. package/src/desk/studio-route.ts +119 -0
  69. package/src/desk/tick-runner.ts +66 -0
  70. package/src/desk/tick.ts +56 -0
  71. package/src/desk/topics-route.ts +41 -0
  72. package/src/desk/ui/app.css +505 -0
  73. package/src/desk/ui/app.js +185 -0
  74. package/src/desk/ui/apple-icon.png +0 -0
  75. package/src/desk/ui/components.js +79 -0
  76. package/src/desk/ui/core.js +156 -0
  77. package/src/desk/ui/favicon.ico +0 -0
  78. package/src/desk/ui/icon.svg +1 -0
  79. package/src/desk/ui/icons.js +49 -0
  80. package/src/desk/ui/index.html +41 -0
  81. package/src/desk/ui/metrics-math.d.ts +22 -0
  82. package/src/desk/ui/metrics-math.js +135 -0
  83. package/src/desk/ui/theme.js +5 -0
  84. package/src/desk/ui/views-creators.js +209 -0
  85. package/src/desk/ui/views-keys.js +114 -0
  86. package/src/desk/ui/views-mail.js +188 -0
  87. package/src/desk/ui/views-misc.js +123 -0
  88. package/src/desk/ui/views-review.js +119 -0
  89. package/src/desk/ui/views-runs.js +350 -0
  90. package/src/desk/ui/views-screens.js +163 -0
  91. package/src/desk/ui/views-series.js +318 -0
  92. package/src/desk/ui/views-topics.js +87 -0
  93. package/src/desk/verbs.ts +361 -0
  94. package/src/doctor.ts +212 -0
  95. package/src/drain.ts +14 -0
  96. package/src/engage/index.ts +217 -0
  97. package/src/generate/index.ts +110 -0
  98. package/src/generate/script.ts +152 -0
  99. package/src/generate/title.ts +78 -0
  100. package/src/help.ts +233 -0
  101. package/src/home.ts +45 -0
  102. package/src/llm/client.ts +177 -0
  103. package/src/log.ts +7 -0
  104. package/src/oauth/tokens.ts +189 -0
  105. package/src/oauth/vault.ts +72 -0
  106. package/src/pipeline/review.ts +642 -0
  107. package/src/pipeline/run.ts +443 -0
  108. package/src/pipeline/series-guard.ts +26 -0
  109. package/src/pipeline/source-fetch.ts +69 -0
  110. package/src/pipeline/stages.ts +728 -0
  111. package/src/pipeline/topics-source.ts +90 -0
  112. package/src/product/commands.ts +296 -0
  113. package/src/product/config-file.ts +38 -0
  114. package/src/product/engine-choice.ts +89 -0
  115. package/src/product/engines.ts +103 -0
  116. package/src/product/insights.ts +50 -0
  117. package/src/product/keys.ts +67 -0
  118. package/src/product/paths.ts +18 -0
  119. package/src/product/probes.ts +88 -0
  120. package/src/product/push-flow.ts +90 -0
  121. package/src/product/render-video.ts +21 -0
  122. package/src/product/short.ts +62 -0
  123. package/src/product/update.ts +32 -0
  124. package/src/project/canonical.ts +14 -0
  125. package/src/project/commands.ts +177 -0
  126. package/src/project/dashboard-status.ts +28 -0
  127. package/src/project/discover.ts +19 -0
  128. package/src/project/index-file.ts +73 -0
  129. package/src/project/marker.ts +87 -0
  130. package/src/project/migrate.ts +201 -0
  131. package/src/project/names.ts +27 -0
  132. package/src/project/notice.ts +16 -0
  133. package/src/project/open.ts +88 -0
  134. package/src/project/scaffold.ts +112 -0
  135. package/src/project/templates.ts +42 -0
  136. package/src/project/videos.ts +64 -0
  137. package/src/publish/facebook.ts +91 -0
  138. package/src/publish/index.ts +12 -0
  139. package/src/publish/instagram.ts +97 -0
  140. package/src/publish/rate.ts +62 -0
  141. package/src/publish/session.ts +242 -0
  142. package/src/publish/tiktok.ts +202 -0
  143. package/src/publish/youtube.ts +177 -0
  144. package/src/queue/desk-ops.ts +1170 -0
  145. package/src/queue/seal.ts +3 -0
  146. package/src/queue/store.ts +1006 -0
  147. package/src/remotion/AiLabel.tsx +26 -0
  148. package/src/remotion/Root.tsx +73 -0
  149. package/src/remotion/defaults.ts +26 -0
  150. package/src/remotion/films/claude/ClaudeFilm.tsx +1014 -0
  151. package/src/remotion/films/engine/EngineMark.tsx +17 -0
  152. package/src/remotion/films/rea/ReaShort.tsx +552 -0
  153. package/src/remotion/films/rea/drawings.tsx +907 -0
  154. package/src/remotion/films/rea/timing.ts +144 -0
  155. package/src/remotion/index.ts +4 -0
  156. package/src/remotion/templates/EditorialSplit.tsx +39 -0
  157. package/src/remotion/templates/KineticType.tsx +39 -0
  158. package/src/remotion/templates/SignalBoard.tsx +50 -0
  159. package/src/remotion/timing.ts +22 -0
  160. package/src/render/chrome.ts +78 -0
  161. package/src/render/engine-mark.ts +29 -0
  162. package/src/render/framey-template.ts +130 -0
  163. package/src/render/html-engine.ts +149 -0
  164. package/src/render/node-crypto-stub.ts +11 -0
  165. package/src/render/probe.ts +29 -0
  166. package/src/render/props.ts +17 -0
  167. package/src/render/vertical-short.ts +35 -0
  168. package/src/render/webpack.ts +33 -0
  169. package/src/render/worker.ts +65 -0
  170. package/src/scene/assets/fonts/TitanOne-OFL.txt +94 -0
  171. package/src/scene/assets/fonts/titan-one.woff2 +0 -0
  172. package/src/scene/assets/gsap/LICENSE.txt +8 -0
  173. package/src/scene/assets/gsap/gsap.min.js +11 -0
  174. package/src/scene/audio.ts +54 -0
  175. package/src/scene/blocks/LICENSE +190 -0
  176. package/src/scene/blocks/NOTICE +5 -0
  177. package/src/scene/blocks/bar-chart-race/bar-chart-race.html +585 -0
  178. package/src/scene/blocks/beat-freeze-cut/beat-freeze-cut.html +874 -0
  179. package/src/scene/blocks/camcorder-hud/camcorder-hud.html +164 -0
  180. package/src/scene/blocks/camera-dolly-zoom/camera-dolly-zoom.html +355 -0
  181. package/src/scene/blocks/code-diff/code-diff.html +817 -0
  182. package/src/scene/blocks/code-snippet-apple-terminal-pro/code-snippet-apple-terminal-pro.html +248 -0
  183. package/src/scene/blocks/code-typing/code-typing.html +764 -0
  184. package/src/scene/blocks/data-chart/data-chart.html +452 -0
  185. package/src/scene/blocks/flowchart-vertical/flowchart-vertical.html +454 -0
  186. package/src/scene/blocks/hw-scribble-transition/hw-scribble-transition.html +153 -0
  187. package/src/scene/blocks/index.json +824 -0
  188. package/src/scene/blocks/lt-accent-underline/lt-accent-underline.html +107 -0
  189. package/src/scene/blocks/lt-bold-block/lt-bold-block.html +109 -0
  190. package/src/scene/blocks/lt-clean-bar/lt-clean-bar.html +112 -0
  191. package/src/scene/blocks/lt-dark-card/lt-dark-card.html +111 -0
  192. package/src/scene/blocks/lt-kicker-name/lt-kicker-name.html +114 -0
  193. package/src/scene/blocks/lt-mask-reveal/lt-mask-reveal.html +120 -0
  194. package/src/scene/blocks/lt-neon-border/lt-neon-border.html +391 -0
  195. package/src/scene/blocks/lt-stack-bars/lt-stack-bars.html +109 -0
  196. package/src/scene/blocks/macos-notification/macos-notification.html +194 -0
  197. package/src/scene/blocks/mk-background/mk-background.html +236 -0
  198. package/src/scene/blocks/mk-callout-highlight/mk-callout-highlight.html +183 -0
  199. package/src/scene/blocks/mk-clone-wall-transition/mk-clone-wall-transition.html +226 -0
  200. package/src/scene/blocks/mk-line-graph/mk-line-graph.html +293 -0
  201. package/src/scene/blocks/mk-progress-stat/mk-progress-stat.html +186 -0
  202. package/src/scene/blocks/mk-specs-list/mk-specs-list.html +223 -0
  203. package/src/scene/blocks/news-ticker/news-ticker.html +409 -0
  204. package/src/scene/blocks/organic-light-leak-overlay/organic-light-leak-overlay.html +126 -0
  205. package/src/scene/blocks/oscilloscope-trace/oscilloscope-trace.html +519 -0
  206. package/src/scene/blocks/snow/snow.html +205 -0
  207. package/src/scene/blocks/split-flap-board/split-flap-board.html +347 -0
  208. package/src/scene/blocks/spotify-card/spotify-card.html +294 -0
  209. package/src/scene/blocks/starfield/starfield.html +188 -0
  210. package/src/scene/blocks/thread-message-stack/thread-message-stack.html +239 -0
  211. package/src/scene/blocks/week-in-merges/week-in-merges.html +470 -0
  212. package/src/scene/blocks/x-post/x-post.html +437 -0
  213. package/src/scene/blocks/yt-comment-card/yt-comment-card.html +319 -0
  214. package/src/scene/blocks/yt-lcd-background/yt-lcd-background.html +307 -0
  215. package/src/scene/blocks/yt-prism-title/yt-prism-title.html +205 -0
  216. package/src/scene/blocks.ts +229 -0
  217. package/src/scene/command.ts +272 -0
  218. package/src/scene/figure.ts +181 -0
  219. package/src/scene/glyphs.ts +107 -0
  220. package/src/scene/init.ts +86 -0
  221. package/src/scene/inspect/css-tree.d.ts +6 -0
  222. package/src/scene/inspect/page-scripts.ts +272 -0
  223. package/src/scene/inspect/report.ts +405 -0
  224. package/src/scene/inspect/run.ts +200 -0
  225. package/src/scene/inspect/source.ts +236 -0
  226. package/src/scene/label.ts +131 -0
  227. package/src/scene/net-guard.ts +74 -0
  228. package/src/scene/render.ts +292 -0
  229. package/src/scene/runtime/browser.ts +199 -0
  230. package/src/scene/runtime/core.ts +181 -0
  231. package/src/scene/runtime/react.tsx +115 -0
  232. package/src/scene/runtime/transitions.ts +133 -0
  233. package/src/scene/sanitize.ts +181 -0
  234. package/src/scene/scene.ts +152 -0
  235. package/src/scene/studio-command.ts +48 -0
  236. package/src/scene/studio-skin.ts +59 -0
  237. package/src/scene/studio.ts +337 -0
  238. package/src/scene/supply.ts +111 -0
  239. package/src/scene/timing.ts +288 -0
  240. package/src/scene/transitions/LICENSE +190 -0
  241. package/src/scene/transitions/NOTICE +5 -0
  242. package/src/scene/transitions/SOURCE.json +24 -0
  243. package/src/scene/transitions/transitions.global.js +38 -0
  244. package/src/scene/transitions.ts +26 -0
  245. package/src/service/all-projects.ts +153 -0
  246. package/src/service/commands.ts +256 -0
  247. package/src/service/due.ts +82 -0
  248. package/src/service/lock.ts +101 -0
  249. package/src/service/log-file.ts +56 -0
  250. package/src/service/state.ts +41 -0
  251. package/src/service/units.ts +90 -0
  252. package/src/service/worker.ts +51 -0
  253. package/src/skill-agents.ts +74 -0
  254. package/src/skill-install.ts +334 -0
  255. package/src/sync-write.ts +21 -0
  256. package/src/tick-report.ts +205 -0
  257. package/src/tts.ts +124 -0
  258. package/vendor/@vfrey/contracts/dist/account.d.ts +97 -0
  259. package/vendor/@vfrey/contracts/dist/account.js +27 -0
  260. package/vendor/@vfrey/contracts/dist/checks.d.ts +8 -0
  261. package/vendor/@vfrey/contracts/dist/checks.js +1 -0
  262. package/vendor/@vfrey/contracts/dist/credentials/crypto.d.ts +4 -0
  263. package/vendor/@vfrey/contracts/dist/credentials/crypto.js +38 -0
  264. package/vendor/@vfrey/contracts/dist/domain/advice-persona.d.ts +10 -0
  265. package/vendor/@vfrey/contracts/dist/domain/advice-persona.js +24 -0
  266. package/vendor/@vfrey/contracts/dist/domain/backoff.d.ts +13 -0
  267. package/vendor/@vfrey/contracts/dist/domain/backoff.js +27 -0
  268. package/vendor/@vfrey/contracts/dist/domain/cadence.d.ts +29 -0
  269. package/vendor/@vfrey/contracts/dist/domain/cadence.js +95 -0
  270. package/vendor/@vfrey/contracts/dist/domain/creators.d.ts +146 -0
  271. package/vendor/@vfrey/contracts/dist/domain/creators.js +2 -0
  272. package/vendor/@vfrey/contracts/dist/domain/disclosure.d.ts +127 -0
  273. package/vendor/@vfrey/contracts/dist/domain/disclosure.js +250 -0
  274. package/vendor/@vfrey/contracts/dist/domain/errors.d.ts +34 -0
  275. package/vendor/@vfrey/contracts/dist/domain/errors.js +68 -0
  276. package/vendor/@vfrey/contracts/dist/domain/redact.d.ts +1 -0
  277. package/vendor/@vfrey/contracts/dist/domain/redact.js +21 -0
  278. package/vendor/@vfrey/contracts/dist/domain/revenue.d.ts +13 -0
  279. package/vendor/@vfrey/contracts/dist/domain/revenue.js +16 -0
  280. package/vendor/@vfrey/contracts/dist/domain/safety.d.ts +20 -0
  281. package/vendor/@vfrey/contracts/dist/domain/safety.js +61 -0
  282. package/vendor/@vfrey/contracts/dist/domain/similarity.d.ts +13 -0
  283. package/vendor/@vfrey/contracts/dist/domain/similarity.js +100 -0
  284. package/vendor/@vfrey/contracts/dist/domain/templates.d.ts +18 -0
  285. package/vendor/@vfrey/contracts/dist/domain/templates.js +67 -0
  286. package/vendor/@vfrey/contracts/dist/domain/tiktok-chunks.d.ts +19 -0
  287. package/vendor/@vfrey/contracts/dist/domain/tiktok-chunks.js +52 -0
  288. package/vendor/@vfrey/contracts/dist/domain/topics.d.ts +78 -0
  289. package/vendor/@vfrey/contracts/dist/domain/topics.js +4 -0
  290. package/vendor/@vfrey/contracts/dist/domain/types.d.ts +216 -0
  291. package/vendor/@vfrey/contracts/dist/domain/types.js +1 -0
  292. package/vendor/@vfrey/contracts/dist/domain/variation.d.ts +57 -0
  293. package/vendor/@vfrey/contracts/dist/domain/variation.js +278 -0
  294. package/vendor/@vfrey/contracts/dist/events.d.ts +20 -0
  295. package/vendor/@vfrey/contracts/dist/events.js +1 -0
  296. package/vendor/@vfrey/contracts/dist/http.d.ts +11 -0
  297. package/vendor/@vfrey/contracts/dist/http.js +37 -0
  298. package/vendor/@vfrey/contracts/dist/index.d.ts +22 -0
  299. package/vendor/@vfrey/contracts/dist/index.js +22 -0
  300. package/vendor/@vfrey/contracts/dist/log.d.ts +2 -0
  301. package/vendor/@vfrey/contracts/dist/log.js +10 -0
  302. package/vendor/@vfrey/contracts/dist/mail.d.ts +55 -0
  303. package/vendor/@vfrey/contracts/dist/mail.js +1 -0
  304. package/vendor/@vfrey/contracts/package.json +18 -0
  305. package/vendor/@vfrey/ingest/dist/index.d.ts +41 -0
  306. package/vendor/@vfrey/ingest/dist/index.js +221 -0
  307. package/vendor/@vfrey/ingest/dist/parse.d.ts +5 -0
  308. package/vendor/@vfrey/ingest/dist/parse.js +165 -0
  309. package/vendor/@vfrey/ingest/package.json +21 -0
  310. package/vendor/framey/LICENSE +190 -0
  311. package/vendor/framey/NOTICE +15 -0
  312. package/vendor/framey/SOURCE.json +24 -0
  313. package/vendor/framey/STUDIO-SOURCE.json +9 -0
  314. package/vendor/framey/bin/framey-localize-fonts.mjs +12 -0
  315. package/vendor/framey/bin/framey.mjs +16 -0
  316. package/vendor/framey/dist/add-VMJD5KBS.js +75 -0
  317. package/vendor/framey/dist/animatedGifPrep-QPKGJ6PM.js +43 -0
  318. package/vendor/framey/dist/api.d.ts +211 -0
  319. package/vendor/framey/dist/api.js +76 -0
  320. package/vendor/framey/dist/appHistory-WW56FZTT.js +31 -0
  321. package/vendor/framey/dist/asset-WQKGOELE.js +26 -0
  322. package/vendor/framey/dist/audio-RSJWVWRA.js +1936 -0
  323. package/vendor/framey/dist/batchRender-3HPICDCT.js +366 -0
  324. package/vendor/framey/dist/beats-HL2BDUZI.js +273 -0
  325. package/vendor/framey/dist/benchmark-RWCWHI5Z.js +230 -0
  326. package/vendor/framey/dist/browser-ECYET3Q2.js +206 -0
  327. package/vendor/framey/dist/bundleWithLocalizedFonts-ALYBQEQT.js +52 -0
  328. package/vendor/framey/dist/captureCompositionFrame-4DA6SEH2.js +94 -0
  329. package/vendor/framey/dist/catalog-5JVDEUWK.js +979 -0
  330. package/vendor/framey/dist/catch-up-NEBCL5NO.js +106 -0
  331. package/vendor/framey/dist/check-F5N544ML.js +111 -0
  332. package/vendor/framey/dist/checkBrowser-LZ66CMJG.js +110 -0
  333. package/vendor/framey/dist/chunk-2K7Z2HVP.js +372 -0
  334. package/vendor/framey/dist/chunk-2UZQHDM7.js +323 -0
  335. package/vendor/framey/dist/chunk-2X4PQEYM.js +34 -0
  336. package/vendor/framey/dist/chunk-3422KMTD.js +168 -0
  337. package/vendor/framey/dist/chunk-3FYD4YEK.js +72 -0
  338. package/vendor/framey/dist/chunk-3GXQPCJC.js +682 -0
  339. package/vendor/framey/dist/chunk-3LM6YPBR.js +179 -0
  340. package/vendor/framey/dist/chunk-442JNXRM.js +20 -0
  341. package/vendor/framey/dist/chunk-4BNN5FGX.js +182 -0
  342. package/vendor/framey/dist/chunk-4P7NX5BM.js +11532 -0
  343. package/vendor/framey/dist/chunk-4UMPIPCQ.js +88 -0
  344. package/vendor/framey/dist/chunk-4YYJOFKS.js +28 -0
  345. package/vendor/framey/dist/chunk-54HJ63Q2.js +29 -0
  346. package/vendor/framey/dist/chunk-5ETJX6WM.js +89 -0
  347. package/vendor/framey/dist/chunk-5SG54JRS.js +68 -0
  348. package/vendor/framey/dist/chunk-634HSJ3J.js +58 -0
  349. package/vendor/framey/dist/chunk-66LREXGS.js +48 -0
  350. package/vendor/framey/dist/chunk-6BEFEWFB.js +25 -0
  351. package/vendor/framey/dist/chunk-6BNTGNGD.js +286 -0
  352. package/vendor/framey/dist/chunk-6DDPOHMK.js +140 -0
  353. package/vendor/framey/dist/chunk-6GV5XSOR.js +214 -0
  354. package/vendor/framey/dist/chunk-6JR2XUEE.js +127 -0
  355. package/vendor/framey/dist/chunk-73QVATIM.js +362 -0
  356. package/vendor/framey/dist/chunk-7FMUTGOH.js +279 -0
  357. package/vendor/framey/dist/chunk-7JQFJ6JJ.js +291 -0
  358. package/vendor/framey/dist/chunk-AHPGAESX.js +113 -0
  359. package/vendor/framey/dist/chunk-AHX34EFP.js +15 -0
  360. package/vendor/framey/dist/chunk-AJ5CSAEZ.js +487 -0
  361. package/vendor/framey/dist/chunk-B7RJV74O.js +5047 -0
  362. package/vendor/framey/dist/chunk-BL4U6U52.js +254 -0
  363. package/vendor/framey/dist/chunk-BSQ7XANM.js +210 -0
  364. package/vendor/framey/dist/chunk-BZ56MTDX.js +6 -0
  365. package/vendor/framey/dist/chunk-C5BO7PMT.js +282 -0
  366. package/vendor/framey/dist/chunk-CFUCHO4T.js +358 -0
  367. package/vendor/framey/dist/chunk-CZGHFATT.js +31 -0
  368. package/vendor/framey/dist/chunk-DLA44CMS.js +5649 -0
  369. package/vendor/framey/dist/chunk-DPVXBVLL.js +31292 -0
  370. package/vendor/framey/dist/chunk-DQBY7FRR.js +397 -0
  371. package/vendor/framey/dist/chunk-EAMLBAHA.js +154 -0
  372. package/vendor/framey/dist/chunk-EOVYQ3IG.js +143 -0
  373. package/vendor/framey/dist/chunk-EVMY7IPL.js +612 -0
  374. package/vendor/framey/dist/chunk-FG4BBFZI.js +122 -0
  375. package/vendor/framey/dist/chunk-FI4I7CME.js +56 -0
  376. package/vendor/framey/dist/chunk-FLREUEHW.js +2081 -0
  377. package/vendor/framey/dist/chunk-FUFP7A7S.js +1126 -0
  378. package/vendor/framey/dist/chunk-FV3PIKGH.js +56 -0
  379. package/vendor/framey/dist/chunk-FXMKHHPO.js +123 -0
  380. package/vendor/framey/dist/chunk-GGZAM5VH.js +1187 -0
  381. package/vendor/framey/dist/chunk-GKZEVJIB.js +39 -0
  382. package/vendor/framey/dist/chunk-GMECXFAN.js +57 -0
  383. package/vendor/framey/dist/chunk-GNEFDLFB.js +621 -0
  384. package/vendor/framey/dist/chunk-GPMLSOEG.js +19274 -0
  385. package/vendor/framey/dist/chunk-GPYVT5EE.js +59 -0
  386. package/vendor/framey/dist/chunk-H6IEMZEV.js +40 -0
  387. package/vendor/framey/dist/chunk-HEFQCIXR.js +170 -0
  388. package/vendor/framey/dist/chunk-HFQ4CWHA.js +118 -0
  389. package/vendor/framey/dist/chunk-HPDTCOKE.js +304 -0
  390. package/vendor/framey/dist/chunk-HTUHQKDB.js +548 -0
  391. package/vendor/framey/dist/chunk-HU2SPFNG.js +103 -0
  392. package/vendor/framey/dist/chunk-HVW7ABXD.js +19 -0
  393. package/vendor/framey/dist/chunk-IG7NDKXO.js +26 -0
  394. package/vendor/framey/dist/chunk-II3J3WXK.js +246 -0
  395. package/vendor/framey/dist/chunk-IR35BCLK.js +13 -0
  396. package/vendor/framey/dist/chunk-ISN5GRYI.js +20 -0
  397. package/vendor/framey/dist/chunk-IUONB55J.js +669 -0
  398. package/vendor/framey/dist/chunk-IVSUQR2B.js +161 -0
  399. package/vendor/framey/dist/chunk-IXU6PQSW.js +259 -0
  400. package/vendor/framey/dist/chunk-IZCW2NKT.js +29 -0
  401. package/vendor/framey/dist/chunk-JGXJU5PF.js +68 -0
  402. package/vendor/framey/dist/chunk-JHOCK3DG.js +27 -0
  403. package/vendor/framey/dist/chunk-JVBRJMOP.js +121 -0
  404. package/vendor/framey/dist/chunk-K4MJX7SR.js +17 -0
  405. package/vendor/framey/dist/chunk-K4WKGXRC.js +18 -0
  406. package/vendor/framey/dist/chunk-KGPLIH7B.js +127 -0
  407. package/vendor/framey/dist/chunk-KLIKCX6Q.js +63 -0
  408. package/vendor/framey/dist/chunk-KXTKKBOC.js +61 -0
  409. package/vendor/framey/dist/chunk-KZI44OPA.js +185 -0
  410. package/vendor/framey/dist/chunk-LEKZNRKI.js +45 -0
  411. package/vendor/framey/dist/chunk-LFGJWOVA.js +61 -0
  412. package/vendor/framey/dist/chunk-LLMSX6V6.js +17 -0
  413. package/vendor/framey/dist/chunk-LTGTN2TH.js +195 -0
  414. package/vendor/framey/dist/chunk-M2WBOQ2Q.js +54 -0
  415. package/vendor/framey/dist/chunk-MI5FTLYK.js +399 -0
  416. package/vendor/framey/dist/chunk-MLQP2QUF.js +1809 -0
  417. package/vendor/framey/dist/chunk-MMQ52NIZ.js +956 -0
  418. package/vendor/framey/dist/chunk-ND46XKK3.js +742 -0
  419. package/vendor/framey/dist/chunk-NYEXNSHM.js +504 -0
  420. package/vendor/framey/dist/chunk-O4YRB27L.js +57 -0
  421. package/vendor/framey/dist/chunk-O7BGSQ5F.js +92 -0
  422. package/vendor/framey/dist/chunk-OFQWTKPW.js +117 -0
  423. package/vendor/framey/dist/chunk-P5ZBLXJ6.js +91 -0
  424. package/vendor/framey/dist/chunk-P6LJ4Y32.js +4662 -0
  425. package/vendor/framey/dist/chunk-PKZ7RK5N.js +281 -0
  426. package/vendor/framey/dist/chunk-PURHAXFL.js +15 -0
  427. package/vendor/framey/dist/chunk-Q5X2B5WT.js +29 -0
  428. package/vendor/framey/dist/chunk-QAMKOG67.js +248 -0
  429. package/vendor/framey/dist/chunk-R6YBK4XX.js +514 -0
  430. package/vendor/framey/dist/chunk-RGLQURIX.js +2997 -0
  431. package/vendor/framey/dist/chunk-RNV3DM4S.js +3573 -0
  432. package/vendor/framey/dist/chunk-ROEW726S.js +4638 -0
  433. package/vendor/framey/dist/chunk-RQVDTPGD.js +6 -0
  434. package/vendor/framey/dist/chunk-RVZHGOGR.js +26 -0
  435. package/vendor/framey/dist/chunk-RXATE6FZ.js +385 -0
  436. package/vendor/framey/dist/chunk-S3S4TGEH.js +424 -0
  437. package/vendor/framey/dist/chunk-SDYDNHEE.js +11202 -0
  438. package/vendor/framey/dist/chunk-SSWBU67I.js +173 -0
  439. package/vendor/framey/dist/chunk-ST35C4K6.js +28 -0
  440. package/vendor/framey/dist/chunk-SZNTYTIV.js +990 -0
  441. package/vendor/framey/dist/chunk-T2EUWCJE.js +29 -0
  442. package/vendor/framey/dist/chunk-T6AGUTZJ.js +444 -0
  443. package/vendor/framey/dist/chunk-THJALHFJ.js +11131 -0
  444. package/vendor/framey/dist/chunk-TIQB63MX.js +18128 -0
  445. package/vendor/framey/dist/chunk-U242RTCT.js +134 -0
  446. package/vendor/framey/dist/chunk-UJZREAV6.js +3901 -0
  447. package/vendor/framey/dist/chunk-UMD3V7CU.js +264 -0
  448. package/vendor/framey/dist/chunk-UOFAE5RF.js +42 -0
  449. package/vendor/framey/dist/chunk-UTEIUGAZ.js +29 -0
  450. package/vendor/framey/dist/chunk-VAS6HQX3.js +138 -0
  451. package/vendor/framey/dist/chunk-VC76R6W2.js +27 -0
  452. package/vendor/framey/dist/chunk-VFZ7W5W7.js +226 -0
  453. package/vendor/framey/dist/chunk-VHNLZAE2.js +348 -0
  454. package/vendor/framey/dist/chunk-VMC4WSH5.js +278 -0
  455. package/vendor/framey/dist/chunk-VORQIH64.js +108 -0
  456. package/vendor/framey/dist/chunk-VTXFRIHO.js +186 -0
  457. package/vendor/framey/dist/chunk-W2LGJSEN.js +182 -0
  458. package/vendor/framey/dist/chunk-WKBM7NDG.js +32 -0
  459. package/vendor/framey/dist/chunk-WMQNIQDJ.js +2057 -0
  460. package/vendor/framey/dist/chunk-WN4XZC5F.js +504 -0
  461. package/vendor/framey/dist/chunk-WQ6ZXHFQ.js +133 -0
  462. package/vendor/framey/dist/chunk-X7HBSTCZ.js +53 -0
  463. package/vendor/framey/dist/chunk-X7MTZ4T2.js +6 -0
  464. package/vendor/framey/dist/chunk-XPTOJZJF.js +308 -0
  465. package/vendor/framey/dist/chunk-XT6MXC7A.js +6 -0
  466. package/vendor/framey/dist/chunk-XT7X6QCP.js +6 -0
  467. package/vendor/framey/dist/chunk-XTMDWNEC.js +2820 -0
  468. package/vendor/framey/dist/chunk-XUHOIDKG.js +6 -0
  469. package/vendor/framey/dist/chunk-XX7LTW5Y.js +138 -0
  470. package/vendor/framey/dist/chunk-Y3YGTZEG.js +382 -0
  471. package/vendor/framey/dist/chunk-Y5SBSGN7.js +346 -0
  472. package/vendor/framey/dist/chunk-YCMVI4MZ.js +625 -0
  473. package/vendor/framey/dist/chunk-YOR4CTCE.js +261 -0
  474. package/vendor/framey/dist/chunk-YPRBGITP.js +2748 -0
  475. package/vendor/framey/dist/chunk-ZKDMAOFU.js +32 -0
  476. package/vendor/framey/dist/chunk-ZW6DURPF.js +1318 -0
  477. package/vendor/framey/dist/clean-ZJOGDKDM.js +336 -0
  478. package/vendor/framey/dist/cli.js +439 -0
  479. package/vendor/framey/dist/cloudrun-HGJ3B6ZV.js +767 -0
  480. package/vendor/framey/dist/commands/contrast-audit.browser.js +643 -0
  481. package/vendor/framey/dist/commands/layout-audit.browser.js +2914 -0
  482. package/vendor/framey/dist/commands/motion-sample.browser.js +74 -0
  483. package/vendor/framey/dist/commands/motion-signature.browser.js +475 -0
  484. package/vendor/framey/dist/compare-W7UY3BAZ.js +463 -0
  485. package/vendor/framey/dist/compiler-TM3W6GYF.js +136 -0
  486. package/vendor/framey/dist/component-QF5VGYMU.js +176 -0
  487. package/vendor/framey/dist/compositions-XT3PMNDF.js +238 -0
  488. package/vendor/framey/dist/contactSheet-7W6GYHBQ.js +24 -0
  489. package/vendor/framey/dist/deploy-6FJPWKF2.js +299 -0
  490. package/vendor/framey/dist/destroy-HE2RIPKZ.js +57 -0
  491. package/vendor/framey/dist/deterministicFonts-RADD3BSX.js +50 -0
  492. package/vendor/framey/dist/dist-4S2FGGVY.js +422 -0
  493. package/vendor/framey/dist/dist-BE4B2EZE.js +32 -0
  494. package/vendor/framey/dist/dist-EWXJGN63.js +129 -0
  495. package/vendor/framey/dist/docs-VKIRFEEX.js +131 -0
  496. package/vendor/framey/dist/doctor-2UNJ2G7U.js +74 -0
  497. package/vendor/framey/dist/dom-37K6YOH4.js +14 -0
  498. package/vendor/framey/dist/dotEnv-7PZQTVIM.js +54 -0
  499. package/vendor/framey/dist/events-ACY3P2PA.js +76 -0
  500. package/vendor/framey/dist/events-IHB3B2MK.js +69 -0
  501. package/vendor/framey/dist/ffmpeg-DR5LGGSK.js +63 -0
  502. package/vendor/framey/dist/figma-BODVUPHB.js +63 -0
  503. package/vendor/framey/dist/fontData.generated-NXAOI4GH.js +13 -0
  504. package/vendor/framey/dist/fontLocalizeCli.js +142 -0
  505. package/vendor/framey/dist/gpuPolicy-XLEXORZY.js +49 -0
  506. package/vendor/framey/dist/grade-compare-GAXFQ74C.js +661 -0
  507. package/vendor/framey/dist/gsapParser-IEUSLYDJ.js +2885 -0
  508. package/vendor/framey/dist/gsapParserAcorn-LZJKCFQI.js +30 -0
  509. package/vendor/framey/dist/help-VCB5X2HS.js +184 -0
  510. package/vendor/framey/dist/history-ENGZEVFT.js +471 -0
  511. package/vendor/framey/dist/hyperframe.manifest.json +22 -0
  512. package/vendor/framey/dist/hyperframe.runtime.iife.js +1132 -0
  513. package/vendor/framey/dist/hyperframes-player.global.js +478 -0
  514. package/vendor/framey/dist/hyperframes-slideshow.global.js +148 -0
  515. package/vendor/framey/dist/info-WPCJHBMU.js +182 -0
  516. package/vendor/framey/dist/init-G4WGLYGD.js +1176 -0
  517. package/vendor/framey/dist/inspect-5IQ6CNEQ.js +106 -0
  518. package/vendor/framey/dist/installer-ML4HWUV7.js +40 -0
  519. package/vendor/framey/dist/keyframes-Q6XJO7VW.js +2755 -0
  520. package/vendor/framey/dist/lambda-A7JC74JF.js +468 -0
  521. package/vendor/framey/dist/layout-YET6XNXA.js +95 -0
  522. package/vendor/framey/dist/lint-I7FZN2VJ.js +162 -0
  523. package/vendor/framey/dist/lintProject-PDB3UN72.js +30 -0
  524. package/vendor/framey/dist/manager-CD6LJ7ZN.js +45 -0
  525. package/vendor/framey/dist/manager-WA4F2GST.js +67 -0
  526. package/vendor/framey/dist/media-treatment-BXYS4WVA.js +1030 -0
  527. package/vendor/framey/dist/media-use-LWH3MANK.js +113 -0
  528. package/vendor/framey/dist/models-K363FYM4.js +195 -0
  529. package/vendor/framey/dist/motionShot-GPAVWXLH.js +640 -0
  530. package/vendor/framey/dist/normalize-FASIPBUM.js +24 -0
  531. package/vendor/framey/dist/normalize-audio-VDWYRHN6.js +268 -0
  532. package/vendor/framey/dist/open-E3TB6P6J.js +128 -0
  533. package/vendor/framey/dist/parakeetRunner-UP34UOI2.js +58 -0
  534. package/vendor/framey/dist/pipeline-VXIUYEBU.js +64 -0
  535. package/vendor/framey/dist/play-BUTDQ4DV.js +353 -0
  536. package/vendor/framey/dist/policies-OLDYGFK5.js +309 -0
  537. package/vendor/framey/dist/preflight-2KZ2GWAZ.js +55 -0
  538. package/vendor/framey/dist/present-GXYSM7NX.js +353 -0
  539. package/vendor/framey/dist/preview-EKZ33JOJ.js +1910 -0
  540. package/vendor/framey/dist/producer-SKU5EV3J.js +13 -0
  541. package/vendor/framey/dist/progress-ZWB4Z4ET.js +76 -0
  542. package/vendor/framey/dist/projectConfig-3MZAYVTS.js +60 -0
  543. package/vendor/framey/dist/publication-DTKWNF74.js +33 -0
  544. package/vendor/framey/dist/remove-background-OY5L7XN2.js +265 -0
  545. package/vendor/framey/dist/render-CDV4GDFX.js +187 -0
  546. package/vendor/framey/dist/render-YE5YAMOD.js +2620 -0
  547. package/vendor/framey/dist/render-batch-ZAMFPCLL.js +274 -0
  548. package/vendor/framey/dist/renderSetupWorker.js +120 -0
  549. package/vendor/framey/dist/resolver-D5BIPSEW.js +42 -0
  550. package/vendor/framey/dist/runtimeVersion.js +18 -0
  551. package/vendor/framey/dist/sam-WFZXI4F7.js +23 -0
  552. package/vendor/framey/dist/shaderTransitionWorker.js +44 -0
  553. package/vendor/framey/dist/sherpa-RQWLV7I3.js +79 -0
  554. package/vendor/framey/dist/sherpaWorker.js +84 -0
  555. package/vendor/framey/dist/sites-AMOVABTK.js +54 -0
  556. package/vendor/framey/dist/skill-ZHVLH7KX.js +15 -0
  557. package/vendor/framey/dist/slideshow-SJGK4RQS.js +24 -0
  558. package/vendor/framey/dist/snapshot-TUXL6LBQ.js +1515 -0
  559. package/vendor/framey/dist/src-JHQGB2S6.js +215 -0
  560. package/vendor/framey/dist/src-Z5PGEMXB.js +532 -0
  561. package/vendor/framey/dist/state-B6H3WHCF.js +28 -0
  562. package/vendor/framey/dist/staticProjectServer-DFVZOUGI.js +63 -0
  563. package/vendor/framey/dist/studio/assets/hyperframes-player-DLaKjw0L.js +478 -0
  564. package/vendor/framey/dist/studio/assets/index-BX3KHhGX.js +71 -0
  565. package/vendor/framey/dist/studio/assets/index-CYbvOVp-.css +1 -0
  566. package/vendor/framey/dist/studio/assets/index-Dp3QEUGL.js +402 -0
  567. package/vendor/framey/dist/studio/assets/index-qrTAXbqc.js +531 -0
  568. package/vendor/framey/dist/studio/favicon.svg +14 -0
  569. package/vendor/framey/dist/studio/icons/timeline/audio.svg +7 -0
  570. package/vendor/framey/dist/studio/icons/timeline/captions.svg +5 -0
  571. package/vendor/framey/dist/studio/icons/timeline/composition.svg +12 -0
  572. package/vendor/framey/dist/studio/icons/timeline/image.svg +18 -0
  573. package/vendor/framey/dist/studio/icons/timeline/music.svg +10 -0
  574. package/vendor/framey/dist/studio/icons/timeline/text.svg +3 -0
  575. package/vendor/framey/dist/studio/index.html +23 -0
  576. package/vendor/framey/dist/studio-api-2NECGRMB.js +179 -0
  577. package/vendor/framey/dist/studioSelectionClient-IUUPKUHZ.js +25 -0
  578. package/vendor/framey/dist/studioServer-N2OPUMOQ.js +1569 -0
  579. package/vendor/framey/dist/synthesize-PKTB5ATG.js +183 -0
  580. package/vendor/framey/dist/system-7F3UEHQT.js +27 -0
  581. package/vendor/framey/dist/telemetry-DQGPEKM6.js +145 -0
  582. package/vendor/framey/dist/telemetry-UN55N6U6.js +77 -0
  583. package/vendor/framey/dist/timeline-LHUUMK63.js +1295 -0
  584. package/vendor/framey/dist/tokens-OLECWDFK.js +92 -0
  585. package/vendor/framey/dist/transcribe-O7HQKMIV.js +331 -0
  586. package/vendor/framey/dist/transcribe-UJESPBT5.js +76 -0
  587. package/vendor/framey/dist/tts-YCCQHZD4.js +234 -0
  588. package/vendor/framey/dist/urlDownloader-H2LXLG4U.js +48 -0
  589. package/vendor/framey/dist/usage-HG4WMM7A.js +2167 -0
  590. package/vendor/framey/dist/validate-F2XMN6EV.js +87 -0
  591. package/vendor/framey/dist/vendor/npm/gsap@3.15.0/GSAP-LICENSE.txt +8 -0
  592. package/vendor/framey/dist/vendor/npm/gsap@3.15.0/dist/CustomEase.min.js +11 -0
  593. package/vendor/framey/dist/vendor/npm/gsap@3.15.0/dist/MotionPathPlugin.min.js +11 -0
  594. package/vendor/framey/dist/vendor/npm/gsap@3.15.0/dist/gsap.min.js +11 -0
  595. package/vendor/framey/dist/warmCheck.js +220 -0
  596. package/vendor/framey/dist/warmCheckClient.js +139 -0
  597. package/vendor/framey/dist/workspaceBuildCheck-XYD2YTFW.js +133 -0
  598. package/vendor/framey-player/LICENSE +190 -0
  599. package/vendor/framey-player/NOTICE +16 -0
  600. package/vendor/framey-player/SOURCE.json +6 -0
  601. package/vendor/framey-player/hyperframes-player.global.js +478 -0
  602. package/vendor/framey.pin +1 -0
  603. package/bin/index.js +0 -3
@@ -0,0 +1,1809 @@
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
+ ambiguousIssue,
9
+ loadBrowserScript
10
+ } from "./chunk-FUFP7A7S.js";
11
+ import {
12
+ auditClipDurations,
13
+ shouldIgnoreHttpError,
14
+ shouldIgnoreRequestFailure
15
+ } from "./chunk-WN4XZC5F.js";
16
+ import {
17
+ serveStaticProjectHtml
18
+ } from "./chunk-C5BO7PMT.js";
19
+ import {
20
+ FfmpegUnavailableError,
21
+ STUDIO_PREVIEW_CAPTURE_MODE,
22
+ STUDIO_PREVIEW_MARK_META,
23
+ decideMediaProxyEligibility,
24
+ getProxyCachePath,
25
+ proxyVariantFor,
26
+ resolveProxies,
27
+ scanProjectMediaCodecMap
28
+ } from "./chunk-THJALHFJ.js";
29
+ import {
30
+ artifactDirectory,
31
+ finishSnapshotRun
32
+ } from "./chunk-YPRBGITP.js";
33
+ import {
34
+ AUDIT_SEEK_OPTIONS,
35
+ BrowserCleanupError,
36
+ DEFAULT_ZOOM_PADDING_PX,
37
+ DEFAULT_ZOOM_SCALE,
38
+ DENSE_GEOMETRY_SEEK_OPTIONS,
39
+ SCREENSHOT_SEEK_OPTIONS,
40
+ captureRegionCrop,
41
+ closeManagedBrowser,
42
+ openSettledCompositionPage,
43
+ padCropRegion,
44
+ resolveCliChromeGpuMode,
45
+ seekCompositionTimeline,
46
+ seekInPage,
47
+ waitForPreferredSeekTarget
48
+ } from "./chunk-SZNTYTIV.js";
49
+ import {
50
+ findStageProxyBox
51
+ } from "./chunk-LEKZNRKI.js";
52
+ import {
53
+ resolveAutoProxy
54
+ } from "./chunk-4BNN5FGX.js";
55
+ import {
56
+ injectTagsAtHeadStart
57
+ } from "./chunk-UJZREAV6.js";
58
+ import {
59
+ normalizeErrorMessage
60
+ } from "./chunk-T2EUWCJE.js";
61
+
62
+ // src/utils/checkProgress.ts
63
+ function logCheckProgress(stage, done, total) {
64
+ console.error(`[hyperframes] check: ${stage} ${done}/${total}`);
65
+ }
66
+
67
+ // src/utils/checkMotionBlur.ts
68
+ var OFF_HINTS = {
69
+ "accelerated-canvas": "html-in-canvas captures WebGL/WebGPU frozen, in sub-compositions too: render that effect separately or flatten it out of the page, or drop data-motion-blur on this composition",
70
+ "backface-visibility": "backface-visibility: hidden inside a 3D transform is drawn mirrored; avoid the 3D flip or drop motion blur",
71
+ "iframe-in-root": "move the <iframe>, <object>, <embed> or custom element out of the composition root (each is re-initialised when blur wraps the root), or drop motion blur",
72
+ "root-transform": "animate a child element instead of the composition root, or drop motion blur",
73
+ "root-opacity": "animate a child element instead of the composition root, or drop motion blur",
74
+ "root-blend-mode": "set mix-blend-mode on a child element instead of the composition root, or drop motion blur",
75
+ "nested-capture-canvas": "remove the inner <canvas layoutsubtree> / content=drawable, or drop motion blur"
76
+ };
77
+ var CHOSEN = /* @__PURE__ */ new Set(["translation-only", "tier-attribute"]);
78
+ var GENERIC_OFF_HINT = "remove what the reason names, or drop data-motion-blur";
79
+ var ASKED = 'data-motion-blur="on" is set but';
80
+ function motionBlurDrafts(probe) {
81
+ if (!probe) return [];
82
+ if (probe.reasonCode === "unsupported-browser") {
83
+ return [
84
+ {
85
+ code: "motion_blur_unverified",
86
+ severity: "info",
87
+ message: `${ASKED} the check browser cannot run capture blur, so it was drawn with the filter fallback`,
88
+ fixHint: "the check browser has no html-in-canvas (drawElementImage); render once to see how capture blur looks",
89
+ time: 0
90
+ }
91
+ ];
92
+ }
93
+ if (probe.state === "off") {
94
+ return [
95
+ {
96
+ code: "motion_blur_off",
97
+ severity: "warning",
98
+ message: `${ASKED} blur is off: ${probe.reason ?? "unknown reason"}`,
99
+ fixHint: OFF_HINTS[probe.reasonCode ?? ""] ?? GENERIC_OFF_HINT,
100
+ time: 0
101
+ }
102
+ ];
103
+ }
104
+ if (probe.tier === "filter" && probe.movers > 0 && !CHOSEN.has(probe.reasonCode ?? "")) {
105
+ return [
106
+ {
107
+ code: "motion_blur_filter_fallback",
108
+ severity: "info",
109
+ message: `data-motion-blur="on" is drawn by the filter fallback: ${probe.reason ?? "capture blur cannot run here"}`,
110
+ fixHint: `the fallback smears movement but only softens zoom and rotation; ${OFF_HINTS[probe.reasonCode ?? ""] ?? GENERIC_OFF_HINT}`,
111
+ time: 0
112
+ }
113
+ ];
114
+ }
115
+ if (probe.movers === 0) {
116
+ return [
117
+ {
118
+ code: "motion_blur_no_movers",
119
+ severity: "info",
120
+ message: `${ASKED} nothing in the composition moves fast enough to blur, so it has no effect`,
121
+ fixHint: `animate an element's transform or position by 2+ px per frame; if the motion is set from a timeline callback (onUpdate, render(t)), add data-motion-blur-events="on"; otherwise drop data-motion-blur`,
122
+ time: 0
123
+ }
124
+ ];
125
+ }
126
+ return [];
127
+ }
128
+ function readMotionBlurProbe() {
129
+ const api = Reflect.get(window, "__hfMotionBlur");
130
+ if (typeof api !== "object" || api === null) return null;
131
+ const probe = Reflect.get(api, "probe");
132
+ if (typeof probe !== "function") return null;
133
+ const report = Reflect.apply(probe, api, []);
134
+ if (typeof report !== "object" || report === null) return null;
135
+ const reason = Reflect.get(report, "reason");
136
+ const code = Reflect.get(report, "reasonCode");
137
+ const movers = Reflect.get(report, "movers");
138
+ const tier = Reflect.get(report, "tier");
139
+ const suspend = Reflect.get(api, "suspend");
140
+ if (typeof suspend === "function") Reflect.apply(suspend, api, []);
141
+ return {
142
+ state: Reflect.get(report, "state") === "off" ? "off" : "on",
143
+ tier: tier === "capture" || tier === "filter" ? tier : null,
144
+ reason: typeof reason === "string" ? reason : null,
145
+ reasonCode: typeof code === "string" ? code : null,
146
+ movers: typeof movers === "number" ? movers : 0
147
+ };
148
+ }
149
+ async function collectMotionBlurDrafts(page) {
150
+ const probe = await page.evaluate(readMotionBlurProbe).catch(() => null);
151
+ return motionBlurDrafts(probe);
152
+ }
153
+ function dropMotionBlurConsoleEcho(drafts, found) {
154
+ if (found.length === 0) return drafts;
155
+ return drafts.filter(
156
+ (d) => !(d.code === "console_warning" && d.message.startsWith("[motion-blur] off:"))
157
+ );
158
+ }
159
+
160
+ // src/utils/checkSnapshotDirectory.ts
161
+ import { resolve } from "path";
162
+ var runDirectories = /* @__PURE__ */ new Map();
163
+ var activeChecks = /* @__PURE__ */ new Map();
164
+ function beginCheckSnapshots(projectDir) {
165
+ const project = resolve(projectDir);
166
+ activeChecks.set(project, (activeChecks.get(project) ?? 0) + 1);
167
+ }
168
+ function checkSnapshotDirectory(projectDir) {
169
+ const project = resolve(projectDir);
170
+ let directory = runDirectories.get(project);
171
+ if (!directory) {
172
+ directory = artifactDirectory(project, "snapshots");
173
+ runDirectories.set(project, directory);
174
+ }
175
+ return directory;
176
+ }
177
+ async function finishCheckSnapshots(projectDir) {
178
+ const project = resolve(projectDir);
179
+ const remaining = Math.max(0, (activeChecks.get(project) ?? 1) - 1);
180
+ if (remaining > 0) {
181
+ activeChecks.set(project, remaining);
182
+ return;
183
+ }
184
+ activeChecks.delete(project);
185
+ const path = runDirectories.get(project);
186
+ if (!path) return;
187
+ runDirectories.delete(project);
188
+ await finishSnapshotRun(project, path);
189
+ }
190
+
191
+ // src/utils/checkBrowser.ts
192
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
193
+ import os from "os";
194
+ import { join, resolve as resolve2 } from "path";
195
+
196
+ // src/utils/gsapTweenTails.ts
197
+ var TWEEN_TAIL_WINDOW = 0.25;
198
+ function findTweenTails(records) {
199
+ return records.flatMap(
200
+ (earlier) => records.flatMap((later) => {
201
+ const tail = tailBetween(earlier, later);
202
+ return tail ? [tail] : [];
203
+ })
204
+ );
205
+ }
206
+ function tailBetween(earlier, later) {
207
+ if (later.target !== earlier.target || later.timeline !== earlier.timeline) return null;
208
+ const overlaps = earlier.start < later.start && later.start < earlier.end;
209
+ const tail = earlier.end - later.end;
210
+ if (!overlaps || tail <= 0 || tail > TWEEN_TAIL_WINDOW) return null;
211
+ const properties = earlier.properties.filter((name) => later.properties.includes(name));
212
+ if (properties.length === 0) return null;
213
+ return {
214
+ timeline: earlier.timeline,
215
+ label: earlier.label,
216
+ properties,
217
+ earlier: { start: earlier.start, end: earlier.end },
218
+ later: { start: later.start, end: later.end }
219
+ };
220
+ }
221
+ function tweenTailMessage(tail) {
222
+ const props = tail.properties.join(", ");
223
+ const seconds = (value) => `${value.toFixed(3)} s`;
224
+ return `In timeline "${tail.timeline}", a tween on ${props} of ${tail.label} ends at ${seconds(tail.earlier.end)}, ${(tail.earlier.end - tail.later.end).toFixed(3)} s after a later tween on ${props} ends at ${seconds(tail.later.end)}. For that tail the earlier tween takes ${props} back and leaves its own end value on screen, so the later tween's end never shows. End the earlier tween by ${seconds(tail.later.start)}, or add overwrite: "auto" to the later tween.`;
225
+ }
226
+ function collectTweenRecords() {
227
+ const NOT_PROPERTIES = /* @__PURE__ */ new Set([
228
+ "duration",
229
+ "force3D",
230
+ "autoRound",
231
+ "delay",
232
+ "ease",
233
+ "repeat",
234
+ "repeatDelay",
235
+ "repeatRefresh",
236
+ "yoyo",
237
+ "yoyoEase",
238
+ "stagger",
239
+ "overwrite",
240
+ "immediateRender",
241
+ "lazy",
242
+ "paused",
243
+ "reversed",
244
+ "runBackwards",
245
+ "startAt",
246
+ "keyframes",
247
+ "inherit",
248
+ "data",
249
+ "id",
250
+ "callbackScope",
251
+ "onStart",
252
+ "onStartParams",
253
+ "onUpdate",
254
+ "onUpdateParams",
255
+ "onComplete",
256
+ "onCompleteParams",
257
+ "onRepeat",
258
+ "onRepeatParams",
259
+ "onReverseComplete",
260
+ "onReverseCompleteParams",
261
+ "parent",
262
+ "onInterrupt",
263
+ "autoRevert",
264
+ "smoothChildTiming"
265
+ ]);
266
+ const registered = window.__timelines ?? {};
267
+ const names = /* @__PURE__ */ new Map();
268
+ for (const [name, timeline] of Object.entries(registered)) {
269
+ if (typeof timeline?.getChildren === "function") names.set(timeline, name);
270
+ }
271
+ const ids = /* @__PURE__ */ new Map();
272
+ function nestedInAnother(timeline) {
273
+ for (let parent = timeline.parent; parent; parent = parent.parent) {
274
+ if (names.has(parent)) return true;
275
+ }
276
+ return false;
277
+ }
278
+ function plainProperties(tween) {
279
+ const vars = tween.vars ?? {};
280
+ const plain = !vars.repeat && !vars.yoyo && !vars.keyframes && !vars.overwrite;
281
+ return plain ? Object.keys(vars).filter((key) => !NOT_PROPERTIES.has(key)) : [];
282
+ }
283
+ function labelOf(target) {
284
+ if (!(target instanceof Element)) return "an object";
285
+ if (target.id) return `#${target.id}`;
286
+ return [target.tagName.toLowerCase(), ...target.classList].join(".");
287
+ }
288
+ function recordsOf(timeline, name) {
289
+ const origin = timeline.globalTime(0);
290
+ return (timeline.getChildren?.(true, true, false) ?? []).flatMap((tween) => {
291
+ const duration = tween.totalDuration();
292
+ const properties = plainProperties(tween);
293
+ if (!(duration > 0) || properties.length === 0) return [];
294
+ const start = tween.globalTime(0) - origin;
295
+ const end = tween.globalTime(duration) - origin;
296
+ return tween.targets().map((target) => {
297
+ if (!ids.has(target)) ids.set(target, ids.size);
298
+ const id = ids.get(target) ?? -1;
299
+ return { timeline: name, target: id, label: labelOf(target), properties, start, end };
300
+ });
301
+ });
302
+ }
303
+ return [...names].flatMap(
304
+ ([timeline, name]) => nestedInAnother(timeline) ? [] : recordsOf(timeline, name)
305
+ );
306
+ }
307
+
308
+ // src/utils/checkTypes.ts
309
+ function rectToBbox(rect) {
310
+ return { x: rect.left, y: rect.top, width: rect.width, height: rect.height };
311
+ }
312
+
313
+ // src/utils/checkBrowser.ts
314
+ async function preResolveHostileMediaProxies(projectDir, html, autoProxyOverride) {
315
+ const none = { findings: [], failedPaths: /* @__PURE__ */ new Set(), files: [] };
316
+ if (!resolveAutoProxy(projectDir, autoProxyOverride)) return none;
317
+ let codecMap;
318
+ try {
319
+ codecMap = await scanProjectMediaCodecMap(projectDir, [{ html }]);
320
+ } catch (err) {
321
+ console.error(
322
+ `[hyperframes] media proxy pre-resolve: scan failed (${normalizeErrorMessage(err)})`
323
+ );
324
+ return none;
325
+ }
326
+ const hostileEntries = Object.entries(codecMap).filter(
327
+ ([, facts]) => decideMediaProxyEligibility(facts).eligible
328
+ );
329
+ if (hostileEntries.length === 0) return none;
330
+ const startedAt = Date.now();
331
+ const stageBox = findStageProxyBox(html);
332
+ const sources = hostileEntries.map(([pathname, facts]) => {
333
+ const file = pathname.replace(/^\/+/, "");
334
+ return {
335
+ pathname,
336
+ file,
337
+ sourcePath: resolve2(projectDir, file),
338
+ variant: proxyVariantFor(facts),
339
+ box: stageBox
340
+ };
341
+ });
342
+ const total = hostileEntries.length;
343
+ const cached = sources.map((source) => proxyCached(projectDir, source));
344
+ const toMake = cached.filter((isCached) => !isCached).length;
345
+ if (toMake > 0) {
346
+ console.error(
347
+ `[hyperframes] Making browser-playable copies of ${toMake} video${toMake === 1 ? "" : "s"} Chrome cannot decode. Only the first check of these files waits for this; later checks reuse the copies.`
348
+ );
349
+ }
350
+ let settled = 0;
351
+ const results = await resolveProxies(projectDir, sources, () => {
352
+ settled += 1;
353
+ if (toMake > 0) console.error(`[hyperframes] browser-playable copies: ${settled}/${total}`);
354
+ });
355
+ const failures = sources.flatMap((source, index) => {
356
+ const result = results[index];
357
+ return result.status === "rejected" ? [{ ...source, reason: result.reason }] : [];
358
+ });
359
+ console.error(
360
+ `[hyperframes] media proxy pre-resolve: ${total - failures.length}/${total} ready, ${failures.length} failed (${Date.now() - startedAt}ms)`
361
+ );
362
+ const unusableFfmpeg = failures.filter(({ reason }) => reason instanceof FfmpegUnavailableError);
363
+ const findings = failures.filter(({ reason }) => !(reason instanceof FfmpegUnavailableError)).map(
364
+ ({ file, reason }) => proxyFailedDraft(
365
+ `Could not make a browser-playable copy of ${file}: ${normalizeErrorMessage(reason)}. A default render decodes the original with ffmpeg and does not need it, but publish stops on it (unless run with --no-proxy) and a browser that cannot decode the original will not play it in preview.`
366
+ )
367
+ );
368
+ if (unusableFfmpeg[0]) {
369
+ findings.unshift(
370
+ proxyFailedDraft(
371
+ `Could not make browser-playable copies of ${unusableFfmpeg.map(({ file }) => file).join(", ")}: ${normalizeErrorMessage(unusableFfmpeg[0].reason)}. Publish stops on them (unless run with --no-proxy) and a browser that cannot decode them will not play them in preview.`
372
+ )
373
+ );
374
+ }
375
+ const files = sources.map(({ file }, index) => {
376
+ const result = results[index];
377
+ if (result.status === "rejected") {
378
+ return { file, state: "failed", reason: normalizeErrorMessage(result.reason) };
379
+ }
380
+ return { file, state: cached[index] ? "cached" : "ready" };
381
+ });
382
+ return { findings, failedPaths: new Set(failures.map(({ pathname }) => pathname)), files };
383
+ }
384
+ function proxyCached(projectDir, source) {
385
+ try {
386
+ return existsSync(getProxyCachePath(projectDir, source.sourcePath, source.variant, source.box));
387
+ } catch {
388
+ return false;
389
+ }
390
+ }
391
+ function proxyFailedDraft(message) {
392
+ return { code: "media_proxy_failed", severity: "warning", message, time: 0 };
393
+ }
394
+ async function loadCheckHtml(dir) {
395
+ const { bundleWithLocalizedFonts } = await import("./bundleWithLocalizedFonts-ALYBQEQT.js");
396
+ return injectTagsAtHeadStart(
397
+ await bundleWithLocalizedFonts(dir),
398
+ `<meta name="${STUDIO_PREVIEW_MARK_META}" content="${STUDIO_PREVIEW_CAPTURE_MODE}">`
399
+ );
400
+ }
401
+ async function runBrowserCheck(project, options, motion, runGrid, deadline, prelaunched) {
402
+ const html = await loadCheckHtml(project.dir);
403
+ deadline?.enter("copies");
404
+ const { findings: drafts, failedPaths } = await preResolveHostileMediaProxies(
405
+ project.dir,
406
+ html,
407
+ options.autoProxy
408
+ );
409
+ deadline?.enter("launch");
410
+ const server = await serveStaticProjectHtml(
411
+ project.dir,
412
+ html,
413
+ "Failed to bind check server",
414
+ [],
415
+ options.autoProxy
416
+ );
417
+ const clock = createRuntimeClock();
418
+ let failure = { kind: "none" };
419
+ let chromeBrowser;
420
+ const helperSession = samplingBrowserCount(options) > 1 ? startHelperSession(html, server.url, options, deadline) : void 0;
421
+ const helperOpen = helperSession?.opened;
422
+ const helpers = helperOpen?.then(
423
+ (helper) => [helper.driver],
424
+ () => []
425
+ );
426
+ try {
427
+ const launchSettleStart = Date.now();
428
+ const session = await openSettledCompositionPage(html, server.url, {
429
+ navigationTimeoutMs: options.timeout,
430
+ renderReadyTimeoutMs: options.timeout,
431
+ renderReadyWarningSuffix: "checking the current page state",
432
+ prelaunched,
433
+ browserGpuMode: options.browserGpuMode ?? resolveCliChromeGpuMode(),
434
+ signal: deadline?.signal,
435
+ onBrowser: deadline?.ownBrowser,
436
+ onBrowserReady: deadline?.start,
437
+ beforeNavigate: async (page2) => {
438
+ wireRuntimeListeners(page2, drafts, clock);
439
+ await deadline?.preparePage(page2);
440
+ },
441
+ onLoaded: () => deadline?.enter("settle")
442
+ });
443
+ chromeBrowser = session.browser;
444
+ const page = session.page;
445
+ await waitForPreferredSeekTarget(page);
446
+ const rootAnchor = await resolveRootAnchor(page);
447
+ deadline?.keepPartial(() => ({
448
+ runtimeFindings: dropFailedProxyEchoes(
449
+ keepBrokenImageAborts(drafts, /* @__PURE__ */ new Set()),
450
+ failedPaths
451
+ ).map((draft) => runtimeFinding(draft, rootAnchor))
452
+ }));
453
+ const launchSettleMs = Date.now() - launchSettleStart;
454
+ const { analyzeClipMediaFit } = await import("./src-Z5PGEMXB.js");
455
+ for (const entry of await auditClipDurations(page, analyzeClipMediaFit, options.timeout)) {
456
+ drafts.push({ code: "clip_media_fit", severity: entry.level, message: entry.text, time: 0 });
457
+ }
458
+ for (const tail of findTweenTails(await page.evaluate(collectTweenRecords) ?? [])) {
459
+ const message = tweenTailMessage(tail);
460
+ drafts.push({ code: "gsap_tween_tail", severity: "warning", message, time: tail.later.end });
461
+ }
462
+ const blur = await collectMotionBlurDrafts(page);
463
+ drafts.push(...blur);
464
+ const sampleLog = sampleWindow(drafts);
465
+ const driver = createPageDriver(page, clock, sampleLog);
466
+ const result = await runGrid(
467
+ driver,
468
+ options,
469
+ motion,
470
+ helpers,
471
+ deadline?.enter,
472
+ logCheckProgress,
473
+ deadline?.keepPartial
474
+ );
475
+ helperSession?.stop();
476
+ const helper = await helperOpen?.catch(() => void 0);
477
+ const merged = helper ? mergeHelperDrafts(sampleLog, helper.sampleLog) : drafts;
478
+ const broken = await abortedImagesStillBroken(page, merged);
479
+ return {
480
+ ...result,
481
+ timings: { ...result.timings, launchSettleMs },
482
+ runtimeFindings: dropFailedProxyEchoes(
483
+ dropMotionBlurConsoleEcho(keepBrokenImageAborts(merged, broken), blur),
484
+ failedPaths
485
+ ).map((draft) => runtimeFinding(draft, rootAnchor))
486
+ };
487
+ } catch (error) {
488
+ failure = { kind: "failed", error };
489
+ throw error;
490
+ } finally {
491
+ helperSession?.stop();
492
+ await helperOpen?.catch(() => void 0);
493
+ await closeCheckResources([chromeBrowser, helperSession?.browser()], server, failure);
494
+ }
495
+ }
496
+ function createRuntimeClock() {
497
+ let stamp = { time: 0 };
498
+ return {
499
+ now: () => stamp,
500
+ at: (time) => {
501
+ stamp = { time };
502
+ },
503
+ during: (range) => {
504
+ stamp = { time: range[0], timeRange: range };
505
+ }
506
+ };
507
+ }
508
+ var SAMPLING_BROWSER_BYTES = 250 * 1024 * 1024;
509
+ function samplingBrowserCount(options, cores = os.availableParallelism(), free = Math.min(os.freemem(), process.availableMemory())) {
510
+ if (options.at?.length === 1) return 1;
511
+ return Math.max(1, Math.min(2, cores - 1, Math.floor(free / SAMPLING_BROWSER_BYTES)));
512
+ }
513
+ function sampleWindow(drafts) {
514
+ return { drafts, start: Number.POSITIVE_INFINITY, end: Number.POSITIVE_INFINITY };
515
+ }
516
+ function startHelperSession(html, url, options, deadline) {
517
+ const abort = new AbortController();
518
+ let browser;
519
+ const opened = openHelperSession(html, url, options, deadline, {
520
+ signal: deadline ? AbortSignal.any([deadline.signal, abort.signal]) : abort.signal,
521
+ onBrowser: (launched) => {
522
+ browser = launched;
523
+ deadline?.ownBrowser(launched);
524
+ }
525
+ });
526
+ return {
527
+ opened,
528
+ browser: () => browser,
529
+ stop: () => {
530
+ abort.abort();
531
+ if (browser) void closeManagedBrowser(browser).catch(() => void 0);
532
+ }
533
+ };
534
+ }
535
+ async function openHelperSession(html, url, options, deadline, owner) {
536
+ const sampleLog = sampleWindow([]);
537
+ const clock = createRuntimeClock();
538
+ const session = await openSettledCompositionPage(html, url, {
539
+ navigationTimeoutMs: options.timeout,
540
+ renderReadyTimeoutMs: options.timeout,
541
+ renderReadyWarningSuffix: "checking the current page state",
542
+ browserGpuMode: options.browserGpuMode ?? resolveCliChromeGpuMode(),
543
+ signal: owner.signal,
544
+ onBrowser: owner.onBrowser,
545
+ beforeNavigate: async (page) => {
546
+ wireRuntimeListeners(page, sampleLog.drafts, clock);
547
+ await deadline?.preparePage(page);
548
+ }
549
+ });
550
+ await waitForPreferredSeekTarget(session.page);
551
+ return {
552
+ driver: createPageDriver(session.page, clock, sampleLog),
553
+ sampleLog
554
+ };
555
+ }
556
+ var draftKey = (draft) => `${draft.code} ${draft.time} ${draft.message}`;
557
+ function mergeHelperDrafts(primary, helper) {
558
+ const window2 = ({ drafts, start: start2, end }) => drafts.slice(Math.min(start2, drafts.length), Math.min(end, drafts.length));
559
+ const own = window2(primary);
560
+ const seen = new Set(own.map(draftKey));
561
+ const extra = window2(helper).filter((draft) => !seen.has(draftKey(draft)));
562
+ const start = Math.min(primary.start, primary.drafts.length);
563
+ return [
564
+ ...primary.drafts.slice(0, start),
565
+ ...[...own, ...extra].sort((a, b) => a.time - b.time),
566
+ ...primary.drafts.slice(start + own.length)
567
+ ];
568
+ }
569
+ async function captureFindingCrops(project, options, requests, deadline) {
570
+ if (requests.length === 0) return [];
571
+ const html = await loadCheckHtml(project.dir);
572
+ const server = await serveStaticProjectHtml(
573
+ project.dir,
574
+ html,
575
+ "Failed to bind check server",
576
+ [],
577
+ options.autoProxy
578
+ );
579
+ let chromeBrowser;
580
+ const written = [];
581
+ let failure = { kind: "none" };
582
+ try {
583
+ const session = await openSettledCompositionPage(html, server.url, {
584
+ navigationTimeoutMs: options.timeout,
585
+ renderReadyTimeoutMs: options.timeout,
586
+ renderReadyWarningSuffix: "capturing finding crops",
587
+ signal: deadline?.signal,
588
+ onBrowser: deadline?.ownBrowser,
589
+ onBrowserReady: deadline?.start,
590
+ beforeNavigate: (page2) => deadline?.preparePage(page2),
591
+ browserGpuMode: options.browserGpuMode ?? resolveCliChromeGpuMode()
592
+ });
593
+ chromeBrowser = session.browser;
594
+ const page = session.page;
595
+ await waitForPreferredSeekTarget(page);
596
+ const snapshotDir = checkSnapshotDirectory(project.dir);
597
+ mkdirSync(snapshotDir, { recursive: true });
598
+ for (const request of requests) {
599
+ await seekCompositionTimeline(page, request.time, SCREENSHOT_SEEK_OPTIONS);
600
+ const canvas = await page.evaluate(() => ({
601
+ width: window.innerWidth,
602
+ height: window.innerHeight
603
+ }));
604
+ const region = padCropRegion(request.bbox, canvas, DEFAULT_ZOOM_PADDING_PX);
605
+ const buffer = await captureRegionCrop(page, region, DEFAULT_ZOOM_SCALE);
606
+ writeFileSync(join(snapshotDir, request.filename), buffer);
607
+ written.push(join(snapshotDir, request.filename));
608
+ }
609
+ return written;
610
+ } catch (error) {
611
+ failure = { kind: "failed", error };
612
+ throw error;
613
+ } finally {
614
+ await closeCheckResources([chromeBrowser], server, failure);
615
+ }
616
+ }
617
+ async function closeCheckResources(browsers, server, failure) {
618
+ const cleanup = await Promise.allSettled([
619
+ ...browsers.map((browser) => browser ? closeManagedBrowser(browser) : Promise.resolve()),
620
+ server.close()
621
+ ]);
622
+ const errors = cleanup.filter((entry) => entry.status === "rejected").map((entry) => entry.reason);
623
+ if (errors.length === 0) return;
624
+ if (failure.kind === "failed") errors.unshift(failure.error);
625
+ throw new BrowserCleanupError(errors, errors.map(normalizeErrorMessage).join("; "));
626
+ }
627
+ var MEDIA_PROXY_MARKER_PREFIX = "[hyperframes] runtime_media_proxy_";
628
+ var MEDIA_PROXY_UNAVAILABLE_MARKER = "[hyperframes] runtime_media_proxy_unavailable";
629
+ var WEB_AUDIO_BYPASS_MARKER = "[hyperframes] runtime_web_audio_bypass";
630
+ var WEBGPU_RUNTIME_FAILURE = /\b(?:GPUValidationError|GPUOutOfMemoryError|GPUInternalError)\b|WebGPU uncaptured error|(?:destroyed\b.*\b(?:GPU )?(?:resource|buffer|texture)\b.*\bsubmit)|(?:(?:GPU )?(?:resource|buffer|texture)\b.*\bdestroyed\b.*\bsubmit)/i;
631
+ function isWebGpuRuntimeFailure(text) {
632
+ return WEBGPU_RUNTIME_FAILURE.test(text);
633
+ }
634
+ function pushRuntimeDraft(drafts, draft) {
635
+ if (draft.code !== "webgpu_runtime_error") {
636
+ drafts.push(draft);
637
+ return;
638
+ }
639
+ const duplicate = drafts.find(
640
+ (entry) => entry.code === draft.code && entry.message === draft.message && entry.url === draft.url && entry.line === draft.line
641
+ );
642
+ if (duplicate) {
643
+ duplicate.count = (duplicate.count ?? 1) + 1;
644
+ return;
645
+ }
646
+ drafts.push({ ...draft, count: 1 });
647
+ }
648
+ function runtimeInfoFindingCode(text) {
649
+ if (text.startsWith(WEB_AUDIO_BYPASS_MARKER)) return "web_audio_bypass";
650
+ if (!text.startsWith(MEDIA_PROXY_MARKER_PREFIX)) return null;
651
+ return text.includes(MEDIA_PROXY_UNAVAILABLE_MARKER) ? "media_proxy_unavailable" : "media_proxy_fallback";
652
+ }
653
+ function wireRuntimeListeners(page, drafts, clock) {
654
+ followSampleTimeMarkers(page, clock.at);
655
+ page.on("console", (message) => {
656
+ const type = message.type();
657
+ const text = message.text();
658
+ if (type === "error" && !text.startsWith("Failed to load resource")) {
659
+ const location = message.location();
660
+ pushRuntimeDraft(drafts, {
661
+ code: "console_error",
662
+ severity: "error",
663
+ message: text,
664
+ ...clock.now(),
665
+ url: location.url,
666
+ line: location.lineNumber
667
+ });
668
+ } else if (type === "warn") {
669
+ const location = message.location();
670
+ const webGpuFailure = isWebGpuRuntimeFailure(text);
671
+ pushRuntimeDraft(drafts, {
672
+ code: webGpuFailure ? "webgpu_runtime_error" : "console_warning",
673
+ severity: webGpuFailure ? "error" : "warning",
674
+ message: text,
675
+ ...clock.now(),
676
+ url: location.url,
677
+ line: location.lineNumber
678
+ });
679
+ } else if (type === "info") {
680
+ const code = runtimeInfoFindingCode(text);
681
+ if (!code) return;
682
+ const location = message.location();
683
+ pushRuntimeDraft(drafts, {
684
+ code,
685
+ severity: "info",
686
+ message: text,
687
+ ...clock.now(),
688
+ url: location.url,
689
+ line: location.lineNumber
690
+ });
691
+ }
692
+ });
693
+ page.on("pageerror", (error) => {
694
+ const message = normalizeErrorMessage(error);
695
+ if (message.includes("Unexpected token '<'") || message.includes("Unexpected token '&lt;'")) {
696
+ return;
697
+ }
698
+ pushRuntimeDraft(drafts, {
699
+ code: "page_error",
700
+ severity: "error",
701
+ message,
702
+ ...clock.now()
703
+ });
704
+ });
705
+ wireNetworkListeners(page, drafts, clock);
706
+ }
707
+ function keepBrokenImageAborts(drafts, broken) {
708
+ return drafts.filter((draft) => !draft.abortedImage || broken.has(draft.url ?? ""));
709
+ }
710
+ function dropFailedProxyEchoes(drafts, failedPaths) {
711
+ if (failedPaths.size === 0) return drafts;
712
+ return drafts.filter((draft) => !failedPaths.has(proxyEchoPath(draft) ?? ""));
713
+ }
714
+ function proxyEchoPath(draft) {
715
+ if (draft.code === "http_error" || draft.code === "request_failed") {
716
+ const url = parseUrl(draft.url);
717
+ return url?.searchParams.has("hf-proxy") ? decodedPath(url) : void 0;
718
+ }
719
+ if (draft.code === "media_proxy_fallback" || draft.code === "media_proxy_unavailable") {
720
+ return decodedPath(parseUrl(/"([^"]+)"/.exec(draft.message)?.[1]));
721
+ }
722
+ return void 0;
723
+ }
724
+ function parseUrl(target) {
725
+ if (!target) return void 0;
726
+ try {
727
+ return new URL(target, "http://check.invalid/");
728
+ } catch {
729
+ return void 0;
730
+ }
731
+ }
732
+ function decodedPath(url) {
733
+ if (!url) return void 0;
734
+ try {
735
+ return decodeURIComponent(url.pathname);
736
+ } catch {
737
+ return void 0;
738
+ }
739
+ }
740
+ var IMAGE_DECODE_CAP_MS = 5e3;
741
+ async function abortedImagesStillBroken(page, drafts) {
742
+ const urls = drafts.filter((draft) => draft.abortedImage).map((draft) => draft.url ?? "");
743
+ if (urls.length === 0) return /* @__PURE__ */ new Set();
744
+ const broken = await page.evaluate(
745
+ async (candidates, capMs) => {
746
+ const fails = (img) => new Promise((resolve3) => {
747
+ const cap = setTimeout(() => resolve3(false), capMs);
748
+ img.decode().then(
749
+ () => resolve3(false),
750
+ () => resolve3(true)
751
+ ).finally(() => clearTimeout(cap));
752
+ });
753
+ const stillBroken = await Promise.all(
754
+ candidates.map(async (url) => {
755
+ const shown = Array.from(document.querySelectorAll("img")).filter(
756
+ (img) => img.currentSrc === url || img.src === url
757
+ );
758
+ return (await Promise.all(shown.map(fails))).some(Boolean);
759
+ })
760
+ );
761
+ return candidates.filter((_, i) => stillBroken[i]);
762
+ },
763
+ urls,
764
+ IMAGE_DECODE_CAP_MS
765
+ );
766
+ return new Set(broken);
767
+ }
768
+ function wireNetworkListeners(page, drafts, clock) {
769
+ page.on("requestfailed", (request) => {
770
+ const url = request.url();
771
+ if (url.includes("favicon") || url.startsWith("data:")) return;
772
+ const failure = request.failure()?.errorText;
773
+ if (shouldIgnoreRequestFailure(url, failure, request.resourceType())) return;
774
+ drafts.push({
775
+ code: "request_failed",
776
+ severity: "error",
777
+ message: `Failed to load ${urlPath(url)}: ${failure ?? "net::ERR_FAILED"}`,
778
+ ...clock.now(),
779
+ url,
780
+ abortedImage: failure === "net::ERR_ABORTED" && request.resourceType() === "image"
781
+ });
782
+ });
783
+ page.on("response", (response) => {
784
+ if (response.status() < 400) return;
785
+ const url = response.url();
786
+ if (url.includes("favicon")) return;
787
+ if (shouldIgnoreHttpError(url, response.status())) return;
788
+ drafts.push({
789
+ code: "http_error",
790
+ severity: "error",
791
+ message: `${response.status()} loading ${urlPath(url)}`,
792
+ ...clock.now(),
793
+ url
794
+ });
795
+ });
796
+ }
797
+ function failWhenPageDies(page, driver) {
798
+ const dead = new Promise((_, reject) => {
799
+ page.on(
800
+ "error",
801
+ (error) => reject(new Error(`The page crashed: ${normalizeErrorMessage(error)}`))
802
+ );
803
+ page.on("close", () => reject(new Error("The page closed before the check finished")));
804
+ });
805
+ dead.catch(() => void 0);
806
+ return Object.fromEntries(
807
+ Object.entries(driver).map(([name, member]) => [
808
+ name,
809
+ typeof member === "function" ? (...args) => {
810
+ const result = Reflect.apply(member, driver, args);
811
+ return result instanceof Promise ? Promise.race([result, dead]) : result;
812
+ } : member
813
+ ])
814
+ );
815
+ }
816
+ function createPageDriver(page, clock = createRuntimeClock(), sampleLog) {
817
+ return failWhenPageDies(page, {
818
+ initialize: (contrast) => injectAuditScripts(page, contrast),
819
+ markSamples: (phase) => {
820
+ if (!sampleLog) return;
821
+ if (phase === "drop") sampleLog.start = sampleLog.end = Number.POSITIVE_INFINITY;
822
+ else sampleLog[phase] = sampleLog.drafts.length;
823
+ },
824
+ matchComponents: (components, findings) => page.evaluate(matchComponentFindings, { components, findings }),
825
+ getDuration: () => getCompositionDuration(page),
826
+ hasNoTimelineDeclaration: () => hasNoTimelineDeclaration(page),
827
+ getTransitionBoundaries: () => collectTweenBoundaries(page),
828
+ getClipEdges: () => collectClipEdges(page),
829
+ getCanvas: () => page.evaluate(() => ({ width: window.innerWidth, height: window.innerHeight })),
830
+ findAmbiguousSelectors: (selectors) => findAmbiguousSelectors(page, selectors),
831
+ seek: async (time, screenshotFollows) => {
832
+ clock.at(time);
833
+ await seekCompositionTimeline(
834
+ page,
835
+ time,
836
+ screenshotFollows ? SCREENSHOT_SEEK_OPTIONS : AUDIT_SEEK_OPTIONS
837
+ );
838
+ },
839
+ seekGeometry: async (time) => {
840
+ clock.at(time);
841
+ await seekCompositionTimeline(page, time, DENSE_GEOMETRY_SEEK_OPTIONS);
842
+ },
843
+ collectLayout: (time, tolerance, layout) => collectLayout(page, time, tolerance, layout),
844
+ collectOverlap: (time) => collectOverlap(page, time),
845
+ collectOverlapGrid: async (times) => {
846
+ const issues = await collectOverlapGrid(page, times);
847
+ if (times.length > 0) clock.during([times[0] ?? 0, times.at(-1) ?? 0]);
848
+ return issues;
849
+ },
850
+ collectLayoutGeometry: () => collectLayoutGeometry(page),
851
+ captureFrame: (scope) => captureFrame(page, scope),
852
+ framesDiffer: (first, second) => page.evaluate(
853
+ (a, b) => Reflect.apply(Reflect.get(window, "__hyperframesFramesDiffer"), window, [a, b]),
854
+ first,
855
+ second
856
+ ).then((differ) => differ === true),
857
+ collectSeekClock: () => collectSeekClock(page),
858
+ collectRotationSample: (time) => collectRotationSample(page, time),
859
+ collectOffPivotRotationSample: (time) => collectOffPivotRotationSample(page, time),
860
+ collectGeometryCandidates: (time, request) => collectGeometryCandidates(page, time, request),
861
+ collectMotionFrame: (time, selectors, scopes) => collectMotionFrame(page, time, selectors, scopes),
862
+ anchorMotionIssues: (issues) => anchorLayoutIssues(page, issues),
863
+ collectContrast: (time, annotations) => collectContrast(page, time, annotations),
864
+ collectCraftFrame: (time) => collectCraftFrame(page, time),
865
+ collectCraftFilm: () => collectCraftFilm(page)
866
+ });
867
+ }
868
+ async function collectCraftFrame(page, time) {
869
+ const raw = await page.evaluate(() => {
870
+ const sample = Reflect.get(window, "__hyperframesCraftSample");
871
+ return typeof sample === "function" ? Reflect.apply(sample, window, []) : null;
872
+ });
873
+ const record = isRecord(raw) ? raw : {};
874
+ const parts = Reflect.get(record, "parts");
875
+ return {
876
+ time,
877
+ parts: Array.isArray(parts) ? parts.flatMap(parseCraftTextPart) : [],
878
+ held: booleanValue(record, "held") ?? false,
879
+ painted: booleanValue(record, "painted") ?? true,
880
+ signature: stringValue(record, "signature") ?? ""
881
+ };
882
+ }
883
+ async function collectCraftFilm(page) {
884
+ const raw = await page.evaluate(() => {
885
+ const film = Reflect.get(window, "__hyperframesCraftFilm");
886
+ return typeof film === "function" ? Reflect.apply(film, window, []) : null;
887
+ });
888
+ return { soundSources: (isRecord(raw) ? numberValue(raw, "soundSources") : null) ?? 0 };
889
+ }
890
+ var CRAFT_PART_NUMBERS = ["key", "block", "opacity", "fontPx"];
891
+ var CRAFT_PART_STRINGS = ["selector", "blockSelector", "sourceFile", "text"];
892
+ var CRAFT_RECT_NUMBERS = ["left", "top", "width", "height"];
893
+ function parseCraftTextPart(value) {
894
+ if (!isRecord(value)) return [];
895
+ const nums = requiredNumbers(value, CRAFT_PART_NUMBERS);
896
+ const strings = requiredStrings(value, CRAFT_PART_STRINGS);
897
+ const rect = recordField(value, "rect");
898
+ const box = rect ? requiredNumbers(rect, CRAFT_RECT_NUMBERS) : null;
899
+ const captions = booleanValue(value, "captions");
900
+ return nums && strings && box && captions !== null ? [{ ...nums, ...strings, rect: box, captions }] : [];
901
+ }
902
+ function requiredStrings(value, keys) {
903
+ const out = {};
904
+ for (const key of keys) {
905
+ const entry = stringValue(value, key);
906
+ if (entry === null) return null;
907
+ out[key] = entry;
908
+ }
909
+ return out;
910
+ }
911
+ async function hasNoTimelineDeclaration(page) {
912
+ return page.evaluate(
913
+ () => document.querySelector("[data-composition-id]")?.hasAttribute("data-no-timeline") ?? false
914
+ );
915
+ }
916
+ async function injectAuditScripts(page, contrast) {
917
+ await page.addScriptTag({ content: loadBrowserScript("motion-signature.browser.js") });
918
+ await page.addScriptTag({ content: loadBrowserScript("layout-audit.browser.js") });
919
+ await page.addScriptTag({ content: loadBrowserScript("motion-sample.browser.js") });
920
+ if (contrast) {
921
+ await page.addScriptTag({ content: loadBrowserScript("contrast-audit.browser.js") });
922
+ }
923
+ }
924
+ async function getCompositionDuration(page) {
925
+ return page.evaluate(() => {
926
+ const value = (target, key) => typeof target === "object" && target !== null ? Reflect.get(target, key) : void 0;
927
+ const positive = (candidate) => typeof candidate === "number" && candidate > 0 ? candidate : null;
928
+ const callDuration = (target) => {
929
+ const duration = value(target, "duration");
930
+ if (typeof duration === "function") {
931
+ const result = Reflect.apply(duration, target, []);
932
+ return positive(result);
933
+ }
934
+ return positive(duration);
935
+ };
936
+ const hfDuration = positive(value(Reflect.get(window, "__hf"), "duration"));
937
+ if (hfDuration) return hfDuration;
938
+ const playerDuration = callDuration(Reflect.get(window, "__player"));
939
+ if (playerDuration) return playerDuration;
940
+ const root = document.querySelector("[data-composition-id][data-duration]");
941
+ const authored = root ? parseFloat(root.getAttribute("data-duration") ?? "0") : 0;
942
+ if (authored > 0) return authored;
943
+ const timelines = Reflect.get(window, "__timelines");
944
+ if (typeof timelines !== "object" || timelines === null) return 0;
945
+ for (const key of Object.keys(timelines)) {
946
+ const duration = callDuration(Reflect.get(timelines, key));
947
+ if (duration) return duration;
948
+ }
949
+ return 0;
950
+ });
951
+ }
952
+ async function collectClipEdges(page) {
953
+ return page.evaluate(() => {
954
+ const manifest = Reflect.get(window, "__clipManifest");
955
+ return (manifest?.clips ?? []).filter((clip) => clip.kind !== "audio").flatMap((clip) => [clip.start, clip.start + clip.duration]);
956
+ });
957
+ }
958
+ async function collectTweenBoundaries(page) {
959
+ return page.evaluate(() => {
960
+ const property = (target, key) => typeof target === "object" && target !== null || typeof target === "function" ? Reflect.get(target, key) : void 0;
961
+ const numberCall = (target, key, fallback) => {
962
+ const method = property(target, key);
963
+ if (typeof method !== "function") return fallback;
964
+ const result = Reflect.apply(method, target, []);
965
+ return typeof result === "number" ? result : fallback;
966
+ };
967
+ const rootTime = (root, animation, local) => {
968
+ let time = local;
969
+ let node = animation;
970
+ while (node && node !== root) {
971
+ time = numberCall(node, "startTime", 0) + time / (numberCall(node, "timeScale", 1) || 1);
972
+ node = property(node, "parent");
973
+ }
974
+ return time;
975
+ };
976
+ const timelines = Reflect.get(window, "__timelines");
977
+ if (typeof timelines !== "object" || timelines === null) return [];
978
+ const boundaries = [];
979
+ for (const key of Object.keys(timelines)) {
980
+ const timeline = Reflect.get(timelines, key);
981
+ const getChildren = property(timeline, "getChildren");
982
+ if (typeof getChildren !== "function") continue;
983
+ try {
984
+ const children = Reflect.apply(getChildren, timeline, [true, true, false]);
985
+ if (!Array.isArray(children)) continue;
986
+ for (const child of children) {
987
+ const duration = numberCall(child, "duration", Number.NaN);
988
+ if (!Number.isFinite(duration)) continue;
989
+ boundaries.push(rootTime(timeline, child, 0), rootTime(timeline, child, duration));
990
+ }
991
+ } catch {
992
+ continue;
993
+ }
994
+ }
995
+ return boundaries.filter(Number.isFinite);
996
+ });
997
+ }
998
+ async function collectLayout(page, time, tolerance, layout) {
999
+ const raw = await page.evaluate(
1000
+ (options) => {
1001
+ const audit = Reflect.get(window, "__hyperframesLayoutAudit");
1002
+ if (typeof audit !== "function") return [];
1003
+ const result = Reflect.apply(audit, window, [options]);
1004
+ return Array.isArray(result) ? result : [];
1005
+ },
1006
+ {
1007
+ time,
1008
+ tolerance,
1009
+ ...typeof layout?.proseCoverageFloor === "number" ? { proseCoverageFloor: layout.proseCoverageFloor } : {}
1010
+ }
1011
+ );
1012
+ return anchorLayoutIssues(page, raw.flatMap(parseLayoutIssue));
1013
+ }
1014
+ async function collectOverlap(page, time) {
1015
+ const raw = await page.evaluate(
1016
+ (options) => {
1017
+ const audit = Reflect.get(window, "__hyperframesOverlapAudit");
1018
+ if (typeof audit !== "function") return [];
1019
+ const result = Reflect.apply(audit, window, [options]);
1020
+ return Array.isArray(result) ? result : [];
1021
+ },
1022
+ { time }
1023
+ );
1024
+ return anchorLayoutIssues(page, raw.flatMap(parseLayoutIssue));
1025
+ }
1026
+ var SAMPLE_TIME_MARKER = "__hfCheckSample ";
1027
+ function followSampleTimeMarkers(page, setTime) {
1028
+ page.on("console", (message) => {
1029
+ const text = message.text();
1030
+ if (message.type() === "debug" && text.startsWith(SAMPLE_TIME_MARKER)) {
1031
+ setTime(Number(text.slice(SAMPLE_TIME_MARKER.length)));
1032
+ }
1033
+ });
1034
+ }
1035
+ async function overlapGridInPage(grid, seek, anchors) {
1036
+ const audit = Reflect.get(window, "__hyperframesOverlapAudit");
1037
+ const waitForCompletion = Reflect.get(window, "__hfWaitForSeekCompletion");
1038
+ const samples = [];
1039
+ for (const time of grid.times) {
1040
+ console.debug(`${grid.marker}${time}`);
1041
+ seek(time, grid.fallback, false, grid.skipDraws);
1042
+ if (typeof waitForCompletion === "function") {
1043
+ await Reflect.apply(waitForCompletion, window, [{ videoFrames: grid.videoFrames }]);
1044
+ }
1045
+ const result = typeof audit === "function" ? Reflect.apply(audit, window, [{ time }]) : [];
1046
+ const raw = Array.isArray(result) ? result : [];
1047
+ const zero = { x: 0, y: 0, width: 0, height: 0 };
1048
+ const requests = raw.map((issue) => ({
1049
+ selector: String(Reflect.get(Object(issue), "selector")),
1050
+ time,
1051
+ bbox: zero
1052
+ }));
1053
+ samples.push({ raw, anchors: anchors(requests) });
1054
+ }
1055
+ return samples;
1056
+ }
1057
+ async function collectOverlapGrid(page, times) {
1058
+ if (times.length === 0) return [];
1059
+ const grid = {
1060
+ times,
1061
+ marker: SAMPLE_TIME_MARKER,
1062
+ fallback: DENSE_GEOMETRY_SEEK_OPTIONS.fallbackToBridgeAndTimelines,
1063
+ skipDraws: DENSE_GEOMETRY_SEEK_OPTIONS.skipWebglDraws,
1064
+ videoFrames: DENSE_GEOMETRY_SEEK_OPTIONS.waitForVideoFrames
1065
+ };
1066
+ const samples = await page.evaluate(
1067
+ `(${overlapGridInPage})(${JSON.stringify(grid)}, ${seekInPage}, ${anchorsInPage})`
1068
+ );
1069
+ return samples.map(
1070
+ ({ raw, anchors }) => raw.flatMap(
1071
+ (value, index) => parseLayoutIssue(value).map((issue) => ({
1072
+ ...issue,
1073
+ ...anchors[index] ?? fallbackAnchor(void 0),
1074
+ bbox: rectToBbox(issue.rect),
1075
+ time: issue.time
1076
+ }))
1077
+ )
1078
+ );
1079
+ }
1080
+ async function captureFrame(page, scope) {
1081
+ if (!scope) return page.screenshot({ encoding: "base64", type: "png" });
1082
+ try {
1083
+ const box = await page.evaluate(isolateScopePaint, scope);
1084
+ if (!box || box.width < 1 || box.height < 1) return "";
1085
+ return await page.screenshot({
1086
+ encoding: "base64",
1087
+ type: "png",
1088
+ clip: box,
1089
+ omitBackground: true
1090
+ });
1091
+ } finally {
1092
+ await page.evaluate(restoreScopePaint);
1093
+ }
1094
+ }
1095
+ function isolateScopePaint(scope) {
1096
+ let target = null;
1097
+ try {
1098
+ target = document.querySelector(scope);
1099
+ } catch {
1100
+ return null;
1101
+ }
1102
+ if (!target) return null;
1103
+ const visibility = getComputedStyle(target).visibility;
1104
+ target.setAttribute("data-hf-capture-scope", "");
1105
+ const style = document.createElement("style");
1106
+ style.id = "__hf_capture_scope_style";
1107
+ style.textContent = `:not([data-hf-capture-scope], [data-hf-capture-scope] *) { visibility: hidden !important; }
1108
+ :root:not([data-hf-capture-scope]), body:not([data-hf-capture-scope]) { background: none !important; }
1109
+ [data-hf-capture-scope] { visibility: ${visibility} !important; }`;
1110
+ document.head.append(style);
1111
+ const rect = target.getBoundingClientRect();
1112
+ return { x: rect.left, y: rect.top, width: rect.width, height: rect.height };
1113
+ }
1114
+ function restoreScopePaint() {
1115
+ document.getElementById("__hf_capture_scope_style")?.remove();
1116
+ document.querySelector("[data-hf-capture-scope]")?.removeAttribute("data-hf-capture-scope");
1117
+ }
1118
+ async function collectLayoutGeometry(page) {
1119
+ return page.evaluate(() => {
1120
+ const geometry = Reflect.get(window, "__hyperframesLayoutGeometry");
1121
+ if (typeof geometry !== "function") return "";
1122
+ const result = Reflect.apply(geometry, window, []);
1123
+ return typeof result === "string" ? result : "";
1124
+ });
1125
+ }
1126
+ async function collectSeekClock(page) {
1127
+ return page.evaluate(() => {
1128
+ const callOrUndefined = (target, key, args = []) => {
1129
+ try {
1130
+ return Reflect.apply(Reflect.get(Object(target), key), target, args);
1131
+ } catch {
1132
+ return void 0;
1133
+ }
1134
+ };
1135
+ const known = Reflect.get(
1136
+ window,
1137
+ "__hfSeekClocks"
1138
+ ) ?? {
1139
+ ids: /* @__PURE__ */ new WeakMap(),
1140
+ next: 0
1141
+ };
1142
+ Reflect.set(window, "__hfSeekClocks", known);
1143
+ const idOf = (target) => {
1144
+ if (!known.ids.has(target)) known.ids.set(target, ++known.next);
1145
+ return known.ids.get(target) ?? 0;
1146
+ };
1147
+ const clocks = [];
1148
+ const timelines = Reflect.get(window, "__timelines");
1149
+ const registered = typeof timelines === "object" && timelines ? Object.values(timelines) : [];
1150
+ const gsapRoot = Reflect.get(Reflect.get(window, "gsap") ?? {}, "globalTimeline");
1151
+ const children = callOrUndefined(gsapRoot, "getChildren", [false, true, true]);
1152
+ for (const timeline of [...registered, ...Array.isArray(children) ? children : []]) {
1153
+ const total = Number(
1154
+ callOrUndefined(timeline, "totalDuration") ?? callOrUndefined(timeline, "duration")
1155
+ );
1156
+ if (typeof timeline !== "object" || !timeline || !(total > 0)) continue;
1157
+ const time = callOrUndefined(timeline, "totalTime") ?? callOrUndefined(timeline, "time");
1158
+ if (typeof time !== "number" || !Number.isFinite(time)) continue;
1159
+ const progress = Number(callOrUndefined(timeline, "totalProgress") ?? time / total);
1160
+ const done = callOrUndefined(timeline, "reversed") === true ? progress <= 0 : progress >= 1;
1161
+ clocks.push({ id: idOf(timeline), time, done });
1162
+ }
1163
+ for (const animation of document.getAnimations?.() ?? []) {
1164
+ if (typeof animation.currentTime !== "number") continue;
1165
+ const time = animation.currentTime;
1166
+ const end = Number(animation.effect?.getComputedTiming().endTime ?? Number.POSITIVE_INFINITY);
1167
+ const atEnd = animation.playbackRate < 0 ? time <= 0 : time >= end;
1168
+ clocks.push({ id: idOf(animation), time, done: animation.playState === "finished" || atEnd });
1169
+ }
1170
+ return clocks;
1171
+ });
1172
+ }
1173
+ async function evaluateSampler(page, globalName) {
1174
+ return page.evaluate((name) => {
1175
+ const sample = Reflect.get(window, name);
1176
+ if (typeof sample !== "function") return [];
1177
+ const result = Reflect.apply(sample, window, []);
1178
+ return Array.isArray(result) ? result : [];
1179
+ }, globalName);
1180
+ }
1181
+ async function collectRotationSample(page, time) {
1182
+ const raw = await evaluateSampler(page, "__hyperframesRotationSample");
1183
+ return raw.flatMap((value) => parseRotationSample(value, time));
1184
+ }
1185
+ function parseRotationSample(value, time) {
1186
+ if (!isRecord(value)) return [];
1187
+ const selector = stringValue(value, "selector");
1188
+ const cx = numberValue(value, "cx");
1189
+ const cy = numberValue(value, "cy");
1190
+ const w = numberValue(value, "w");
1191
+ const h = numberValue(value, "h");
1192
+ const angle = numberValue(value, "angle");
1193
+ if (!selector || cx === null || cy === null || w === null || h === null || angle === null) {
1194
+ return [];
1195
+ }
1196
+ return [{ time, selector, cx, cy, w, h, angle }];
1197
+ }
1198
+ async function collectOffPivotRotationSample(page, time) {
1199
+ const raw = await evaluateSampler(page, "__hyperframesOffPivotRotationSample");
1200
+ return { time, samples: raw.flatMap(parseOffPivotRotationSample) };
1201
+ }
1202
+ function requiredNumbers(value, keys) {
1203
+ const out = {};
1204
+ for (const key of keys) {
1205
+ const num = numberValue(value, key);
1206
+ if (num === null) return null;
1207
+ out[key] = num;
1208
+ }
1209
+ return out;
1210
+ }
1211
+ var OFF_PIVOT_REQUIRED_NUMBERS = ["ax", "ay", "bx", "by", "len", "angle", "hubCount"];
1212
+ function parseOffPivotRotationSample(value) {
1213
+ if (!isRecord(value)) return [];
1214
+ const selector = stringValue(value, "selector");
1215
+ const nums = requiredNumbers(value, OFF_PIVOT_REQUIRED_NUMBERS);
1216
+ if (!selector || !nums) return [];
1217
+ return [
1218
+ {
1219
+ selector,
1220
+ ax: nums.ax,
1221
+ ay: nums.ay,
1222
+ bx: nums.bx,
1223
+ by: nums.by,
1224
+ len: nums.len,
1225
+ angle: nums.angle,
1226
+ hx: numberValue(value, "hx"),
1227
+ hy: numberValue(value, "hy"),
1228
+ hr: numberValue(value, "hr"),
1229
+ hubCount: nums.hubCount
1230
+ }
1231
+ ];
1232
+ }
1233
+ async function collectGeometryCandidates(page, time, request) {
1234
+ try {
1235
+ const raw = await page.evaluate((options) => {
1236
+ const collect = Reflect.get(window, "__hyperframesGeometryCandidates");
1237
+ if (typeof collect !== "function") return [];
1238
+ const result = Reflect.apply(collect, window, [options]);
1239
+ return Array.isArray(result) ? result : [];
1240
+ }, request);
1241
+ return raw.flatMap((value) => parseGeometryCandidate(value, time));
1242
+ } catch {
1243
+ return [];
1244
+ }
1245
+ }
1246
+ async function findAmbiguousSelectors(page, selectors) {
1247
+ const ambiguous = await page.evaluate(
1248
+ (values) => values.filter((selector) => {
1249
+ try {
1250
+ return document.querySelectorAll(selector).length > 1;
1251
+ } catch {
1252
+ return false;
1253
+ }
1254
+ }),
1255
+ selectors
1256
+ );
1257
+ return anchorLayoutIssues(page, ambiguous.map(ambiguousIssue));
1258
+ }
1259
+ async function collectMotionFrame(page, time, selectors, livenessScopes) {
1260
+ const raw = await page.evaluate(
1261
+ (options) => {
1262
+ const sample = Reflect.get(window, "__hyperframesMotionSample");
1263
+ if (typeof sample !== "function") return null;
1264
+ return Reflect.apply(sample, window, [options]);
1265
+ },
1266
+ { selectors, livenessScopes }
1267
+ );
1268
+ return parseMotionFrame(raw, time, selectors, livenessScopes);
1269
+ }
1270
+ async function anchorLayoutIssues(page, issues) {
1271
+ const requests = issues.map((issue) => ({
1272
+ selector: issue.selector,
1273
+ time: issue.time,
1274
+ bbox: rectToBbox(issue.rect)
1275
+ }));
1276
+ const anchors = await resolveAnchors(page, requests);
1277
+ return issues.map((issue, index) => ({
1278
+ ...issue,
1279
+ ...anchors[index] ?? fallbackAnchor(requests[index])
1280
+ }));
1281
+ }
1282
+ async function resolveAnchors(page, requests) {
1283
+ if (requests.length === 0) return [];
1284
+ return page.evaluate(anchorsInPage, requests);
1285
+ }
1286
+ function anchorsInPage(values) {
1287
+ const root = document.querySelector("[data-composition-id]");
1288
+ return values.map((request) => {
1289
+ let element = null;
1290
+ try {
1291
+ element = document.querySelector(request.selector);
1292
+ } catch {
1293
+ element = null;
1294
+ }
1295
+ element ??= root;
1296
+ const dataAttributes = {};
1297
+ for (const attribute of Array.from(element?.attributes ?? [])) {
1298
+ if (attribute.name.startsWith("data-")) dataAttributes[attribute.name] = attribute.value;
1299
+ }
1300
+ const source = element?.closest("[data-composition-file]")?.getAttribute("data-composition-file");
1301
+ return {
1302
+ selector: element ? request.selector : "[data-composition-id]",
1303
+ dataAttributes,
1304
+ sourceFile: source || "index.html",
1305
+ bbox: request.bbox,
1306
+ time: request.time
1307
+ };
1308
+ });
1309
+ }
1310
+ async function resolveRootAnchor(page) {
1311
+ const selector = await page.evaluate(
1312
+ (explicit) => document.querySelector(explicit) ? explicit : "[data-composition-id]",
1313
+ '[data-composition-id][data-root="true"]'
1314
+ );
1315
+ const anchors = await resolveAnchors(page, [
1316
+ { selector, time: 0, bbox: await compositionBbox(page, selector) }
1317
+ ]);
1318
+ return anchors[0] ?? fallbackAnchor(void 0);
1319
+ }
1320
+ async function compositionBbox(page, selector) {
1321
+ return page.evaluate((root) => {
1322
+ const rect = document.querySelector(root)?.getBoundingClientRect();
1323
+ return rect ? { x: rect.x, y: rect.y, width: rect.width, height: rect.height } : { x: 0, y: 0, width: 0, height: 0 };
1324
+ }, selector);
1325
+ }
1326
+ async function collectContrast(page, time, snapshotAnnotations) {
1327
+ let prepared = [];
1328
+ try {
1329
+ prepared = parsePreparedContrast(await prepareContrast(page, time));
1330
+ if (prepared.length === 0 && !snapshotAnnotations) return { entries: [] };
1331
+ const { shot, region } = await measurementShot(page, prepared);
1332
+ const raw = await finishContrast(
1333
+ page,
1334
+ shot,
1335
+ time,
1336
+ prepared.map((entry) => entry.raw),
1337
+ region
1338
+ );
1339
+ const finished = raw.flatMap(parseFinishedContrast);
1340
+ const entries = joinContrastEntries(finished, prepared);
1341
+ if (!snapshotAnnotations) return { entries };
1342
+ const overviewShot = await page.screenshot({ encoding: "base64", type: "png" });
1343
+ if (typeof overviewShot !== "string") throw new Error("Overview screenshot was not base64");
1344
+ const annotations = [
1345
+ ...snapshotAnnotations,
1346
+ ...contrastFailureAnnotations(entries, snapshotAnnotations.length)
1347
+ ];
1348
+ const pngBase64 = await captureOverviewShot(page, annotations, overviewShot);
1349
+ return { entries, pngBase64 };
1350
+ } finally {
1351
+ await page.evaluate(() => {
1352
+ const restore = Reflect.get(window, "__contrastAuditRestoreIfPending");
1353
+ if (typeof restore === "function") Reflect.apply(restore, window, []);
1354
+ }).catch(() => void 0);
1355
+ }
1356
+ }
1357
+ async function measurementShot(page, prepared) {
1358
+ const frame = plainFrame(page.viewport());
1359
+ const sampled = prepared.filter((entry) => !entry.knownBackdrop);
1360
+ if (frame && sampled.length === 0) {
1361
+ const clip = { x: 0, y: 0, ...frame };
1362
+ return { shot: null, region: { clip, frameWidth: frame.width, frameHeight: frame.height } };
1363
+ }
1364
+ const region = textRegion(sampled, frame);
1365
+ const shot = await page.screenshot({
1366
+ encoding: "base64",
1367
+ type: "png",
1368
+ omitBackground: true,
1369
+ ...region ? { clip: region.clip, captureBeyondViewport: false } : {}
1370
+ });
1371
+ if (typeof shot !== "string") throw new Error("Contrast screenshot was not base64");
1372
+ return { shot, region };
1373
+ }
1374
+ function contrastFailureAnnotations(entries, labelOffset) {
1375
+ return entries.filter((entry) => !entry.wcagAA).map((entry, index) => ({
1376
+ label: `${labelOffset + index + 1} contrast_aa_failure`,
1377
+ bbox: entry.bbox
1378
+ }));
1379
+ }
1380
+ var ANNOTATION_OVERLAY_ID = "__hyperframesCheckAnnotations";
1381
+ async function captureOverviewShot(page, annotations, fallbackScreenshot) {
1382
+ if (annotations.length === 0) return fallbackScreenshot;
1383
+ await injectAnnotationOverlay(page, annotations);
1384
+ try {
1385
+ const shot = await page.screenshot({ encoding: "base64", type: "png" });
1386
+ return typeof shot === "string" ? shot : fallbackScreenshot;
1387
+ } finally {
1388
+ await removeAnnotationOverlay(page);
1389
+ }
1390
+ }
1391
+ async function injectAnnotationOverlay(page, boxes) {
1392
+ await page.evaluate(
1393
+ (items, overlayId) => {
1394
+ const root = document.createElement("div");
1395
+ root.id = overlayId;
1396
+ root.style.cssText = "position:fixed;inset:0;z-index:2147483647;pointer-events:none;";
1397
+ for (const item of items) {
1398
+ const box = document.createElement("div");
1399
+ box.style.cssText = `position:fixed;left:${item.bbox.x}px;top:${item.bbox.y}px;width:${item.bbox.width}px;height:${item.bbox.height}px;border:2px solid #ff2d55;box-sizing:border-box;`;
1400
+ const label = document.createElement("div");
1401
+ label.textContent = item.label;
1402
+ label.style.cssText = "position:absolute;top:-18px;left:0;background:#ff2d55;color:#fff;font:11px/16px monospace;padding:0 4px;white-space:nowrap;";
1403
+ box.appendChild(label);
1404
+ root.appendChild(box);
1405
+ }
1406
+ document.body.appendChild(root);
1407
+ },
1408
+ boxes,
1409
+ ANNOTATION_OVERLAY_ID
1410
+ );
1411
+ }
1412
+ async function removeAnnotationOverlay(page) {
1413
+ await page.evaluate((overlayId) => {
1414
+ document.getElementById(overlayId)?.remove();
1415
+ }, ANNOTATION_OVERLAY_ID);
1416
+ }
1417
+ async function prepareContrast(page, time) {
1418
+ return page.evaluate((sampleTime) => {
1419
+ const prepare = Reflect.get(window, "__contrastAuditPrepare");
1420
+ const candidates = typeof prepare === "function" ? Reflect.apply(prepare, window, []) : [];
1421
+ if (!Array.isArray(candidates)) return [];
1422
+ const restores = Reflect.get(window, "__contrastAuditRestores");
1423
+ const restoreList = Array.isArray(restores) ? restores : [];
1424
+ const escape = (value) => typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(value) : value.replace(/[^a-zA-Z0-9_-]/g, "\\$&");
1425
+ const selectorFor = (element, fallback) => {
1426
+ if (!element) return fallback;
1427
+ if (element.id) return `#${escape(element.id)}`;
1428
+ const parts = [];
1429
+ for (let current = element; current && current !== document.body; current = current.parentElement) {
1430
+ const tag = current.tagName.toLowerCase();
1431
+ const siblings = current.parentElement ? Array.from(current.parentElement.children).filter(
1432
+ (item) => item.tagName === current?.tagName
1433
+ ) : [];
1434
+ parts.push(
1435
+ siblings.length > 1 ? `${tag}:nth-of-type(${siblings.indexOf(current) + 1})` : tag
1436
+ );
1437
+ }
1438
+ return parts.reverse().join(" > ") || fallback;
1439
+ };
1440
+ return candidates.map((candidate, index) => {
1441
+ const restore = restoreList[index];
1442
+ const candidateObject = typeof candidate === "object" && candidate !== null ? candidate : {};
1443
+ const elementValue = typeof restore === "object" && restore !== null ? Reflect.get(restore, "el") : null;
1444
+ const element = elementValue instanceof Element ? elementValue : null;
1445
+ const fallback = Reflect.get(candidateObject, "selector");
1446
+ const selector = selectorFor(
1447
+ element,
1448
+ typeof fallback === "string" ? fallback : "[data-composition-id]"
1449
+ );
1450
+ const dataAttributes = {};
1451
+ for (const attribute of Array.from(element?.attributes ?? [])) {
1452
+ if (attribute.name.startsWith("data-")) dataAttributes[attribute.name] = attribute.value;
1453
+ }
1454
+ const source = element?.closest("[data-composition-file]")?.getAttribute("data-composition-file");
1455
+ return {
1456
+ candidate: { ...candidateObject, selector },
1457
+ anchor: {
1458
+ selector,
1459
+ dataAttributes,
1460
+ sourceFile: source || "index.html",
1461
+ bbox: Reflect.get(candidateObject, "bbox"),
1462
+ time: sampleTime
1463
+ }
1464
+ };
1465
+ });
1466
+ }, time);
1467
+ }
1468
+ function plainFrame(viewport) {
1469
+ if (!viewport || (viewport.deviceScaleFactor ?? 1) !== 1) return void 0;
1470
+ return { width: viewport.width, height: viewport.height };
1471
+ }
1472
+ function textRegion(prepared, viewport) {
1473
+ if (!viewport || prepared.length === 0) return void 0;
1474
+ const boxes = prepared.map((entry) => entry.candidate.bbox);
1475
+ const x = Math.max(0, Math.floor(Math.min(...boxes.map((box) => box.x))));
1476
+ const y = Math.max(0, Math.floor(Math.min(...boxes.map((box) => box.y))));
1477
+ const right = Math.min(viewport.width, Math.ceil(Math.max(...boxes.map((b) => b.x + b.width))));
1478
+ const bottom = Math.min(
1479
+ viewport.height,
1480
+ Math.ceil(Math.max(...boxes.map((b) => b.y + b.height)))
1481
+ );
1482
+ if (right <= x || bottom <= y) return void 0;
1483
+ const clip = { x, y, width: right - x, height: bottom - y };
1484
+ return { clip, frameWidth: viewport.width, frameHeight: viewport.height };
1485
+ }
1486
+ async function finishContrast(page, screenshot, time, candidates, region) {
1487
+ return page.evaluate(
1488
+ async (payload) => {
1489
+ const finish = Reflect.get(window, "__contrastAuditFinish");
1490
+ if (typeof finish !== "function") return [];
1491
+ const result = await Reflect.apply(finish, window, [
1492
+ payload.screenshot,
1493
+ payload.time,
1494
+ payload.candidates,
1495
+ payload.region
1496
+ ]);
1497
+ return Array.isArray(result) ? result : [];
1498
+ },
1499
+ { screenshot, time, candidates, region: region ?? null }
1500
+ );
1501
+ }
1502
+ function parsePreparedContrast(raw) {
1503
+ return raw.flatMap((value) => {
1504
+ if (!isRecord(value)) return [];
1505
+ const raw2 = Reflect.get(value, "candidate");
1506
+ const candidate = parseContrastCandidate(raw2);
1507
+ const anchor = parseAnchor(Reflect.get(value, "anchor"));
1508
+ return candidate && anchor ? [{ raw: raw2, candidate, anchor, knownBackdrop: knownBackdrop(raw2) }] : [];
1509
+ });
1510
+ }
1511
+ function knownBackdrop(raw) {
1512
+ if (!isRecord(raw)) return false;
1513
+ const own = Reflect.get(raw, "ownBg");
1514
+ const solid = Reflect.get(raw, "solidBg");
1515
+ return Array.isArray(solid) || Array.isArray(own) && own.length >= 4 && own[3] >= 0.99;
1516
+ }
1517
+ function parseContrastCandidate(value) {
1518
+ if (!isRecord(value)) return null;
1519
+ const selector = stringValue(value, "selector");
1520
+ const text = stringValue(value, "text");
1521
+ const fg = rgbaValue(Reflect.get(value, "fg"));
1522
+ const large = booleanValue(value, "large");
1523
+ const bbox = parseBbox(Reflect.get(value, "bbox"));
1524
+ return selector && text !== null && fg && large !== null && bbox ? { selector, text, fg, large, bbox } : null;
1525
+ }
1526
+ function parseFinishedContrast(value) {
1527
+ if (!isRecord(value)) return [];
1528
+ const selector = stringValue(value, "selector");
1529
+ const text = stringValue(value, "text");
1530
+ const ratio = numberValue(value, "ratio");
1531
+ const wcagAA = booleanValue(value, "wcagAA");
1532
+ const large = booleanValue(value, "large");
1533
+ const fg = stringValue(value, "fg");
1534
+ const bg = stringValue(value, "bg");
1535
+ return selector && text !== null && ratio !== null && wcagAA !== null && large !== null && fg && bg ? [{ selector, text, ratio, wcagAA, large, fg, bg }] : [];
1536
+ }
1537
+ function joinContrastEntries(finished, prepared) {
1538
+ const remaining = [...prepared];
1539
+ return finished.flatMap((entry) => {
1540
+ const index = remaining.findIndex(
1541
+ (candidate) => candidate.candidate.selector === entry.selector && candidate.candidate.text === entry.text
1542
+ );
1543
+ const match = index >= 0 ? remaining.splice(index, 1)[0] : void 0;
1544
+ return match ? [{ ...entry, ...match.anchor }] : [];
1545
+ });
1546
+ }
1547
+ function parseLayoutIssue(value) {
1548
+ if (!isRecord(value)) return [];
1549
+ const code = layoutCodeValue(Reflect.get(value, "code"));
1550
+ const severity = severityValue(Reflect.get(value, "severity"));
1551
+ const time = numberValue(value, "time");
1552
+ const selector = stringValue(value, "selector");
1553
+ const message = stringValue(value, "message");
1554
+ const rect = parseRect(Reflect.get(value, "rect"));
1555
+ if (!code || !severity || time === null || !selector || !message || !rect) return [];
1556
+ const issue = { code, severity, time, selector, message, rect };
1557
+ assignOptionalLayoutFields(issue, value);
1558
+ return [issue];
1559
+ }
1560
+ function parseGeometryCandidate(value, time) {
1561
+ if (!isRecord(value)) return [];
1562
+ const rect = parseRect(Reflect.get(value, "rect"));
1563
+ const elementRect = parseRect(Reflect.get(value, "elementRect"));
1564
+ if (!rect || !elementRect) return [];
1565
+ const identity = parseGeometryIdentity(value);
1566
+ if (!identity) return [];
1567
+ const anchor = parseGeometryAnchor(value, rect, time);
1568
+ if (!anchor) return [];
1569
+ const candidate = { ...identity, ...anchor, rect, elementRect };
1570
+ const overflow = parseOverflow(Reflect.get(value, "overflow"));
1571
+ if (overflow) candidate.overflow = overflow;
1572
+ return [candidate];
1573
+ }
1574
+ function parseGeometryIdentity(value) {
1575
+ const kindValue = Reflect.get(value, "kind");
1576
+ const kind = kindValue === "text" || kindValue === "media" ? kindValue : null;
1577
+ if (!kind) return null;
1578
+ const tag = stringValue(value, "tag");
1579
+ if (!tag) return null;
1580
+ const text = stringValue(value, "text");
1581
+ return text === null ? null : { kind, tag, text };
1582
+ }
1583
+ function parseGeometryAnchor(value, rect, time) {
1584
+ const selector = stringValue(value, "selector");
1585
+ if (!selector) return null;
1586
+ const sourceFile = stringValue(value, "sourceFile");
1587
+ if (!sourceFile) return null;
1588
+ const dataAttributes = stringRecord(Reflect.get(value, "dataAttributes"));
1589
+ return dataAttributes ? {
1590
+ selector,
1591
+ sourceFile,
1592
+ dataAttributes,
1593
+ bbox: rectToBbox(rect),
1594
+ time
1595
+ } : null;
1596
+ }
1597
+ function assignOptionalLayoutFields(issue, value) {
1598
+ assignOptionalString(issue, value, "containerSelector");
1599
+ assignOptionalString(issue, value, "text");
1600
+ assignOptionalString(issue, value, "fixHint");
1601
+ const containerRect = parseRect(Reflect.get(value, "containerRect"));
1602
+ if (containerRect) issue.containerRect = containerRect;
1603
+ const overflow = parseOverflow(Reflect.get(value, "overflow"));
1604
+ if (overflow) issue.overflow = overflow;
1605
+ const coveredFraction = numberValue(value, "coveredFraction");
1606
+ if (coveredFraction !== null) issue.coveredFraction = coveredFraction;
1607
+ }
1608
+ function recordField(value, key) {
1609
+ if (!isRecord(value)) return null;
1610
+ const field = Reflect.get(value, key);
1611
+ return isRecord(field) ? field : null;
1612
+ }
1613
+ function parseMotionFrame(value, time, selectors, scopes) {
1614
+ const rawData = recordField(value, "data");
1615
+ const rawLiveness = recordField(value, "liveness");
1616
+ const data = {};
1617
+ for (const selector of selectors) {
1618
+ data[selector] = rawData ? parseFrameSample(Reflect.get(rawData, selector)) : null;
1619
+ }
1620
+ const liveness = {};
1621
+ for (const scope of scopes) {
1622
+ const signature = rawLiveness ? Reflect.get(rawLiveness, scope) : "";
1623
+ liveness[scope] = typeof signature === "string" ? signature : "";
1624
+ }
1625
+ return { time, data, liveness };
1626
+ }
1627
+ function parseFrameSample(value) {
1628
+ if (!isRecord(value)) return null;
1629
+ const rect = parseRect(Reflect.get(value, "rect"));
1630
+ const opacity = numberValue(value, "opacity");
1631
+ const visible = booleanValue(value, "visible");
1632
+ return rect && opacity !== null && visible !== null ? { rect, opacity, visible } : null;
1633
+ }
1634
+ function parseAnchor(value) {
1635
+ if (!isRecord(value)) return null;
1636
+ const selector = stringValue(value, "selector");
1637
+ const sourceFile = stringValue(value, "sourceFile");
1638
+ const time = numberValue(value, "time");
1639
+ const bbox = parseBbox(Reflect.get(value, "bbox"));
1640
+ const dataAttributes = stringRecord(Reflect.get(value, "dataAttributes"));
1641
+ return selector && sourceFile && time !== null && bbox && dataAttributes ? { selector, sourceFile, time, bbox, dataAttributes } : null;
1642
+ }
1643
+ function runtimeFinding(draft, root) {
1644
+ return {
1645
+ code: draft.code,
1646
+ severity: draft.severity,
1647
+ message: (draft.count ?? 1) > 1 ? `${draft.message} (repeated ${draft.count} times)` : draft.message,
1648
+ selector: root.selector,
1649
+ dataAttributes: root.dataAttributes,
1650
+ sourceFile: root.sourceFile,
1651
+ bbox: root.bbox,
1652
+ time: draft.time,
1653
+ ...draft.timeRange ? { timeRange: draft.timeRange } : {},
1654
+ url: draft.url,
1655
+ line: draft.line,
1656
+ ...draft.fixHint ? { fixHint: draft.fixHint } : {}
1657
+ };
1658
+ }
1659
+ function fallbackAnchor(request) {
1660
+ return {
1661
+ selector: request?.selector ?? "[data-composition-id]",
1662
+ dataAttributes: {},
1663
+ sourceFile: "index.html",
1664
+ bbox: request?.bbox ?? { x: 0, y: 0, width: 0, height: 0 },
1665
+ time: request?.time ?? 0
1666
+ };
1667
+ }
1668
+ function parseBbox(value) {
1669
+ if (!isRecord(value)) return null;
1670
+ const x = numberValue(value, "x");
1671
+ const y = numberValue(value, "y");
1672
+ const width = numberValue(value, "width") ?? numberValue(value, "w");
1673
+ const height = numberValue(value, "height") ?? numberValue(value, "h");
1674
+ return x !== null && y !== null && width !== null && height !== null ? { x, y, width, height } : null;
1675
+ }
1676
+ function parseRect(value) {
1677
+ if (!isRecord(value)) return null;
1678
+ const left = numberValue(value, "left");
1679
+ const top = numberValue(value, "top");
1680
+ const right = numberValue(value, "right");
1681
+ const bottom = numberValue(value, "bottom");
1682
+ const width = numberValue(value, "width");
1683
+ const height = numberValue(value, "height");
1684
+ return left !== null && top !== null && right !== null && bottom !== null && width !== null && height !== null ? { left, top, right, bottom, width, height } : null;
1685
+ }
1686
+ function parseOverflow(value) {
1687
+ if (!isRecord(value)) return null;
1688
+ const overflow = {};
1689
+ for (const side of ["left", "right", "top", "bottom"]) {
1690
+ const amount = numberValue(value, side);
1691
+ if (amount !== null) overflow[side] = amount;
1692
+ }
1693
+ return Object.keys(overflow).length > 0 ? overflow : null;
1694
+ }
1695
+ var LAYOUT_ISSUE_CODES = [
1696
+ "text_box_overflow",
1697
+ "clipped_text",
1698
+ "canvas_overflow",
1699
+ "container_overflow",
1700
+ "content_overlap",
1701
+ "visibility_escapes_segment",
1702
+ "text_occluded",
1703
+ "video_alpha_unread",
1704
+ "text_not_painted",
1705
+ "caption_zone_collision",
1706
+ "frame_out_of_frame",
1707
+ "escaped_container",
1708
+ "panel_out_of_canvas",
1709
+ "canvas_content_at_edge",
1710
+ "connector_detached",
1711
+ "connector_orphan",
1712
+ "rotation_pivot_drift",
1713
+ "off_pivot_rotation",
1714
+ "motion_appears_late",
1715
+ "motion_out_of_order",
1716
+ "motion_off_frame",
1717
+ "motion_frozen",
1718
+ "motion_selector_missing",
1719
+ "motion_selector_ambiguous"
1720
+ ];
1721
+ function layoutCodeValue(value) {
1722
+ return LAYOUT_ISSUE_CODES.find((code) => code === value) ?? null;
1723
+ }
1724
+ function severityValue(value) {
1725
+ return value === "error" || value === "warning" || value === "info" ? value : null;
1726
+ }
1727
+ function rgbaValue(value) {
1728
+ if (!Array.isArray(value) || value.length < 4) return null;
1729
+ const [red, green, blue, alpha] = value;
1730
+ return [red, green, blue, alpha].every((channel) => typeof channel === "number") ? [red, green, blue, alpha] : null;
1731
+ }
1732
+ function stringRecord(value) {
1733
+ if (!isRecord(value)) return null;
1734
+ const record = {};
1735
+ for (const key of Object.keys(value)) {
1736
+ const entry = Reflect.get(value, key);
1737
+ if (typeof entry !== "string") return null;
1738
+ record[key] = entry;
1739
+ }
1740
+ return record;
1741
+ }
1742
+ function assignOptionalString(issue, source, key) {
1743
+ const value = stringValue(source, key);
1744
+ if (value !== null) issue[key] = value;
1745
+ }
1746
+ function isRecord(value) {
1747
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1748
+ }
1749
+ function stringValue(value, key) {
1750
+ const entry = Reflect.get(value, key);
1751
+ return typeof entry === "string" ? entry : null;
1752
+ }
1753
+ function numberValue(value, key) {
1754
+ const entry = Reflect.get(value, key);
1755
+ return typeof entry === "number" && Number.isFinite(entry) ? entry : null;
1756
+ }
1757
+ function booleanValue(value, key) {
1758
+ const entry = Reflect.get(value, key);
1759
+ return typeof entry === "boolean" ? entry : null;
1760
+ }
1761
+ function urlPath(url) {
1762
+ try {
1763
+ return decodeURIComponent(new URL(url).pathname).replace(/^\//, "");
1764
+ } catch {
1765
+ return url;
1766
+ }
1767
+ }
1768
+ function matchComponentFindings({
1769
+ components,
1770
+ findings
1771
+ }) {
1772
+ const roots = components.flatMap((selector) => {
1773
+ const matches = [...document.querySelectorAll(selector)];
1774
+ if (!matches.length) throw new Error(`Component selector matched nothing: ${selector}`);
1775
+ return matches;
1776
+ });
1777
+ function matchesSelector(selector) {
1778
+ try {
1779
+ const elements = [...document.querySelectorAll(selector)];
1780
+ if (!elements.length) return null;
1781
+ return elements.some((el) => roots.some((root) => root.contains(el)));
1782
+ } catch {
1783
+ return null;
1784
+ }
1785
+ }
1786
+ return findings.map((finding) => {
1787
+ if (!finding.selector || finding.selector === "[data-composition-id]") return true;
1788
+ const container = Reflect.get(finding, "containerSelector");
1789
+ return matchesSelector(finding.selector) !== false || typeof container === "string" && matchesSelector(container) !== false;
1790
+ });
1791
+ }
1792
+
1793
+ export {
1794
+ beginCheckSnapshots,
1795
+ checkSnapshotDirectory,
1796
+ finishCheckSnapshots,
1797
+ rectToBbox,
1798
+ preResolveHostileMediaProxies,
1799
+ runBrowserCheck,
1800
+ samplingBrowserCount,
1801
+ mergeHelperDrafts,
1802
+ captureFindingCrops,
1803
+ keepBrokenImageAborts,
1804
+ dropFailedProxyEchoes,
1805
+ createPageDriver,
1806
+ collectSeekClock,
1807
+ captureOverviewShot,
1808
+ matchComponentFindings
1809
+ };