@ignix-social/editor 0.1.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.
- package/LICENSE +190 -0
- package/NOTICE +54 -0
- package/README.md +23 -0
- package/bin/ignix-editor.mjs +8 -0
- package/package.json +53 -0
- package/patches/index.mjs +53 -0
- package/scripts/build-ffmpeg-macos.sh +35 -0
- package/scripts/build-whisper-macos.sh +21 -0
- package/scripts/vendor.mjs +41 -0
- package/skills/ignix-editor/SKILL.md +132 -0
- package/src/audio.mjs +31 -0
- package/src/binaries.json +46 -0
- package/src/binaries.mjs +83 -0
- package/src/cli.mjs +254 -0
- package/src/prepare.mjs +74 -0
- package/src/runtime/ignix-frame.js +92 -0
- package/src/transcribe.mjs +71 -0
- package/src/validate.mjs +71 -0
- package/templates/blank/index.html +41 -0
- package/vendor/hyperframes/README.md +181 -0
- package/vendor/hyperframes/UPSTREAM.json +12 -0
- package/vendor/hyperframes/bin/hyperframes-localize-fonts.mjs +12 -0
- package/vendor/hyperframes/bin/hyperframes.mjs +11 -0
- package/vendor/hyperframes/dist/add-LR3ZR2A5.js +79 -0
- package/vendor/hyperframes/dist/agentPromptGenerator-VIIPZCJ3.js +143 -0
- package/vendor/hyperframes/dist/animatedGifPrep-P2T6YM7Z.js +34 -0
- package/vendor/hyperframes/dist/asset-BE2DOV72.js +26 -0
- package/vendor/hyperframes/dist/assetCataloger-VBLPHX24.js +340 -0
- package/vendor/hyperframes/dist/auth-RCQB2ZT7.js +60 -0
- package/vendor/hyperframes/dist/autoUpdate-RJAX3DAZ.js +268 -0
- package/vendor/hyperframes/dist/backgroundChecks-H2LCUIMJ.js +61 -0
- package/vendor/hyperframes/dist/backgroundChecksWorker.js +26 -0
- package/vendor/hyperframes/dist/batchRender-FT7AP7XH.js +355 -0
- package/vendor/hyperframes/dist/beat-analyzer.global.js +338 -0
- package/vendor/hyperframes/dist/beats-Y2EOP72P.js +309 -0
- package/vendor/hyperframes/dist/benchmark-MZ7GY3JW.js +231 -0
- package/vendor/hyperframes/dist/browser-HUTAMRQE.js +237 -0
- package/vendor/hyperframes/dist/bundleWithLocalizedFonts-5QOPOB5D.js +52 -0
- package/vendor/hyperframes/dist/capture-RLZA6EMR.js +4079 -0
- package/vendor/hyperframes/dist/capture-SZZ4IYJK.js +290 -0
- package/vendor/hyperframes/dist/captureFile-LYOJOUIE.js +15 -0
- package/vendor/hyperframes/dist/captureTimeout-PA4FYWT5.js +27 -0
- package/vendor/hyperframes/dist/catalog-KYU55EWR.js +1001 -0
- package/vendor/hyperframes/dist/check-TCG4PXLR.js +1697 -0
- package/vendor/hyperframes/dist/checkBrowser-RPMO4OW5.js +1032 -0
- package/vendor/hyperframes/dist/chunk-2EAXUCCE.js +88 -0
- package/vendor/hyperframes/dist/chunk-2EGFTPWD.js +1077 -0
- package/vendor/hyperframes/dist/chunk-2PSPARWP.js +6058 -0
- package/vendor/hyperframes/dist/chunk-2YN64IN5.js +5747 -0
- package/vendor/hyperframes/dist/chunk-3GXQPCJC.js +682 -0
- package/vendor/hyperframes/dist/chunk-3ZP5DXE7.js +15 -0
- package/vendor/hyperframes/dist/chunk-4NWOGZZS.js +1990 -0
- package/vendor/hyperframes/dist/chunk-4PFZPP2N.js +587 -0
- package/vendor/hyperframes/dist/chunk-4THIAPBL.js +128 -0
- package/vendor/hyperframes/dist/chunk-4YYJOFKS.js +28 -0
- package/vendor/hyperframes/dist/chunk-54HJ63Q2.js +29 -0
- package/vendor/hyperframes/dist/chunk-5ETJX6WM.js +89 -0
- package/vendor/hyperframes/dist/chunk-5IAKAQA7.js +389 -0
- package/vendor/hyperframes/dist/chunk-5Z63TBTX.js +37 -0
- package/vendor/hyperframes/dist/chunk-6BEFEWFB.js +25 -0
- package/vendor/hyperframes/dist/chunk-6CSYCFQV.js +68 -0
- package/vendor/hyperframes/dist/chunk-6CTIGJY7.js +154 -0
- package/vendor/hyperframes/dist/chunk-7HG4BFIN.js +93 -0
- package/vendor/hyperframes/dist/chunk-7JZ4FXP2.js +118 -0
- package/vendor/hyperframes/dist/chunk-A2Z4Z4VL.js +2961 -0
- package/vendor/hyperframes/dist/chunk-AMKC3AXA.js +25 -0
- package/vendor/hyperframes/dist/chunk-AVUUN2XD.js +4847 -0
- package/vendor/hyperframes/dist/chunk-AWDFDFI3.js +46 -0
- package/vendor/hyperframes/dist/chunk-AWNBM3MZ.js +94 -0
- package/vendor/hyperframes/dist/chunk-BXCMXMJQ.js +73 -0
- package/vendor/hyperframes/dist/chunk-BZ56MTDX.js +6 -0
- package/vendor/hyperframes/dist/chunk-CFKU7HTK.js +171 -0
- package/vendor/hyperframes/dist/chunk-CWPVM2QV.js +308 -0
- package/vendor/hyperframes/dist/chunk-DPVXBVLL.js +31292 -0
- package/vendor/hyperframes/dist/chunk-DQBY7FRR.js +397 -0
- package/vendor/hyperframes/dist/chunk-E6RPWJVC.js +213 -0
- package/vendor/hyperframes/dist/chunk-EISRN4E6.js +294 -0
- package/vendor/hyperframes/dist/chunk-EOVYQ3IG.js +143 -0
- package/vendor/hyperframes/dist/chunk-F3WZGU7C.js +479 -0
- package/vendor/hyperframes/dist/chunk-FCSIGXXP.js +366 -0
- package/vendor/hyperframes/dist/chunk-FI4I7CME.js +56 -0
- package/vendor/hyperframes/dist/chunk-FLWXXDNS.js +15 -0
- package/vendor/hyperframes/dist/chunk-GK4AIFIH.js +11171 -0
- package/vendor/hyperframes/dist/chunk-GMECXFAN.js +57 -0
- package/vendor/hyperframes/dist/chunk-GULOKZLI.js +155 -0
- package/vendor/hyperframes/dist/chunk-H4YZZ2VQ.js +68 -0
- package/vendor/hyperframes/dist/chunk-H6QMKUYA.js +477 -0
- package/vendor/hyperframes/dist/chunk-HBBJFK6I.js +273 -0
- package/vendor/hyperframes/dist/chunk-HRUGC23L.js +212 -0
- package/vendor/hyperframes/dist/chunk-HVW7ABXD.js +19 -0
- package/vendor/hyperframes/dist/chunk-HW6OYASV.js +344 -0
- package/vendor/hyperframes/dist/chunk-HWKCIWQT.js +3578 -0
- package/vendor/hyperframes/dist/chunk-I465DBM6.js +1214 -0
- package/vendor/hyperframes/dist/chunk-IGLEPPTN.js +24 -0
- package/vendor/hyperframes/dist/chunk-IGNAAHS3.js +433 -0
- package/vendor/hyperframes/dist/chunk-IHFUKJOR.js +85 -0
- package/vendor/hyperframes/dist/chunk-IQ3OUQ5Z.js +213 -0
- package/vendor/hyperframes/dist/chunk-ISN5GRYI.js +20 -0
- package/vendor/hyperframes/dist/chunk-IUZFXWSV.js +446 -0
- package/vendor/hyperframes/dist/chunk-JH556Q42.js +647 -0
- package/vendor/hyperframes/dist/chunk-JTHMTOMQ.js +601 -0
- package/vendor/hyperframes/dist/chunk-K2EQN4VU.js +405 -0
- package/vendor/hyperframes/dist/chunk-K2FTXJYH.js +16044 -0
- package/vendor/hyperframes/dist/chunk-K4WIOZFP.js +32 -0
- package/vendor/hyperframes/dist/chunk-K4WKGXRC.js +18 -0
- package/vendor/hyperframes/dist/chunk-KBJUXVOJ.js +172 -0
- package/vendor/hyperframes/dist/chunk-KC5XXX3X.js +590 -0
- package/vendor/hyperframes/dist/chunk-KNU5COPB.js +29 -0
- package/vendor/hyperframes/dist/chunk-KZI44OPA.js +185 -0
- package/vendor/hyperframes/dist/chunk-L3YOGIPG.js +48 -0
- package/vendor/hyperframes/dist/chunk-LAOCA3MQ.js +189 -0
- package/vendor/hyperframes/dist/chunk-LCSMOLGX.js +312 -0
- package/vendor/hyperframes/dist/chunk-LFGJWOVA.js +61 -0
- package/vendor/hyperframes/dist/chunk-LHSR3M4M.js +498 -0
- package/vendor/hyperframes/dist/chunk-LYNI3FOL.js +123 -0
- package/vendor/hyperframes/dist/chunk-M2WBOQ2Q.js +54 -0
- package/vendor/hyperframes/dist/chunk-MRF4AMKD.js +104 -0
- package/vendor/hyperframes/dist/chunk-MWB3ZIFM.js +852 -0
- package/vendor/hyperframes/dist/chunk-NGKM64BP.js +39 -0
- package/vendor/hyperframes/dist/chunk-NXMYHJAL.js +43 -0
- package/vendor/hyperframes/dist/chunk-OAF4XJOW.js +192 -0
- package/vendor/hyperframes/dist/chunk-OFQWTKPW.js +117 -0
- package/vendor/hyperframes/dist/chunk-P6LJ4Y32.js +4662 -0
- package/vendor/hyperframes/dist/chunk-PBN6GBJE.js +108 -0
- package/vendor/hyperframes/dist/chunk-PDAMK4Q5.js +28 -0
- package/vendor/hyperframes/dist/chunk-PFCFR3KZ.js +20 -0
- package/vendor/hyperframes/dist/chunk-PJ3HDUCY.js +108 -0
- package/vendor/hyperframes/dist/chunk-PMRBLBUP.js +152 -0
- package/vendor/hyperframes/dist/chunk-PPQUYWTW.js +240 -0
- package/vendor/hyperframes/dist/chunk-Q5X2B5WT.js +29 -0
- package/vendor/hyperframes/dist/chunk-Q7IU7MOR.js +351 -0
- package/vendor/hyperframes/dist/chunk-QC4FJVLM.js +371 -0
- package/vendor/hyperframes/dist/chunk-QNYYOUU3.js +1318 -0
- package/vendor/hyperframes/dist/chunk-RDNNAKEP.js +161 -0
- package/vendor/hyperframes/dist/chunk-RMHUQGRK.js +657 -0
- package/vendor/hyperframes/dist/chunk-RQVDTPGD.js +6 -0
- package/vendor/hyperframes/dist/chunk-RVCWIIZ7.js +68 -0
- package/vendor/hyperframes/dist/chunk-S3D6GE5W.js +72 -0
- package/vendor/hyperframes/dist/chunk-S3S4TGEH.js +424 -0
- package/vendor/hyperframes/dist/chunk-S7NPLFWV.js +11395 -0
- package/vendor/hyperframes/dist/chunk-SHB5VDMH.js +51 -0
- package/vendor/hyperframes/dist/chunk-TCLGPL65.js +860 -0
- package/vendor/hyperframes/dist/chunk-THXFSPLV.js +40 -0
- package/vendor/hyperframes/dist/chunk-TJSTGSAW.js +354 -0
- package/vendor/hyperframes/dist/chunk-TQFG7HTI.js +1024 -0
- package/vendor/hyperframes/dist/chunk-TVCRUG2S.js +265 -0
- package/vendor/hyperframes/dist/chunk-TWWSYAKJ.js +24 -0
- package/vendor/hyperframes/dist/chunk-U7CZBDMV.js +27 -0
- package/vendor/hyperframes/dist/chunk-UEZXMWG3.js +139 -0
- package/vendor/hyperframes/dist/chunk-UYEZTK4U.js +61 -0
- package/vendor/hyperframes/dist/chunk-VC76R6W2.js +27 -0
- package/vendor/hyperframes/dist/chunk-VFCKXTBB.js +159 -0
- package/vendor/hyperframes/dist/chunk-VWG7OQKU.js +22 -0
- package/vendor/hyperframes/dist/chunk-VXVRPIJA.js +105 -0
- package/vendor/hyperframes/dist/chunk-WBLXWOYK.js +15 -0
- package/vendor/hyperframes/dist/chunk-WERLJGIC.js +20 -0
- package/vendor/hyperframes/dist/chunk-WMQNIQDJ.js +2057 -0
- package/vendor/hyperframes/dist/chunk-WPHMNO44.js +4528 -0
- package/vendor/hyperframes/dist/chunk-X5HWXQPU.js +113 -0
- package/vendor/hyperframes/dist/chunk-X7MTZ4T2.js +6 -0
- package/vendor/hyperframes/dist/chunk-XH4DSOS5.js +59 -0
- package/vendor/hyperframes/dist/chunk-XS4EJSKU.js +23 -0
- package/vendor/hyperframes/dist/chunk-XT5P4QMO.js +181 -0
- package/vendor/hyperframes/dist/chunk-XT7X6QCP.js +6 -0
- package/vendor/hyperframes/dist/chunk-XUHOIDKG.js +6 -0
- package/vendor/hyperframes/dist/chunk-XUXGIA7H.js +485 -0
- package/vendor/hyperframes/dist/chunk-XZABUQTX.js +113 -0
- package/vendor/hyperframes/dist/chunk-Y6W4DVPS.js +356 -0
- package/vendor/hyperframes/dist/chunk-YEIFI443.js +44 -0
- package/vendor/hyperframes/dist/chunk-YQZNILVH.js +375 -0
- package/vendor/hyperframes/dist/chunk-Z27A7NUB.js +65 -0
- package/vendor/hyperframes/dist/chunk-Z6B37SNM.js +3081 -0
- package/vendor/hyperframes/dist/chunk-ZJUKFZ2P.js +10954 -0
- package/vendor/hyperframes/dist/chunk-ZKDMAOFU.js +32 -0
- package/vendor/hyperframes/dist/chunk-ZMXUQLI2.js +17219 -0
- package/vendor/hyperframes/dist/chunk-ZTZ7NCJT.js +58 -0
- package/vendor/hyperframes/dist/chunk-ZTZA4UWZ.js +108 -0
- package/vendor/hyperframes/dist/clean-W57E5YQ3.js +293 -0
- package/vendor/hyperframes/dist/cli.js +495 -0
- package/vendor/hyperframes/dist/cloud-FFTJGZ24.js +70 -0
- package/vendor/hyperframes/dist/cloudrun-AJUTHUEA.js +763 -0
- package/vendor/hyperframes/dist/colors-HKWSZCGK.js +15 -0
- package/vendor/hyperframes/dist/commands/contrast-audit.browser.js +459 -0
- package/vendor/hyperframes/dist/commands/layout-audit.browser.js +2102 -0
- package/vendor/hyperframes/dist/commands/motion-sample.browser.js +74 -0
- package/vendor/hyperframes/dist/commands/motion-signature.browser.js +374 -0
- package/vendor/hyperframes/dist/compare-AYCTT55F.js +421 -0
- package/vendor/hyperframes/dist/compiler-QO36EXLS.js +121 -0
- package/vendor/hyperframes/dist/component-VFFR2O7T.js +176 -0
- package/vendor/hyperframes/dist/compositions-QTVN3U2A.js +228 -0
- package/vendor/hyperframes/dist/contactSheet-27SRU7A4.js +22 -0
- package/vendor/hyperframes/dist/delete-ZAKYCB7I.js +114 -0
- package/vendor/hyperframes/dist/deploy-MX76RZ36.js +101 -0
- package/vendor/hyperframes/dist/destroy-H2TZBYHH.js +42 -0
- package/vendor/hyperframes/dist/deterministicFonts-HAEMV4TM.js +50 -0
- package/vendor/hyperframes/dist/dist-EWXJGN63.js +129 -0
- package/vendor/hyperframes/dist/dist-FNNGCKFS.js +29 -0
- package/vendor/hyperframes/dist/dist-S3PJNPXQ.js +392 -0
- package/vendor/hyperframes/dist/docker/Dockerfile.render +65 -0
- package/vendor/hyperframes/dist/docs/compositions.md +67 -0
- package/vendor/hyperframes/dist/docs/data-attributes.md +27 -0
- package/vendor/hyperframes/dist/docs/examples.md +19 -0
- package/vendor/hyperframes/dist/docs/gsap.md +26 -0
- package/vendor/hyperframes/dist/docs/rendering.md +35 -0
- package/vendor/hyperframes/dist/docs/troubleshooting.md +29 -0
- package/vendor/hyperframes/dist/docs-QAPJEGLS.js +131 -0
- package/vendor/hyperframes/dist/doctor-AI7C3FON.js +67 -0
- package/vendor/hyperframes/dist/dom-IROKGVJI.js +14 -0
- package/vendor/hyperframes/dist/dotEnv-AECLXQSO.js +14 -0
- package/vendor/hyperframes/dist/events-7LALYNKZ.js +92 -0
- package/vendor/hyperframes/dist/events-FQY3HGKZ.js +88 -0
- package/vendor/hyperframes/dist/feedback-WCMDMSTK.js +472 -0
- package/vendor/hyperframes/dist/ffmpeg-QIUFEFTY.js +35 -0
- package/vendor/hyperframes/dist/figma-64WY462P.js +63 -0
- package/vendor/hyperframes/dist/fontData.generated-NXAOI4GH.js +13 -0
- package/vendor/hyperframes/dist/fontLocalizeCli.js +132 -0
- package/vendor/hyperframes/dist/get-FPOMJMZB.js +103 -0
- package/vendor/hyperframes/dist/gpuPolicy-2ZUZE5D6.js +38 -0
- package/vendor/hyperframes/dist/grade-compare-E2CKPST4.js +647 -0
- package/vendor/hyperframes/dist/gsapParser-DIYYX6JT.js +2846 -0
- package/vendor/hyperframes/dist/gsapParserAcorn-E3GEIRZB.js +28 -0
- package/vendor/hyperframes/dist/help-YRQIDDML.js +197 -0
- package/vendor/hyperframes/dist/history-PP5NDRV3.js +571 -0
- package/vendor/hyperframes/dist/hyperframe-runtime.js +1081 -0
- package/vendor/hyperframes/dist/hyperframe.manifest.json +22 -0
- package/vendor/hyperframes/dist/hyperframe.runtime.iife.js +1081 -0
- package/vendor/hyperframes/dist/hyperframes-player.global.js +474 -0
- package/vendor/hyperframes/dist/hyperframes-slideshow.global.js +149 -0
- package/vendor/hyperframes/dist/info-SEX3B7JL.js +153 -0
- package/vendor/hyperframes/dist/init-U3AKHO5B.js +1147 -0
- package/vendor/hyperframes/dist/inspect-Q3K6EDEK.js +97 -0
- package/vendor/hyperframes/dist/installer-K6O5WF44.js +37 -0
- package/vendor/hyperframes/dist/keyframes-DC64JCI3.js +2602 -0
- package/vendor/hyperframes/dist/lambda-D7UMN4DJ.js +451 -0
- package/vendor/hyperframes/dist/layout-XSPPDHOO.js +86 -0
- package/vendor/hyperframes/dist/lib-TPG2ZMAX.js +128 -0
- package/vendor/hyperframes/dist/lint-7DQZE7L3.js +164 -0
- package/vendor/hyperframes/dist/lintProject-OHBBM3DJ.js +27 -0
- package/vendor/hyperframes/dist/list-4K5MVDQX.js +162 -0
- package/vendor/hyperframes/dist/login-NTX4OWXL.js +377 -0
- package/vendor/hyperframes/dist/logout-Q654A3SI.js +100 -0
- package/vendor/hyperframes/dist/manager-67P2XFXQ.js +34 -0
- package/vendor/hyperframes/dist/manager-CT3D67CG.js +38 -0
- package/vendor/hyperframes/dist/manager-GFN75DM4.js +30 -0
- package/vendor/hyperframes/dist/media-treatment-5FYAOPNL.js +972 -0
- package/vendor/hyperframes/dist/media-use-4XXGABIL.js +113 -0
- package/vendor/hyperframes/dist/models-C4E4IWJD.js +137 -0
- package/vendor/hyperframes/dist/motionShot-S4MIGMT5.js +614 -0
- package/vendor/hyperframes/dist/normalize-O76AC4HE.js +333 -0
- package/vendor/hyperframes/dist/normalize-audio-CSFTXLXD.js +276 -0
- package/vendor/hyperframes/dist/open-2ZD6BHZG.js +115 -0
- package/vendor/hyperframes/dist/pipeline-TNGWUZQC.js +54 -0
- package/vendor/hyperframes/dist/play-CTMUXX6E.js +349 -0
- package/vendor/hyperframes/dist/policies-FSDZVS2E.js +292 -0
- package/vendor/hyperframes/dist/preflight-SMNV6RW2.js +45 -0
- package/vendor/hyperframes/dist/present-WQVHV5CR.js +350 -0
- package/vendor/hyperframes/dist/preview-JOJXTH75.js +1820 -0
- package/vendor/hyperframes/dist/producer-ECLEN5RP.js +13 -0
- package/vendor/hyperframes/dist/progress-FBIEEB7Y.js +73 -0
- package/vendor/hyperframes/dist/projectConfig-HYJMJ5BY.js +56 -0
- package/vendor/hyperframes/dist/publication-HQ5Y3KBM.js +29 -0
- package/vendor/hyperframes/dist/publish-VHDYQASC.js +430 -0
- package/vendor/hyperframes/dist/refresh-K24ETHMA.js +53 -0
- package/vendor/hyperframes/dist/remove-background-W2YX2NVH.js +253 -0
- package/vendor/hyperframes/dist/render-AO5VX3YI.js +177 -0
- package/vendor/hyperframes/dist/render-LNO62LEL.js +2367 -0
- package/vendor/hyperframes/dist/render-TTQI7TGN.js +796 -0
- package/vendor/hyperframes/dist/render-batch-YH7CTWNY.js +284 -0
- package/vendor/hyperframes/dist/renderCancellation-JPIHE47X.js +35 -0
- package/vendor/hyperframes/dist/renderSetupWorker.js +79 -0
- package/vendor/hyperframes/dist/resolver-IZ647GBZ.js +38 -0
- package/vendor/hyperframes/dist/runtimeVersion.js +18 -0
- package/vendor/hyperframes/dist/screenshotCapture-ECBTLCU6.js +179 -0
- package/vendor/hyperframes/dist/shaderTransitionWorker.js +44 -0
- package/vendor/hyperframes/dist/sherpa-KKLNW6U2.js +314 -0
- package/vendor/hyperframes/dist/sherpaWorker.js +77 -0
- package/vendor/hyperframes/dist/sites-TNVKZS73.js +52 -0
- package/vendor/hyperframes/dist/skill-ZHVLH7KX.js +15 -0
- package/vendor/hyperframes/dist/skills/hyperframes/SKILL.md +152 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/brief-contract.md +108 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/brief-format.md +72 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/capability-menu.md +47 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/frame-worker-core.md +80 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/intent-interview.md +73 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/pitch-round.md +40 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/plugin-installation.md +43 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/production-loop.md +26 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/review-loop.md +37 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/route-briefs.md +11 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/embedded-captions.md +11 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/faceless-explainer.md +12 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/general-video.md +12 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/motion-graphics.md +11 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/music-to-video.md +12 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/pr-to-video.md +28 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/product-launch-video.md +13 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/remotion-to-hyperframes.md +9 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/slideshow.md +11 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/routes/talking-head-recut.md +11 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/script-format.md +52 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/skill-lifecycle.md +35 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/storyboard-format.md +99 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/subagent-dispatch.md +35 -0
- package/vendor/hyperframes/dist/skills/hyperframes/references/workflow-catalog.md +10 -0
- package/vendor/hyperframes/dist/skills/hyperframes/scripts/lib/frame-packets-core.mjs +194 -0
- package/vendor/hyperframes/dist/skills/hyperframes/scripts/plugin-cli.mjs +88 -0
- package/vendor/hyperframes/dist/skills/hyperframes/scripts/plugin-cli.test.mjs +117 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/SKILL.md +189 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/beats.md +19 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/cloud.md +163 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/cloudrun.md +62 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/compare-and-batch.md +105 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/doctor-browser.md +57 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/init-and-scaffold.md +74 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/lambda.md +185 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +132 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/preview-render.md +193 -0
- package/vendor/hyperframes/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +134 -0
- package/vendor/hyperframes/dist/skills/media-use/SKILL.md +100 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/CREDITS.md +35 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/chime.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/click-soft.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/click.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/error.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/glitch-1.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/glitch-2.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/glitch-3.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/impact-bass-1.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/impact-bass-2.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/key-press.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/manifest.json +97 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/notification.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/ping.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/pop.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/riser.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/sparkle.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/typing.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/whoosh-cinematic.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/whoosh-short.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/assets/sfx/whoosh.mp3 +0 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/bgm.md +76 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/captions/authoring.md +163 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/captions/motion.md +87 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/captions/transcript-handling.md +97 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/remove-background.md +143 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/requirements.md +29 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/sfx.md +42 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/transcribe.md +52 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/tts-to-captions.md +35 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/references/tts.md +260 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/audio.mjs +311 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/audio.test.mjs +159 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/gemini-pipeline.test.mjs +131 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/heygen-tts.mjs +122 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/heygen-tts.test.mjs +38 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/heygen-voice.mjs +98 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/heygen-voice.test.mjs +233 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/audio-meta.mjs +39 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/audio-meta.test.mjs +136 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/bgm-volume.mjs +4 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/bgm.mjs +257 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/bgm.test.mjs +74 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/concurrency.mjs +14 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/concurrency.test.mjs +41 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-auth.mjs +43 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-auth.py +52 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-auth.test.mjs +86 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-auth_test.py +90 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-tts.mjs +122 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/gemini-tts.test.mjs +243 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/heygen.mjs +197 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/heygen.test.mjs +185 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/media-record.mjs +114 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/media-record.test.mjs +205 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/python.mjs +77 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/python.test.mjs +136 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/sfx.mjs +165 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/sfx.test.mjs +121 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/tts.mjs +389 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/tts.spawn.test.mjs +158 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lib/tts.test.mjs +230 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/lyria-recipe.py +136 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/wait-bgm.mjs +175 -0
- package/vendor/hyperframes/dist/skills/media-use/audio/scripts/wait-bgm.test.mjs +108 -0
- package/vendor/hyperframes/dist/skills/media-use/luts/README.md +28 -0
- package/vendor/hyperframes/dist/skills/media-use/luts/index.json +57 -0
- package/vendor/hyperframes/dist/skills/media-use/references/audio.md +20 -0
- package/vendor/hyperframes/dist/skills/media-use/references/grading.md +160 -0
- package/vendor/hyperframes/dist/skills/media-use/references/media-treatment-recipes.md +929 -0
- package/vendor/hyperframes/dist/skills/media-use/references/media-treatments.md +202 -0
- package/vendor/hyperframes/dist/skills/media-use/references/memory.md +37 -0
- package/vendor/hyperframes/dist/skills/media-use/references/meta.md +61 -0
- package/vendor/hyperframes/dist/skills/media-use/references/operations.md +327 -0
- package/vendor/hyperframes/dist/skills/media-use/references/resolve.md +150 -0
- package/vendor/hyperframes/dist/skills/media-use/references/setup-providers.md +80 -0
- package/vendor/hyperframes/dist/skills/media-use/references/telemetry-dashboard.md +49 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/audio-duck.mjs +113 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/compatibility.test.mjs +96 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/dither.mjs +328 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/dither.test.mjs +176 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/eval.mjs +369 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/adopt.mjs +128 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/adopt.test.mjs +95 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/bgm-provider.mjs +20 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/brand-provider.mjs +59 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/bundled-sfx-provider.mjs +119 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/bundled-sfx-provider.test.mjs +139 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cache.mjs +148 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/candidates.mjs +91 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/candidates.test.mjs +155 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/codex-provider.mjs +161 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/codex-provider.test.mjs +34 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/config-lock.d.mts +3 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/config-lock.mjs +45 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/config-lock.test.mjs +79 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/coverage.test.mjs +136 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cube-build.mjs +181 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cube-build.test.mjs +80 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cube-validate.mjs +198 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cube-validate.test.mjs +125 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cutlist.mjs +184 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/cutlist.test.mjs +162 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/duck.mjs +95 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/duck.test.mjs +153 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/error-diffusion.mjs +230 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/error-diffusion.test.mjs +102 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/ff-binaries.mjs +37 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/freeze.mjs +72 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/freeze.test.mjs +138 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/grade-analyzer.mjs +265 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/grade-analyzer.test.mjs +285 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-cli.mjs +191 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-cli.test.mjs +301 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-search.mjs +45 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-search.test.mjs +49 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-video-provider.mjs +138 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/heygen-video-provider.test.mjs +435 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/image-provider.mjs +44 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/index-gen.mjs +63 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-media-search.mjs +32 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-models.mjs +318 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-models.test.mjs +220 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-run.mjs +78 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/local-run.test.mjs +121 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/logo-provider.mjs +244 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/logo-provider.test.mjs +298 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/ltx-video-provider.mjs +94 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/ltx-video-provider.test.mjs +316 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/lut-preset-provider.mjs +271 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/lut-preset-provider.test.mjs +199 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/manifest.d.mts +19 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/manifest.mjs +279 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/manifest.test.mjs +397 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/match.mjs +47 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-fetch.mjs +85 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-fetch.test.mjs +197 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-home.mjs +20 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-home.test.mjs +61 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-search.d.mts +9 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/media-search.mjs +107 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/mflux-provider.mjs +128 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/mflux-provider.test.mjs +174 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/misses.mjs +49 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/misses.test.mjs +89 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/npx-sync.mjs +31 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/npx-sync.test.mjs +50 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/parakeet-words.mjs +27 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/parakeet-words.test.mjs +44 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/prefs-store.mjs +180 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/prefs-store.test.mjs +189 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/probe.mjs +41 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/probe.test.mjs +148 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/providers.mjs +5 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/recipe-store.mjs +367 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/recipe-store.test.mjs +367 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/registry.mjs +212 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/registry.test.mjs +262 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/search.mjs +24 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/search.test.mjs +32 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/sfx-provider.mjs +23 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/specs.mjs +132 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/specs.test.mjs +157 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/stats.mjs +117 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/stats.test.mjs +165 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/svg-sanitize.mjs +21 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/telemetry.mjs +210 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/telemetry.test.mjs +437 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/test-home.test.mjs +10 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/transcriptCutFade.mjs +21 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/transcriptCutFade.test.mjs +33 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/tts-local-provider.mjs +94 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/tts-local-provider.test.mjs +72 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/usage.mjs +57 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/usage.test.mjs +54 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/voice-provider.mjs +57 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/voice-provider.test.mjs +46 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/lib/words.mjs +18 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/prefs.mjs +70 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/recipe.mjs +103 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/resolve-plugin.test.mjs +62 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/resolve.mjs +1369 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/transcribe.mjs +194 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/transcribe.test.mjs +112 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/transcript-cut.mjs +270 -0
- package/vendor/hyperframes/dist/skills/media-use/scripts/transcript-cut.test.mjs +117 -0
- package/vendor/hyperframes/dist/skills-MJ2J4GEM.js +808 -0
- package/vendor/hyperframes/dist/skillsUpdateCheck-TKTYQN5R.js +26 -0
- package/vendor/hyperframes/dist/slideshow-EJ4IMY6P.js +24 -0
- package/vendor/hyperframes/dist/snapshot-KIVDUUMN.js +875 -0
- package/vendor/hyperframes/dist/src-6YQBJGWR.js +202 -0
- package/vendor/hyperframes/dist/src-PVYUYV3M.js +471 -0
- package/vendor/hyperframes/dist/state-KAXGHF77.js +26 -0
- package/vendor/hyperframes/dist/staticProjectServer-7EU666GS.js +49 -0
- package/vendor/hyperframes/dist/status-YM52BQ6S.js +311 -0
- package/vendor/hyperframes/dist/studio/assets/hyperframes-player-Cp8e_Zst.js +473 -0
- package/vendor/hyperframes/dist/studio/assets/index-BX3KHhGX.js +71 -0
- package/vendor/hyperframes/dist/studio/assets/index-CASEBNy2.js +1 -0
- package/vendor/hyperframes/dist/studio/assets/index-D11atkBt.css +1 -0
- package/vendor/hyperframes/dist/studio/assets/index-DMTt9nTf.js +531 -0
- package/vendor/hyperframes/dist/studio/assets/index-oE1pOdAy.js +399 -0
- package/vendor/hyperframes/dist/studio/chunk-5VSXRGIX.js +948 -0
- package/vendor/hyperframes/dist/studio/chunk-5VSXRGIX.js.map +1 -0
- package/vendor/hyperframes/dist/studio/chunk-7UQWVN52.js +938 -0
- package/vendor/hyperframes/dist/studio/chunk-7UQWVN52.js.map +1 -0
- package/vendor/hyperframes/dist/studio/chunk-EEXSYY5F.js +190 -0
- package/vendor/hyperframes/dist/studio/chunk-EEXSYY5F.js.map +1 -0
- package/vendor/hyperframes/dist/studio/chunk-FOEID72M.js +1441 -0
- package/vendor/hyperframes/dist/studio/chunk-FOEID72M.js.map +1 -0
- package/vendor/hyperframes/dist/studio/chunk-PZ5AY32C.js +10 -0
- package/vendor/hyperframes/dist/studio/chunk-PZ5AY32C.js.map +1 -0
- package/vendor/hyperframes/dist/studio/chunk-TDWGXBUT.js +1103 -0
- package/vendor/hyperframes/dist/studio/chunk-TDWGXBUT.js.map +1 -0
- package/vendor/hyperframes/dist/studio/domEditingLayers-IEVLO54Z.js +47 -0
- package/vendor/hyperframes/dist/studio/domEditingLayers-IEVLO54Z.js.map +1 -0
- package/vendor/hyperframes/dist/studio/favicon.svg +14 -0
- package/vendor/hyperframes/dist/studio/icons/timeline/audio.svg +7 -0
- package/vendor/hyperframes/dist/studio/icons/timeline/captions.svg +5 -0
- package/vendor/hyperframes/dist/studio/icons/timeline/composition.svg +12 -0
- package/vendor/hyperframes/dist/studio/icons/timeline/image.svg +18 -0
- package/vendor/hyperframes/dist/studio/icons/timeline/music.svg +10 -0
- package/vendor/hyperframes/dist/studio/icons/timeline/text.svg +3 -0
- package/vendor/hyperframes/dist/studio/index.css +165 -0
- package/vendor/hyperframes/dist/studio/index.css.map +1 -0
- package/vendor/hyperframes/dist/studio/index.d.ts +4296 -0
- package/vendor/hyperframes/dist/studio/index.html +23 -0
- package/vendor/hyperframes/dist/studio/index.js +99693 -0
- package/vendor/hyperframes/dist/studio/index.js.map +1 -0
- package/vendor/hyperframes/dist/studio/player.d.ts +30 -0
- package/vendor/hyperframes/dist/studio/player.js +10 -0
- package/vendor/hyperframes/dist/studio/player.js.map +1 -0
- package/vendor/hyperframes/dist/studio/styles/tailwind-preset.d.ts +39 -0
- package/vendor/hyperframes/dist/studio/styles/tailwind-preset.js +50 -0
- package/vendor/hyperframes/dist/studio/styles/tailwind-preset.js.map +1 -0
- package/vendor/hyperframes/dist/studio/styles.css +1 -0
- package/vendor/hyperframes/dist/studio/ui.d.ts +296 -0
- package/vendor/hyperframes/dist/studio/ui.js +66 -0
- package/vendor/hyperframes/dist/studio/ui.js.map +1 -0
- package/vendor/hyperframes/dist/studio-api-PNQZRPX5.js +136 -0
- package/vendor/hyperframes/dist/studioSelectionClient-IUUPKUHZ.js +25 -0
- package/vendor/hyperframes/dist/studioServer-UWRBPIOJ.js +1457 -0
- package/vendor/hyperframes/dist/synthesize-K62TIZWI.js +182 -0
- package/vendor/hyperframes/dist/system-EZYZNUFD.js +44 -0
- package/vendor/hyperframes/dist/telemetry-2YC4SGQU.js +144 -0
- package/vendor/hyperframes/dist/telemetry-QMYM4WME.js +95 -0
- package/vendor/hyperframes/dist/templates/_shared/AGENTS.md +107 -0
- package/vendor/hyperframes/dist/templates/_shared/CLAUDE.md +107 -0
- package/vendor/hyperframes/dist/templates/blank/index.html +55 -0
- package/vendor/hyperframes/dist/templates/from-file/index.html +75 -0
- package/vendor/hyperframes/dist/templates/warm-grain/compositions/captions.html +154 -0
- package/vendor/hyperframes/dist/templates/warm-grain/compositions/graphics.html +162 -0
- package/vendor/hyperframes/dist/templates/warm-grain/compositions/intro.html +87 -0
- package/vendor/hyperframes/dist/templates/warm-grain/index.html +264 -0
- package/vendor/hyperframes/dist/templates/warm-grain/registry-item.json +34 -0
- package/vendor/hyperframes/dist/timeline-77Z3BBQM.js +1377 -0
- package/vendor/hyperframes/dist/tokens-OBGTYE4Z.js +92 -0
- package/vendor/hyperframes/dist/transcribe-7NVFHCGA.js +387 -0
- package/vendor/hyperframes/dist/transcribe-BNSJRR4M.js +62 -0
- package/vendor/hyperframes/dist/tts-P3LIPIL5.js +234 -0
- package/vendor/hyperframes/dist/updateCheck-UDWIJ4ZQ.js +39 -0
- package/vendor/hyperframes/dist/upgrade-CT3CPO3E.js +231 -0
- package/vendor/hyperframes/dist/urlDownloader-H6WRI2UE.js +39 -0
- package/vendor/hyperframes/dist/usage-EC3KFUIJ.js +2139 -0
- package/vendor/hyperframes/dist/validate-65QDZJWZ.js +70 -0
- package/vendor/hyperframes/dist/video-FGSGKRSV.js +261 -0
- package/vendor/hyperframes/dist/workspaceBuildCheck-TOLGAI4T.js +133 -0
- package/vendor/hyperframes/package.json +80 -0
|
@@ -0,0 +1,1697 @@
|
|
|
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
|
+
rectToBbox
|
|
9
|
+
} from "./chunk-WBLXWOYK.js";
|
|
10
|
+
import {
|
|
11
|
+
loadProducer
|
|
12
|
+
} from "./chunk-3ZP5DXE7.js";
|
|
13
|
+
import {
|
|
14
|
+
trackLintRun
|
|
15
|
+
} from "./chunk-RDNNAKEP.js";
|
|
16
|
+
import {
|
|
17
|
+
assertionTargets,
|
|
18
|
+
buildLayoutSampleTimes,
|
|
19
|
+
buildTransitionSampleTimes,
|
|
20
|
+
collapseStaticLayoutIssues,
|
|
21
|
+
collectSamplingTargets,
|
|
22
|
+
dedupeLayoutIssues,
|
|
23
|
+
evaluateMotion,
|
|
24
|
+
findMotionSpec,
|
|
25
|
+
formatLayoutIssue,
|
|
26
|
+
limitLayoutIssues,
|
|
27
|
+
mergeSampleTimes,
|
|
28
|
+
parseAt,
|
|
29
|
+
readMotionSpec
|
|
30
|
+
} from "./chunk-2EGFTPWD.js";
|
|
31
|
+
import "./chunk-KBJUXVOJ.js";
|
|
32
|
+
import "./chunk-XUHOIDKG.js";
|
|
33
|
+
import "./chunk-UEZXMWG3.js";
|
|
34
|
+
import "./chunk-X7MTZ4T2.js";
|
|
35
|
+
import "./chunk-YQZNILVH.js";
|
|
36
|
+
import "./chunk-5Z63TBTX.js";
|
|
37
|
+
import "./chunk-7HG4BFIN.js";
|
|
38
|
+
import "./chunk-HRUGC23L.js";
|
|
39
|
+
import "./chunk-YEIFI443.js";
|
|
40
|
+
import "./chunk-S7NPLFWV.js";
|
|
41
|
+
import "./chunk-RMHUQGRK.js";
|
|
42
|
+
import "./chunk-EOVYQ3IG.js";
|
|
43
|
+
import "./chunk-QC4FJVLM.js";
|
|
44
|
+
import "./chunk-TCLGPL65.js";
|
|
45
|
+
import {
|
|
46
|
+
resolveProject
|
|
47
|
+
} from "./chunk-S3D6GE5W.js";
|
|
48
|
+
import "./chunk-IHFUKJOR.js";
|
|
49
|
+
import {
|
|
50
|
+
resolveLocalBrowserGpuMode
|
|
51
|
+
} from "./chunk-XS4EJSKU.js";
|
|
52
|
+
import "./chunk-PFCFR3KZ.js";
|
|
53
|
+
import "./chunk-CFKU7HTK.js";
|
|
54
|
+
import "./chunk-XT7X6QCP.js";
|
|
55
|
+
import "./chunk-4YYJOFKS.js";
|
|
56
|
+
import "./chunk-HVW7ABXD.js";
|
|
57
|
+
import "./chunk-LYNI3FOL.js";
|
|
58
|
+
import "./chunk-CWPVM2QV.js";
|
|
59
|
+
import "./chunk-A2Z4Z4VL.js";
|
|
60
|
+
import "./chunk-AWDFDFI3.js";
|
|
61
|
+
import "./chunk-P6LJ4Y32.js";
|
|
62
|
+
import "./chunk-GMECXFAN.js";
|
|
63
|
+
import "./chunk-4NWOGZZS.js";
|
|
64
|
+
import {
|
|
65
|
+
trackCheckReport,
|
|
66
|
+
trackCommandFailure
|
|
67
|
+
} from "./chunk-JTHMTOMQ.js";
|
|
68
|
+
import "./chunk-EISRN4E6.js";
|
|
69
|
+
import "./chunk-VWG7OQKU.js";
|
|
70
|
+
import {
|
|
71
|
+
c
|
|
72
|
+
} from "./chunk-ZTZA4UWZ.js";
|
|
73
|
+
import "./chunk-IUZFXWSV.js";
|
|
74
|
+
import "./chunk-AMKC3AXA.js";
|
|
75
|
+
import {
|
|
76
|
+
defineCommand,
|
|
77
|
+
parseArgs
|
|
78
|
+
} from "./chunk-S3S4TGEH.js";
|
|
79
|
+
import {
|
|
80
|
+
getRunId
|
|
81
|
+
} from "./chunk-54HJ63Q2.js";
|
|
82
|
+
import {
|
|
83
|
+
setCommandExitCode
|
|
84
|
+
} from "./chunk-PBN6GBJE.js";
|
|
85
|
+
import "./chunk-KC5XXX3X.js";
|
|
86
|
+
import "./chunk-TJSTGSAW.js";
|
|
87
|
+
import {
|
|
88
|
+
extractMediaMetadata,
|
|
89
|
+
findHdrAutoPromotion
|
|
90
|
+
} from "./chunk-K2FTXJYH.js";
|
|
91
|
+
import "./chunk-2YN64IN5.js";
|
|
92
|
+
import "./chunk-AVUUN2XD.js";
|
|
93
|
+
import "./chunk-DPVXBVLL.js";
|
|
94
|
+
import "./chunk-Z6B37SNM.js";
|
|
95
|
+
import "./chunk-HWKCIWQT.js";
|
|
96
|
+
import "./chunk-VC76R6W2.js";
|
|
97
|
+
import "./chunk-OFQWTKPW.js";
|
|
98
|
+
import "./chunk-Q5X2B5WT.js";
|
|
99
|
+
import "./chunk-TWWSYAKJ.js";
|
|
100
|
+
import {
|
|
101
|
+
lintProject,
|
|
102
|
+
resolveProjectRelativeSrc,
|
|
103
|
+
shouldBlockRender
|
|
104
|
+
} from "./chunk-ZJUKFZ2P.js";
|
|
105
|
+
import "./chunk-HBBJFK6I.js";
|
|
106
|
+
import "./chunk-PJ3HDUCY.js";
|
|
107
|
+
import "./chunk-TQFG7HTI.js";
|
|
108
|
+
import "./chunk-GK4AIFIH.js";
|
|
109
|
+
import "./chunk-2PSPARWP.js";
|
|
110
|
+
import {
|
|
111
|
+
withMeta
|
|
112
|
+
} from "./chunk-HW6OYASV.js";
|
|
113
|
+
import "./chunk-K4WIOZFP.js";
|
|
114
|
+
import "./chunk-XUXGIA7H.js";
|
|
115
|
+
import "./chunk-WERLJGIC.js";
|
|
116
|
+
import "./chunk-ISN5GRYI.js";
|
|
117
|
+
import "./chunk-FLWXXDNS.js";
|
|
118
|
+
import {
|
|
119
|
+
normalizeErrorMessage
|
|
120
|
+
} from "./chunk-KNU5COPB.js";
|
|
121
|
+
import "./chunk-3GXQPCJC.js";
|
|
122
|
+
import "./chunk-RQVDTPGD.js";
|
|
123
|
+
import "./chunk-PMRBLBUP.js";
|
|
124
|
+
import "./chunk-M2WBOQ2Q.js";
|
|
125
|
+
|
|
126
|
+
// src/utils/checkPipeline.ts
|
|
127
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
128
|
+
import { join, relative } from "path";
|
|
129
|
+
|
|
130
|
+
// src/utils/hdrPromotion.ts
|
|
131
|
+
async function bundleProjectHtml(projectDir) {
|
|
132
|
+
const { bundleToSingleHtml } = await import("./compiler-QO36EXLS.js");
|
|
133
|
+
return bundleToSingleHtml(projectDir);
|
|
134
|
+
}
|
|
135
|
+
async function collectBundledRenderMedia(html) {
|
|
136
|
+
const producer = await loadProducer();
|
|
137
|
+
if (!producer.collectRenderMedia) throw new Error("Render media collector unavailable");
|
|
138
|
+
return producer.collectRenderMedia(html);
|
|
139
|
+
}
|
|
140
|
+
var DEFAULT_DEPENDENCIES = {
|
|
141
|
+
bundleHtml: bundleProjectHtml,
|
|
142
|
+
collectMedia: collectBundledRenderMedia
|
|
143
|
+
};
|
|
144
|
+
async function inspectHdrAutoPromotion(project, extractMetadata = extractMediaMetadata, dependencies = DEFAULT_DEPENDENCIES) {
|
|
145
|
+
const assets = [];
|
|
146
|
+
const media = await dependencies.collectMedia(await dependencies.bundleHtml(project.dir));
|
|
147
|
+
for (const { src } of [...media.videos, ...media.images]) {
|
|
148
|
+
const path = /^https?:\/\//i.test(src) ? src : resolveProjectRelativeSrc(src, project.dir, project.dir);
|
|
149
|
+
try {
|
|
150
|
+
assets.push({
|
|
151
|
+
asset: src,
|
|
152
|
+
colorSpace: (await extractMetadata(path)).colorSpace
|
|
153
|
+
});
|
|
154
|
+
} catch {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return findHdrAutoPromotion(assets);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/commands/contrast-bg.ts
|
|
162
|
+
function relativeLuminance(color) {
|
|
163
|
+
const channel = (value) => {
|
|
164
|
+
const srgb = value / 255;
|
|
165
|
+
return srgb <= 0.03928 ? srgb / 12.92 : ((srgb + 0.055) / 1.055) ** 2.4;
|
|
166
|
+
};
|
|
167
|
+
return 0.2126 * channel(color[0]) + 0.7152 * channel(color[1]) + 0.0722 * channel(color[2]);
|
|
168
|
+
}
|
|
169
|
+
function contrastRatio(first, second) {
|
|
170
|
+
const firstLuminance = relativeLuminance(first);
|
|
171
|
+
const secondLuminance = relativeLuminance(second);
|
|
172
|
+
const lighter = Math.max(firstLuminance, secondLuminance);
|
|
173
|
+
const darker = Math.min(firstLuminance, secondLuminance);
|
|
174
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
175
|
+
}
|
|
176
|
+
function requiredContrastRatio(large) {
|
|
177
|
+
return large ? 3 : 4.5;
|
|
178
|
+
}
|
|
179
|
+
function suggestCompliantForegroundColor(foreground, background, requiredRatio) {
|
|
180
|
+
if (contrastRatio(foreground, background) >= requiredRatio) return [...foreground];
|
|
181
|
+
const black = [0, 0, 0];
|
|
182
|
+
const white = [255, 255, 255];
|
|
183
|
+
const target = contrastRatio(white, background) >= contrastRatio(black, background) ? white : black;
|
|
184
|
+
for (let step = 1; step <= 255; step += 1) {
|
|
185
|
+
const amount = step / 255;
|
|
186
|
+
const candidate = [
|
|
187
|
+
Math.round(foreground[0] + (target[0] - foreground[0]) * amount),
|
|
188
|
+
Math.round(foreground[1] + (target[1] - foreground[1]) * amount),
|
|
189
|
+
Math.round(foreground[2] + (target[2] - foreground[2]) * amount)
|
|
190
|
+
];
|
|
191
|
+
if (contrastRatio(candidate, background) >= requiredRatio) return candidate;
|
|
192
|
+
}
|
|
193
|
+
return [...target];
|
|
194
|
+
}
|
|
195
|
+
function parseColorRGBA(color) {
|
|
196
|
+
const body = /rgba?\(([^)]+)\)/.exec(color ?? "")?.[1];
|
|
197
|
+
if (body == null) return null;
|
|
198
|
+
const p = body.split(",").map((s) => parseFloat(s.trim()));
|
|
199
|
+
if (p.length < 3 || p.some((n) => Number.isNaN(n))) return null;
|
|
200
|
+
const [r, g, b, a] = p;
|
|
201
|
+
if (r == null || g == null || b == null) return null;
|
|
202
|
+
return [r, g, b, a ?? 1];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/utils/checkPipeline.ts
|
|
206
|
+
var MOTION_FPS = 20;
|
|
207
|
+
var MOTION_MAX_SAMPLES = 300;
|
|
208
|
+
var ZERO_BBOX = { x: 0, y: 0, width: 0, height: 0 };
|
|
209
|
+
var FRAME_BREACH_FLOOR_PX = 120;
|
|
210
|
+
var FRAME_BREACH_FLOOR_FRACTION = 0.06;
|
|
211
|
+
var DEFAULT_CHECK_OPTIONS = {
|
|
212
|
+
samples: 9,
|
|
213
|
+
atTransitions: false,
|
|
214
|
+
maxIssues: 80,
|
|
215
|
+
collapseStatic: true,
|
|
216
|
+
tolerance: 2,
|
|
217
|
+
timeout: 3e3,
|
|
218
|
+
contrast: true,
|
|
219
|
+
strict: false,
|
|
220
|
+
snapshots: false,
|
|
221
|
+
browserGpuMode: "auto"
|
|
222
|
+
};
|
|
223
|
+
function selectContrastTimes(grid) {
|
|
224
|
+
if (grid.length <= 5) return [...grid];
|
|
225
|
+
return Array.from({ length: 5 }, (_, index) => {
|
|
226
|
+
const selected = Math.floor(index * (grid.length - 1) / 4);
|
|
227
|
+
return grid[selected] ?? grid[0] ?? 0;
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
function buildMotionSampleTimes(duration) {
|
|
231
|
+
if (!Number.isFinite(duration) || duration <= 0) return [];
|
|
232
|
+
const count = Math.min(MOTION_MAX_SAMPLES, Math.max(2, Math.ceil(duration * MOTION_FPS) + 1));
|
|
233
|
+
const step = duration / (count - 1);
|
|
234
|
+
return Array.from({ length: count }, (_, index) => Math.round(index * step * 1e3) / 1e3);
|
|
235
|
+
}
|
|
236
|
+
function gateSampleTimes(duration, seeks, fallback) {
|
|
237
|
+
if (!Number.isFinite(duration) || duration <= 0) return [];
|
|
238
|
+
const fractions = seeks && seeks.length > 0 ? seeks : [fallback];
|
|
239
|
+
return mergeSampleTimes(fractions.map((fraction) => fraction * duration));
|
|
240
|
+
}
|
|
241
|
+
async function buildSampleGrid(driver, options) {
|
|
242
|
+
const duration = await driver.getDuration();
|
|
243
|
+
const baseSamples = buildLayoutSampleTimes({
|
|
244
|
+
duration,
|
|
245
|
+
samples: options.samples,
|
|
246
|
+
at: options.at
|
|
247
|
+
});
|
|
248
|
+
const transitions = options.atTransitions ? buildTransitionSampleTimes({
|
|
249
|
+
duration,
|
|
250
|
+
boundaries: await driver.getTransitionBoundaries(),
|
|
251
|
+
cap: options.maxTransitionSamples
|
|
252
|
+
}) : { times: [], dropped: 0 };
|
|
253
|
+
const captionSamples = options.captionZone ? gateSampleTimes(duration, options.captionZone.seek, 1) : [];
|
|
254
|
+
const frameSamples = options.frameCheck ? gateSampleTimes(duration, options.frameCheck.seek, 0.5) : [];
|
|
255
|
+
const auditSamples = mergeSampleTimes(baseSamples, transitions.times);
|
|
256
|
+
const layoutSamples = mergeSampleTimes(auditSamples, captionSamples, frameSamples);
|
|
257
|
+
if (layoutSamples.length === 0) {
|
|
258
|
+
throw new Error("Could not determine composition duration \u2014 no layout samples run");
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
duration,
|
|
262
|
+
layoutSamples,
|
|
263
|
+
userPickedSamples: options.at?.length ? baseSamples : [],
|
|
264
|
+
captionSamples,
|
|
265
|
+
frameSamples,
|
|
266
|
+
transitionSamples: transitions.times,
|
|
267
|
+
transitionSamplesDropped: transitions.dropped,
|
|
268
|
+
contrastSamples: options.contrast ? selectContrastTimes(auditSamples) : []
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
async function planMotionSampling(driver, motion, duration) {
|
|
272
|
+
if (motion.kind !== "valid") {
|
|
273
|
+
return { times: [], selectors: [], livenessScopes: [], preflightIssues: [], assertions: [] };
|
|
274
|
+
}
|
|
275
|
+
const preflightIssues = await driver.findAmbiguousSelectors(
|
|
276
|
+
collectSamplingTargets(motion.spec.assertions).selectors
|
|
277
|
+
);
|
|
278
|
+
const ambiguous = new Set(preflightIssues.map((issue) => issue.selector));
|
|
279
|
+
const assertions = motion.spec.assertions.filter(
|
|
280
|
+
(assertion) => !assertionTargets(assertion).selectors.some((selector) => ambiguous.has(selector))
|
|
281
|
+
);
|
|
282
|
+
noteSkippedAssertions(preflightIssues, motion.spec.assertions);
|
|
283
|
+
const targets = collectSamplingTargets(assertions);
|
|
284
|
+
const times = assertions.length > 0 ? buildMotionSampleTimes(motion.spec.duration ?? duration) : [];
|
|
285
|
+
return { times, ...targets, preflightIssues, assertions };
|
|
286
|
+
}
|
|
287
|
+
function noteSkippedAssertions(issues, assertions) {
|
|
288
|
+
for (const issue of issues) {
|
|
289
|
+
const skipped = assertions.filter(
|
|
290
|
+
(assertion) => assertionTargets(assertion).selectors.includes(issue.selector)
|
|
291
|
+
).length;
|
|
292
|
+
if (skipped > 0) issue.message += ` ${skipped} assertion(s) naming it were not evaluated.`;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function geometryRequest(time, grid, options) {
|
|
296
|
+
const text = grid.captionSamples.includes(time);
|
|
297
|
+
const media = grid.frameSamples.includes(time);
|
|
298
|
+
if (!text && !media) return null;
|
|
299
|
+
const configuredTolerance = options.frameCheck?.tol;
|
|
300
|
+
const tolerance = typeof configuredTolerance === "number" ? configuredTolerance : 2;
|
|
301
|
+
return { text, media, tolerance };
|
|
302
|
+
}
|
|
303
|
+
function candidateIsSized(candidate, canvas) {
|
|
304
|
+
if (candidate.elementRect.width < 4 || candidate.elementRect.height < 4) return false;
|
|
305
|
+
return !(candidate.elementRect.width >= 0.95 * canvas.width && candidate.elementRect.height >= 0.95 * canvas.height);
|
|
306
|
+
}
|
|
307
|
+
function geometryIssueAnchor(candidate, time) {
|
|
308
|
+
return {
|
|
309
|
+
selector: candidate.selector,
|
|
310
|
+
dataAttributes: candidate.dataAttributes,
|
|
311
|
+
sourceFile: candidate.sourceFile,
|
|
312
|
+
bbox: candidate.bbox,
|
|
313
|
+
time,
|
|
314
|
+
rect: candidate.rect
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function captionBoxOverlapsZone(box, zone, canvas) {
|
|
318
|
+
const zx0 = zone.x0 * canvas.width;
|
|
319
|
+
const zy0 = zone.y0 * canvas.height;
|
|
320
|
+
const zx1 = zone.x1 * canvas.width;
|
|
321
|
+
const zy1 = zone.y1 * canvas.height;
|
|
322
|
+
const bx1 = box.left + box.width;
|
|
323
|
+
const by1 = box.top + box.height;
|
|
324
|
+
const overlaps = box.left < zx1 && bx1 > zx0 && box.top < zy1 && by1 > zy0;
|
|
325
|
+
return { overlaps, cy: box.top + box.height / 2 };
|
|
326
|
+
}
|
|
327
|
+
function captionFinding(candidate, options, canvas, time) {
|
|
328
|
+
const zone = options.captionZone;
|
|
329
|
+
if (!zone || candidate.kind !== "text" || !candidateIsSized(candidate, canvas)) return null;
|
|
330
|
+
if ("data-layout-allow-caption-zone" in candidate.dataAttributes) return null;
|
|
331
|
+
const { overlaps, cy } = captionBoxOverlapsZone(candidate.elementRect, zone, canvas);
|
|
332
|
+
if (!overlaps) return null;
|
|
333
|
+
const text = candidate.text.slice(0, 48);
|
|
334
|
+
const pctFromBottom = Math.round((canvas.height - cy) / canvas.height * 100);
|
|
335
|
+
return {
|
|
336
|
+
key: `${candidate.tag}|${text}`,
|
|
337
|
+
issue: {
|
|
338
|
+
...geometryIssueAnchor(candidate, time),
|
|
339
|
+
code: "caption_zone_collision",
|
|
340
|
+
severity: zone.severity === "error" ? "error" : "warning",
|
|
341
|
+
text,
|
|
342
|
+
message: `<${candidate.tag}> "${text}" overlaps the reserved caption band (~${pctFromBottom}% up from the bottom).`,
|
|
343
|
+
fixHint: "Keep main content outside the configured caption band, or mark intentional lower-third copy with data-layout-allow-caption-zone."
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
function maxOverflow(candidate) {
|
|
348
|
+
if (!candidate.overflow) return 0;
|
|
349
|
+
return Math.max(
|
|
350
|
+
candidate.overflow.left ?? 0,
|
|
351
|
+
candidate.overflow.top ?? 0,
|
|
352
|
+
candidate.overflow.right ?? 0,
|
|
353
|
+
candidate.overflow.bottom ?? 0
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
function overflowMessage(candidate) {
|
|
357
|
+
const overflow = candidate.overflow ?? {};
|
|
358
|
+
const edges = [];
|
|
359
|
+
if (overflow.left) edges.push(`${overflow.left}px past the left`);
|
|
360
|
+
if (overflow.top) edges.push(`${overflow.top}px past the top`);
|
|
361
|
+
if (overflow.right) edges.push(`${overflow.right}px past the right`);
|
|
362
|
+
if (overflow.bottom) edges.push(`${overflow.bottom}px past the bottom`);
|
|
363
|
+
return `<${candidate.tag}> "${candidate.text.slice(0, 48)}" spills outside the frame (${edges.join(", ")}).`;
|
|
364
|
+
}
|
|
365
|
+
function frameFinding(candidate, options, canvas, time) {
|
|
366
|
+
if (!options.frameCheck || candidate.kind !== "media" || !candidateIsSized(candidate, canvas)) {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
const floor = Math.max(
|
|
370
|
+
FRAME_BREACH_FLOOR_PX,
|
|
371
|
+
FRAME_BREACH_FLOOR_FRACTION * Math.min(canvas.width, canvas.height)
|
|
372
|
+
);
|
|
373
|
+
if (maxOverflow(candidate) < floor) return null;
|
|
374
|
+
const text = candidate.text.slice(0, 48);
|
|
375
|
+
return {
|
|
376
|
+
key: `${candidate.tag}|${text}|${Math.round(candidate.rect.left)},${Math.round(candidate.rect.top)}`,
|
|
377
|
+
issue: {
|
|
378
|
+
...geometryIssueAnchor(candidate, time),
|
|
379
|
+
code: "frame_out_of_frame",
|
|
380
|
+
severity: options.frameCheck.severity === "error" ? "error" : "warning",
|
|
381
|
+
text,
|
|
382
|
+
overflow: candidate.overflow,
|
|
383
|
+
message: overflowMessage(candidate),
|
|
384
|
+
fixHint: "Keep media within the composition frame's safe area."
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function appendGeometryFinding(result, seen, issues) {
|
|
389
|
+
if (!result || seen.has(result.key)) return;
|
|
390
|
+
seen.add(result.key);
|
|
391
|
+
issues.push(result.issue);
|
|
392
|
+
}
|
|
393
|
+
async function collectGeometryAt(driver, options, grid, canvas, time, seen) {
|
|
394
|
+
const request = geometryRequest(time, grid, options);
|
|
395
|
+
if (!request) return [];
|
|
396
|
+
const candidates = await driver.collectGeometryCandidates(time, request);
|
|
397
|
+
const issues = [];
|
|
398
|
+
for (const candidate of candidates) {
|
|
399
|
+
if (request.text) {
|
|
400
|
+
appendGeometryFinding(captionFinding(candidate, options, canvas, time), seen.caption, issues);
|
|
401
|
+
}
|
|
402
|
+
if (request.media) {
|
|
403
|
+
appendGeometryFinding(frameFinding(candidate, options, canvas, time), seen.frame, issues);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return issues;
|
|
407
|
+
}
|
|
408
|
+
async function collectGridSamples(driver, options, grid, motion) {
|
|
409
|
+
const layoutSet = new Set(grid.layoutSamples);
|
|
410
|
+
const motionSet = new Set(motion.times);
|
|
411
|
+
const contrastSet = new Set(grid.contrastSamples);
|
|
412
|
+
const geometryEnabled = grid.captionSamples.length > 0 || grid.frameSamples.length > 0;
|
|
413
|
+
const canvas = geometryEnabled ? await driver.getCanvas() : null;
|
|
414
|
+
const geometrySeen = { caption: /* @__PURE__ */ new Set(), frame: /* @__PURE__ */ new Set() };
|
|
415
|
+
const collected = {
|
|
416
|
+
layoutIssues: [],
|
|
417
|
+
motionFrames: [],
|
|
418
|
+
contrastEntries: [],
|
|
419
|
+
screenshots: [],
|
|
420
|
+
contrastMs: 0,
|
|
421
|
+
layoutStateSignatures: [],
|
|
422
|
+
rotationSamples: [],
|
|
423
|
+
indicatorFrames: []
|
|
424
|
+
};
|
|
425
|
+
for (const time of mergeSampleTimes(grid.layoutSamples, motion.times)) {
|
|
426
|
+
await driver.seek(time);
|
|
427
|
+
const issuesAtTime = [];
|
|
428
|
+
if (layoutSet.has(time)) {
|
|
429
|
+
const layoutIssues = await driver.collectLayout(time, options.tolerance, options.layout);
|
|
430
|
+
collected.layoutIssues.push(...layoutIssues);
|
|
431
|
+
issuesAtTime.push(...layoutIssues);
|
|
432
|
+
collected.layoutStateSignatures.push({
|
|
433
|
+
time,
|
|
434
|
+
signature: await driver.collectLayoutGeometry()
|
|
435
|
+
});
|
|
436
|
+
collected.rotationSamples.push(...await driver.collectRotationSample(time));
|
|
437
|
+
collected.indicatorFrames.push(await driver.collectOffPivotRotationSample(time));
|
|
438
|
+
}
|
|
439
|
+
if (canvas) {
|
|
440
|
+
const geometryIssues = await collectGeometryAt(
|
|
441
|
+
driver,
|
|
442
|
+
options,
|
|
443
|
+
grid,
|
|
444
|
+
canvas,
|
|
445
|
+
time,
|
|
446
|
+
geometrySeen
|
|
447
|
+
);
|
|
448
|
+
collected.layoutIssues.push(...geometryIssues);
|
|
449
|
+
issuesAtTime.push(...geometryIssues);
|
|
450
|
+
}
|
|
451
|
+
if (motionSet.has(time)) {
|
|
452
|
+
collected.motionFrames.push(
|
|
453
|
+
await driver.collectMotionFrame(time, motion.selectors, motion.livenessScopes)
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
if (contrastSet.has(time)) {
|
|
457
|
+
const contrastStart = Date.now();
|
|
458
|
+
const capture = options.snapshots ? await driver.collectContrast(time, annotationBoxesFrom(issuesAtTime)) : await driver.collectContrast(time);
|
|
459
|
+
collected.contrastMs += Date.now() - contrastStart;
|
|
460
|
+
collected.contrastEntries.push(...capture.entries);
|
|
461
|
+
collected.screenshots.push({ time, pngBase64: capture.pngBase64 });
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
await collectMotionOverlapSamples(driver, grid, collected);
|
|
465
|
+
return collected;
|
|
466
|
+
}
|
|
467
|
+
var OVERLAP_SAMPLE_FPS = 8;
|
|
468
|
+
var OVERLAP_MAX_SAMPLES = 600;
|
|
469
|
+
function buildOverlapSampleTimes(duration) {
|
|
470
|
+
if (!Number.isFinite(duration) || duration <= 0) return [];
|
|
471
|
+
const count = Math.min(
|
|
472
|
+
OVERLAP_MAX_SAMPLES,
|
|
473
|
+
Math.max(2, Math.ceil(duration * OVERLAP_SAMPLE_FPS) + 1)
|
|
474
|
+
);
|
|
475
|
+
const step = duration / (count - 1);
|
|
476
|
+
return mergeSampleTimes(
|
|
477
|
+
Array.from({ length: count }, (_, index) => Math.round(index * step * 1e3) / 1e3)
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
async function collectMotionOverlapSamples(driver, grid, collected) {
|
|
481
|
+
const baseTimes = new Set(grid.layoutSamples);
|
|
482
|
+
for (const time of buildOverlapSampleTimes(grid.duration)) {
|
|
483
|
+
if (baseTimes.has(time)) continue;
|
|
484
|
+
await driver.seekGeometry(time);
|
|
485
|
+
collected.layoutIssues.push(...await driver.collectOverlap(time));
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
var SWEEP_STATIC_MIN_DURATION_SEC = 3;
|
|
489
|
+
var ZERO_LAYOUT_RECT = {
|
|
490
|
+
left: 0,
|
|
491
|
+
top: 0,
|
|
492
|
+
right: 0,
|
|
493
|
+
bottom: 0,
|
|
494
|
+
width: 0,
|
|
495
|
+
height: 0
|
|
496
|
+
};
|
|
497
|
+
function detectSweepStatic(duration, layoutStateSignatures, motionIssues, hasNoTimelineDeclaration) {
|
|
498
|
+
if (hasNoTimelineDeclaration) return [];
|
|
499
|
+
if (duration < SWEEP_STATIC_MIN_DURATION_SEC) return [];
|
|
500
|
+
if (layoutStateSignatures.length < 2) return [];
|
|
501
|
+
if (motionIssues.some((issue) => issue.code === "motion_frozen")) return [];
|
|
502
|
+
const [first, ...rest] = layoutStateSignatures;
|
|
503
|
+
if (!first || rest.some((signature) => signature !== first)) return [];
|
|
504
|
+
return [
|
|
505
|
+
{
|
|
506
|
+
code: "sweep_static",
|
|
507
|
+
severity: "error",
|
|
508
|
+
time: 0,
|
|
509
|
+
selector: "[data-composition-id]",
|
|
510
|
+
dataAttributes: {},
|
|
511
|
+
sourceFile: "index.html",
|
|
512
|
+
bbox: ZERO_BBOX,
|
|
513
|
+
rect: ZERO_LAYOUT_RECT,
|
|
514
|
+
message: "Timeline did not advance under seek; every green verdict on this run is unreliable.",
|
|
515
|
+
fixHint: "Confirm the composition seeks a paused GSAP/CSS timeline under `data-*` timing attributes rather than only autoplaying."
|
|
516
|
+
}
|
|
517
|
+
];
|
|
518
|
+
}
|
|
519
|
+
var ROTATION_MIN_SAMPLES = 3;
|
|
520
|
+
var ROTATION_MIN_ANGLE_SPREAD_DEG = 20;
|
|
521
|
+
var ROTATION_MAX_SIZE_RATIO = 1.6;
|
|
522
|
+
var ROTATION_RIGID_AABB_RATIO = 1.15;
|
|
523
|
+
var ROTATION_RIGID_ESTIMATE_MIN_DET = 0.15;
|
|
524
|
+
var ROTATION_MIN_MEDIAN_AREA_PX = 2500;
|
|
525
|
+
var ROTATION_DRIFT_SIZE_FRACTION = 0.1;
|
|
526
|
+
var ROTATION_DRIFT_VIEWPORT_FRACTION = 0.02;
|
|
527
|
+
function median(values) {
|
|
528
|
+
if (values.length === 0) return 0;
|
|
529
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
530
|
+
const mid = Math.floor(sorted.length / 2);
|
|
531
|
+
const upper = sorted[mid] ?? 0;
|
|
532
|
+
return sorted.length % 2 === 0 ? ((sorted[mid - 1] ?? 0) + upper) / 2 : upper;
|
|
533
|
+
}
|
|
534
|
+
function maxAngleSpread(angles) {
|
|
535
|
+
let max = 0;
|
|
536
|
+
for (let i = 0; i < angles.length; i++) {
|
|
537
|
+
const a = angles[i];
|
|
538
|
+
if (a === void 0) continue;
|
|
539
|
+
for (let j = i + 1; j < angles.length; j++) {
|
|
540
|
+
const b = angles[j];
|
|
541
|
+
if (b === void 0) continue;
|
|
542
|
+
const raw = Math.abs(a - b) % 360;
|
|
543
|
+
max = Math.max(max, Math.min(raw, 360 - raw));
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return max;
|
|
547
|
+
}
|
|
548
|
+
function maxCenterDrift(samples) {
|
|
549
|
+
let max = 0;
|
|
550
|
+
for (let i = 0; i < samples.length; i++) {
|
|
551
|
+
const first = samples[i];
|
|
552
|
+
if (!first) continue;
|
|
553
|
+
for (let j = i + 1; j < samples.length; j++) {
|
|
554
|
+
const second = samples[j];
|
|
555
|
+
if (!second) continue;
|
|
556
|
+
max = Math.max(max, Math.hypot(first.cx - second.cx, first.cy - second.cy));
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return max;
|
|
560
|
+
}
|
|
561
|
+
function rotationDriftFinding(samples, drift) {
|
|
562
|
+
const last = samples[samples.length - 1];
|
|
563
|
+
if (!last) return null;
|
|
564
|
+
const rect = {
|
|
565
|
+
left: last.cx - last.w / 2,
|
|
566
|
+
top: last.cy - last.h / 2,
|
|
567
|
+
right: last.cx + last.w / 2,
|
|
568
|
+
bottom: last.cy + last.h / 2,
|
|
569
|
+
width: last.w,
|
|
570
|
+
height: last.h
|
|
571
|
+
};
|
|
572
|
+
return {
|
|
573
|
+
code: "rotation_pivot_drift",
|
|
574
|
+
// EF promotes this to error separately; keep it a warning here.
|
|
575
|
+
severity: "warning",
|
|
576
|
+
time: last.time,
|
|
577
|
+
selector: last.selector,
|
|
578
|
+
dataAttributes: {},
|
|
579
|
+
sourceFile: "index.html",
|
|
580
|
+
bbox: rectToBbox(rect),
|
|
581
|
+
rect,
|
|
582
|
+
message: `Rotating element's bounding-box center drifts ${Math.round(drift)}px across rotation \u2014 it is not spinning about its own center (check transformOrigin/svgOrigin).`,
|
|
583
|
+
fixHint: "The bounding-box center should stay fixed while the element spins; check its transformOrigin/svgOrigin so rotation pivots about the element's own center rather than a point in a coordinate space it was resized out of."
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function groupBy(items, keyOf) {
|
|
587
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
588
|
+
for (const item of items) {
|
|
589
|
+
const group = byKey.get(keyOf(item));
|
|
590
|
+
if (group) group.push(item);
|
|
591
|
+
else byKey.set(keyOf(item), [item]);
|
|
592
|
+
}
|
|
593
|
+
return byKey;
|
|
594
|
+
}
|
|
595
|
+
function groupBySelector(samples) {
|
|
596
|
+
return groupBy(samples, (sample) => sample.selector);
|
|
597
|
+
}
|
|
598
|
+
function hasEnoughRotationSamples(group) {
|
|
599
|
+
return group.length >= ROTATION_MIN_SAMPLES;
|
|
600
|
+
}
|
|
601
|
+
function isActuallySpinning(group) {
|
|
602
|
+
return maxAngleSpread(group.map((s) => s.angle)) > ROTATION_MIN_ANGLE_SPREAD_DEG;
|
|
603
|
+
}
|
|
604
|
+
function aabbForRotatedRect(elemW, elemH, angleDeg) {
|
|
605
|
+
const rad = angleDeg * Math.PI / 180;
|
|
606
|
+
const cosAbs = Math.abs(Math.cos(rad));
|
|
607
|
+
const sinAbs = Math.abs(Math.sin(rad));
|
|
608
|
+
return { w: elemW * cosAbs + elemH * sinAbs, h: elemW * sinAbs + elemH * cosAbs };
|
|
609
|
+
}
|
|
610
|
+
function unrotatedSizeFromSample(sample) {
|
|
611
|
+
const rad = sample.angle * Math.PI / 180;
|
|
612
|
+
const cosAbs = Math.abs(Math.cos(rad));
|
|
613
|
+
const sinAbs = Math.abs(Math.sin(rad));
|
|
614
|
+
const det = cosAbs * cosAbs - sinAbs * sinAbs;
|
|
615
|
+
if (Math.abs(det) < ROTATION_RIGID_ESTIMATE_MIN_DET) return null;
|
|
616
|
+
const elemW = (cosAbs * sample.w - sinAbs * sample.h) / det;
|
|
617
|
+
const elemH = (cosAbs * sample.h - sinAbs * sample.w) / det;
|
|
618
|
+
if (!(elemW > 0) || !(elemH > 0)) return null;
|
|
619
|
+
return { w: elemW, h: elemH };
|
|
620
|
+
}
|
|
621
|
+
function aabbMatchesSample(expected, sample) {
|
|
622
|
+
if (expected.w <= 0 || expected.h <= 0 || sample.w <= 0 || sample.h <= 0) return false;
|
|
623
|
+
return Math.max(expected.w, sample.w) / Math.min(expected.w, sample.w) <= ROTATION_RIGID_AABB_RATIO && Math.max(expected.h, sample.h) / Math.min(expected.h, sample.h) <= ROTATION_RIGID_AABB_RATIO;
|
|
624
|
+
}
|
|
625
|
+
function isSingularRotationAngle(angleDeg) {
|
|
626
|
+
const rad = angleDeg * Math.PI / 180;
|
|
627
|
+
const cosAbs = Math.abs(Math.cos(rad));
|
|
628
|
+
const sinAbs = Math.abs(Math.sin(rad));
|
|
629
|
+
return Math.abs(cosAbs * cosAbs - sinAbs * sinAbs) < ROTATION_RIGID_ESTIMATE_MIN_DET;
|
|
630
|
+
}
|
|
631
|
+
function isNearSquareAabb(sample) {
|
|
632
|
+
if (sample.w <= 0 || sample.h <= 0) return false;
|
|
633
|
+
return Math.max(sample.w, sample.h) / Math.min(sample.w, sample.h) <= ROTATION_RIGID_AABB_RATIO;
|
|
634
|
+
}
|
|
635
|
+
function fitsSingularPhaseRigidProjection(group) {
|
|
636
|
+
if (group.length === 0 || !group.every((s) => isSingularRotationAngle(s.angle))) return false;
|
|
637
|
+
if (!group.every(isNearSquareAabb)) return false;
|
|
638
|
+
const ref = group[0];
|
|
639
|
+
if (!ref) return false;
|
|
640
|
+
return group.every((sample) => aabbMatchesSample({ w: ref.w, h: ref.h }, sample));
|
|
641
|
+
}
|
|
642
|
+
function fitsOneRigidRectangle(group) {
|
|
643
|
+
for (const ref of group) {
|
|
644
|
+
const size = unrotatedSizeFromSample(ref);
|
|
645
|
+
if (!size) continue;
|
|
646
|
+
if (group.every(
|
|
647
|
+
(sample) => aabbMatchesSample(aabbForRotatedRect(size.w, size.h, sample.angle), sample)
|
|
648
|
+
)) {
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return fitsSingularPhaseRigidProjection(group);
|
|
653
|
+
}
|
|
654
|
+
function isRotationSizeStable(group) {
|
|
655
|
+
if (group.some((s) => s.w <= 0 || s.h <= 0)) return false;
|
|
656
|
+
const longSides = group.map((s) => Math.max(s.w, s.h));
|
|
657
|
+
const minLong = Math.min(...longSides);
|
|
658
|
+
if (minLong <= 0) return false;
|
|
659
|
+
if (Math.max(...longSides) / minLong > ROTATION_MAX_SIZE_RATIO) return false;
|
|
660
|
+
return fitsOneRigidRectangle(group);
|
|
661
|
+
}
|
|
662
|
+
function isSizableRotation(group) {
|
|
663
|
+
return median(group.map((s) => s.w * s.h)) >= ROTATION_MIN_MEDIAN_AREA_PX;
|
|
664
|
+
}
|
|
665
|
+
function isRotationDriftCandidate(group) {
|
|
666
|
+
return hasEnoughRotationSamples(group) && isActuallySpinning(group) && isRotationSizeStable(group) && isSizableRotation(group);
|
|
667
|
+
}
|
|
668
|
+
function detectRotationPivotDrift(samples, canvas) {
|
|
669
|
+
const findings = [];
|
|
670
|
+
const viewportFloor = ROTATION_DRIFT_VIEWPORT_FRACTION * Math.min(canvas.width, canvas.height);
|
|
671
|
+
for (const group of groupBySelector(samples).values()) {
|
|
672
|
+
if (!isRotationDriftCandidate(group)) continue;
|
|
673
|
+
const medianSize = median(group.map((s) => Math.max(s.w, s.h)));
|
|
674
|
+
const threshold = Math.max(ROTATION_DRIFT_SIZE_FRACTION * medianSize, viewportFloor);
|
|
675
|
+
const drift = maxCenterDrift(group);
|
|
676
|
+
if (drift <= threshold) continue;
|
|
677
|
+
const finding = rotationDriftFinding(group, drift);
|
|
678
|
+
if (finding) findings.push(finding);
|
|
679
|
+
}
|
|
680
|
+
return findings;
|
|
681
|
+
}
|
|
682
|
+
var INDICATOR_MIN_SAMPLES = 5;
|
|
683
|
+
var INDICATOR_MIN_ANGLE_SPREAD_DEG = 20;
|
|
684
|
+
var INDICATOR_MIN_HUB_CIRCLES = 2;
|
|
685
|
+
var INDICATOR_MAX_FIT_RESIDUAL_FRACTION = 0.05;
|
|
686
|
+
var INDICATOR_MAX_RIGID_LEN_VARIATION = 0.15;
|
|
687
|
+
var INDICATOR_DRIFT_LENGTH_FRACTION = 0.35;
|
|
688
|
+
function fitCircle(points) {
|
|
689
|
+
const count = points.length;
|
|
690
|
+
if (count < 3) return null;
|
|
691
|
+
const meanX = points.reduce((sum, p) => sum + p.x, 0) / count;
|
|
692
|
+
const meanY = points.reduce((sum, p) => sum + p.y, 0) / count;
|
|
693
|
+
let suu = 0;
|
|
694
|
+
let svv = 0;
|
|
695
|
+
let suv = 0;
|
|
696
|
+
let suuu = 0;
|
|
697
|
+
let svvv = 0;
|
|
698
|
+
let suvv = 0;
|
|
699
|
+
let svuu = 0;
|
|
700
|
+
for (const point of points) {
|
|
701
|
+
const u = point.x - meanX;
|
|
702
|
+
const v = point.y - meanY;
|
|
703
|
+
suu += u * u;
|
|
704
|
+
svv += v * v;
|
|
705
|
+
suv += u * v;
|
|
706
|
+
suuu += u * u * u;
|
|
707
|
+
svvv += v * v * v;
|
|
708
|
+
suvv += u * v * v;
|
|
709
|
+
svuu += v * u * u;
|
|
710
|
+
}
|
|
711
|
+
const determinant = suu * svv - suv * suv;
|
|
712
|
+
if (Math.abs(determinant) < 1e-6) return null;
|
|
713
|
+
const rhsU = (suuu + suvv) / 2;
|
|
714
|
+
const rhsV = (svvv + svuu) / 2;
|
|
715
|
+
const uc = (rhsU * svv - rhsV * suv) / determinant;
|
|
716
|
+
const vc = (rhsV * suu - rhsU * suv) / determinant;
|
|
717
|
+
const cx = uc + meanX;
|
|
718
|
+
const cy = vc + meanY;
|
|
719
|
+
const radius = Math.sqrt(uc * uc + vc * vc + (suu + svv) / count);
|
|
720
|
+
let squaredError = 0;
|
|
721
|
+
for (const point of points) {
|
|
722
|
+
const delta = Math.hypot(point.x - cx, point.y - cy) - radius;
|
|
723
|
+
squaredError += delta * delta;
|
|
724
|
+
}
|
|
725
|
+
return { cx, cy, radius, residual: Math.sqrt(squaredError / count) };
|
|
726
|
+
}
|
|
727
|
+
var INDICATOR_MIN_HUB_PRESENCE_FRACTION = 0.6;
|
|
728
|
+
function resolveHub(group) {
|
|
729
|
+
const present = group.filter(
|
|
730
|
+
(s) => s.hx !== null && s.hy !== null && s.hubCount >= INDICATOR_MIN_HUB_CIRCLES
|
|
731
|
+
);
|
|
732
|
+
if (present.length < INDICATOR_MIN_HUB_PRESENCE_FRACTION * group.length) return null;
|
|
733
|
+
const hx = median(present.map((s) => s.hx));
|
|
734
|
+
const hy = median(present.map((s) => s.hy));
|
|
735
|
+
return { hx, hy };
|
|
736
|
+
}
|
|
737
|
+
function isRigidBody(group) {
|
|
738
|
+
const lengths = group.map((s) => s.len).filter((len) => len > 0);
|
|
739
|
+
if (lengths.length < group.length) return false;
|
|
740
|
+
const mid = median(lengths);
|
|
741
|
+
if (mid <= 0) return false;
|
|
742
|
+
const spread = Math.max(...lengths) - Math.min(...lengths);
|
|
743
|
+
return spread <= INDICATOR_MAX_RIGID_LEN_VARIATION * mid;
|
|
744
|
+
}
|
|
745
|
+
function recoverPivot(group) {
|
|
746
|
+
if (group.length < INDICATOR_MIN_SAMPLES) return null;
|
|
747
|
+
const endpointA = group.map((s) => ({ x: s.ax, y: s.ay }));
|
|
748
|
+
const endpointB = group.map((s) => ({ x: s.bx, y: s.by }));
|
|
749
|
+
const fits = [fitCircle(endpointA), fitCircle(endpointB)].filter(
|
|
750
|
+
(fit) => fit !== null
|
|
751
|
+
);
|
|
752
|
+
if (fits.length === 0) return null;
|
|
753
|
+
const best = fits.reduce((widest, fit) => fit.radius > widest.radius ? fit : widest);
|
|
754
|
+
if (best.radius <= 0) return null;
|
|
755
|
+
if (best.residual > INDICATOR_MAX_FIT_RESIDUAL_FRACTION * best.radius) return null;
|
|
756
|
+
return best;
|
|
757
|
+
}
|
|
758
|
+
function offPivotRotationFinding(group, drift) {
|
|
759
|
+
const last = group[group.length - 1];
|
|
760
|
+
if (!last) return null;
|
|
761
|
+
const rect = {
|
|
762
|
+
left: Math.min(last.ax, last.bx) - 4,
|
|
763
|
+
top: Math.min(last.ay, last.by) - 4,
|
|
764
|
+
right: Math.max(last.ax, last.bx) + 4,
|
|
765
|
+
bottom: Math.max(last.ay, last.by) + 4,
|
|
766
|
+
width: Math.abs(last.bx - last.ax) + 8,
|
|
767
|
+
height: Math.abs(last.by - last.ay) + 8
|
|
768
|
+
};
|
|
769
|
+
return {
|
|
770
|
+
code: "off_pivot_rotation",
|
|
771
|
+
severity: "warning",
|
|
772
|
+
time: last.time,
|
|
773
|
+
selector: last.selector,
|
|
774
|
+
dataAttributes: {},
|
|
775
|
+
sourceFile: "index.html",
|
|
776
|
+
bbox: rectToBbox(rect),
|
|
777
|
+
rect,
|
|
778
|
+
message: `Gauge/dial pointer rotates about a point ${Math.round(drift)}px from the dial hub \u2014 its center-of-rotation is off the hub, so it points wrong or overshoots the track (check the rotating group's pivot: translate to the hub before rotate, or set svgOrigin/transform-origin to the hub).`,
|
|
779
|
+
fixHint: "The pointer's center-of-rotation must coincide with the dial hub. Rotate the group about the hub (e.g. transform-origin/svgOrigin set to the hub center, or translate the group so its rotation pivot lands on the hub) rather than about the element's own bbox center."
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
function countAngularBodies(angles) {
|
|
783
|
+
const clusters = [];
|
|
784
|
+
for (const angle of angles) {
|
|
785
|
+
if (!clusters.some((rep) => Math.min(Math.abs(angle - rep), 360 - Math.abs(angle - rep)) <= 25)) {
|
|
786
|
+
clusters.push(angle);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return clusters.length;
|
|
790
|
+
}
|
|
791
|
+
function angleAboutHub(group, hub) {
|
|
792
|
+
const midX = median(group.map((s) => (s.ax + s.bx) / 2));
|
|
793
|
+
const midY = median(group.map((s) => (s.ay + s.by) / 2));
|
|
794
|
+
return Math.atan2(midY - hub.hy, midX - hub.hx) * 180 / Math.PI;
|
|
795
|
+
}
|
|
796
|
+
function buildIndicatorCandidate(group) {
|
|
797
|
+
if (group.length < INDICATOR_MIN_SAMPLES) return null;
|
|
798
|
+
if (maxAngleSpread(group.map((s) => s.angle)) <= INDICATOR_MIN_ANGLE_SPREAD_DEG) return null;
|
|
799
|
+
const hub = resolveHub(group);
|
|
800
|
+
if (!hub) return null;
|
|
801
|
+
if (!isRigidBody(group)) return null;
|
|
802
|
+
const pivot = recoverPivot(group);
|
|
803
|
+
if (!pivot) return null;
|
|
804
|
+
const drift = Math.hypot(pivot.cx - hub.hx, pivot.cy - hub.hy);
|
|
805
|
+
const length = median(group.map((s) => s.len));
|
|
806
|
+
const eligible = drift > INDICATOR_DRIFT_LENGTH_FRACTION * length;
|
|
807
|
+
return {
|
|
808
|
+
// Scoped-known blind spot: hubs bucketed by rounded screen coords, so two
|
|
809
|
+
// separate dials whose screen hubs land in the same 5px bucket merge into
|
|
810
|
+
// one multi-body group (rare — distinct dials stacked at ~identical screen
|
|
811
|
+
// position). Key by owning <svg> identity if that pattern shows up.
|
|
812
|
+
hubKey: `${Math.round(hub.hx / 5)}:${Math.round(hub.hy / 5)}`,
|
|
813
|
+
angleAboutHub: angleAboutHub(group, hub),
|
|
814
|
+
drift,
|
|
815
|
+
length,
|
|
816
|
+
finding: eligible ? offPivotRotationFinding(group, drift) : null
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
function selectHubFindings(candidates) {
|
|
820
|
+
const byHub = groupBy(candidates, (candidate) => candidate.hubKey);
|
|
821
|
+
const findings = [];
|
|
822
|
+
for (const group of byHub.values()) {
|
|
823
|
+
const eligible = group.filter((c2) => c2.finding !== null);
|
|
824
|
+
if (countAngularBodies(eligible.map((c2) => c2.angleAboutHub)) >= 2) continue;
|
|
825
|
+
const best = group.filter((c2) => c2.finding !== null).reduce(
|
|
826
|
+
(max, c2) => !max || c2.length > max.length ? c2 : max,
|
|
827
|
+
null
|
|
828
|
+
);
|
|
829
|
+
if (best?.finding) findings.push(best.finding);
|
|
830
|
+
}
|
|
831
|
+
return findings;
|
|
832
|
+
}
|
|
833
|
+
function detectOffPivotRotation(frames) {
|
|
834
|
+
const timed = frames.flatMap(
|
|
835
|
+
(frame) => frame.samples.map((sample) => ({ ...sample, time: frame.time }))
|
|
836
|
+
);
|
|
837
|
+
const candidates = [];
|
|
838
|
+
for (const group of groupBySelector(timed).values()) {
|
|
839
|
+
const candidate = buildIndicatorCandidate(group);
|
|
840
|
+
if (candidate) candidates.push(candidate);
|
|
841
|
+
}
|
|
842
|
+
return selectHubFindings(candidates);
|
|
843
|
+
}
|
|
844
|
+
function annotationBoxesFrom(issues) {
|
|
845
|
+
return issues.filter((issue) => issue.severity === "error" && issue.bbox.width > 0 && issue.bbox.height > 0).map((issue, index) => ({ label: `${index + 1} ${issue.code}`, bbox: issue.bbox }));
|
|
846
|
+
}
|
|
847
|
+
async function runAuditGrid(driver, options, motion) {
|
|
848
|
+
await driver.initialize(options.contrast);
|
|
849
|
+
const grid = await buildSampleGrid(driver, options);
|
|
850
|
+
const plan = await planMotionSampling(driver, motion, grid.duration);
|
|
851
|
+
const seekLoopStart = Date.now();
|
|
852
|
+
const collected = await collectGridSamples(driver, options, grid, plan);
|
|
853
|
+
const seekLoopMs = Date.now() - seekLoopStart;
|
|
854
|
+
let motionIssues = plan.preflightIssues;
|
|
855
|
+
if (motion.kind === "valid" && plan.assertions.length > 0 && collected.motionFrames.length > 0) {
|
|
856
|
+
const evaluated = evaluateMotion(
|
|
857
|
+
collected.motionFrames,
|
|
858
|
+
plan.assertions,
|
|
859
|
+
await driver.getCanvas()
|
|
860
|
+
);
|
|
861
|
+
motionIssues = [...motionIssues, ...await driver.anchorMotionIssues(evaluated)];
|
|
862
|
+
}
|
|
863
|
+
const userPicked = new Set(grid.userPickedSamples);
|
|
864
|
+
const sweepFindings = detectSweepStatic(
|
|
865
|
+
grid.duration,
|
|
866
|
+
collected.layoutStateSignatures.filter((sample) => !userPicked.has(sample.time)).map((sample) => sample.signature),
|
|
867
|
+
motionIssues,
|
|
868
|
+
await driver.hasNoTimelineDeclaration()
|
|
869
|
+
);
|
|
870
|
+
const rotationFindings = detectRotationPivotDrift(
|
|
871
|
+
collected.rotationSamples,
|
|
872
|
+
await driver.getCanvas()
|
|
873
|
+
);
|
|
874
|
+
const offPivotFindings = detectOffPivotRotation(collected.indicatorFrames);
|
|
875
|
+
const contrast = buildContrastResults(collected.contrastEntries);
|
|
876
|
+
return {
|
|
877
|
+
duration: grid.duration,
|
|
878
|
+
layoutSamples: grid.layoutSamples,
|
|
879
|
+
transitionSamples: grid.transitionSamples,
|
|
880
|
+
transitionSamplesDropped: grid.transitionSamplesDropped,
|
|
881
|
+
runtimeFindings: [],
|
|
882
|
+
layoutIssues: [
|
|
883
|
+
...collected.layoutIssues,
|
|
884
|
+
...sweepFindings,
|
|
885
|
+
...rotationFindings,
|
|
886
|
+
...offPivotFindings
|
|
887
|
+
],
|
|
888
|
+
motionIssues,
|
|
889
|
+
motionSampleCount: collected.motionFrames.length,
|
|
890
|
+
contrastSamples: grid.contrastSamples,
|
|
891
|
+
contrastFindings: contrast.findings,
|
|
892
|
+
contrastChecked: collected.contrastEntries.length,
|
|
893
|
+
contrastPassed: contrast.passed,
|
|
894
|
+
screenshots: collected.screenshots,
|
|
895
|
+
timings: { launchSettleMs: 0, seekLoopMs, contrastMs: collected.contrastMs },
|
|
896
|
+
skipped: false
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
async function runCheckPipeline(project, options, dependencies = DEFAULT_DEPENDENCIES2) {
|
|
900
|
+
let lintResult;
|
|
901
|
+
const lintStartedAt = Date.now();
|
|
902
|
+
try {
|
|
903
|
+
lintResult = await dependencies.lintProject(project.dir);
|
|
904
|
+
} catch (error) {
|
|
905
|
+
return failureReport(options, runtimeFailure(error, "check_lint_failure"));
|
|
906
|
+
}
|
|
907
|
+
trackLintRun(project.dir, lintResult, {
|
|
908
|
+
command: "check",
|
|
909
|
+
durationMs: Date.now() - lintStartedAt,
|
|
910
|
+
...getRunId() !== void 0 ? { runId: getRunId() } : {}
|
|
911
|
+
});
|
|
912
|
+
const lint = buildLintSection(lintResult);
|
|
913
|
+
let hdrPromotion = null;
|
|
914
|
+
let hdrInspection = "available";
|
|
915
|
+
try {
|
|
916
|
+
hdrPromotion = await (dependencies.inspectHdrAutoPromotion ?? inspectHdrAutoPromotion)(project);
|
|
917
|
+
} catch {
|
|
918
|
+
hdrInspection = "unavailable";
|
|
919
|
+
}
|
|
920
|
+
if (shouldBlockRender(true, false, lintResult.totalErrors, lintResult.totalWarnings)) {
|
|
921
|
+
return buildReport(
|
|
922
|
+
options,
|
|
923
|
+
lint,
|
|
924
|
+
emptyBrowserResult(),
|
|
925
|
+
{ kind: "none" },
|
|
926
|
+
[],
|
|
927
|
+
[],
|
|
928
|
+
hdrPromotion,
|
|
929
|
+
hdrInspection
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
const motion = dependencies.resolveMotionSpec(project.dir);
|
|
933
|
+
const specFindings = motion.kind === "invalid" ? [
|
|
934
|
+
findingAtRoot(
|
|
935
|
+
"motion_spec_invalid",
|
|
936
|
+
"error",
|
|
937
|
+
motion.message,
|
|
938
|
+
relative(project.dir, motion.path) || "index.motion.json"
|
|
939
|
+
)
|
|
940
|
+
] : [];
|
|
941
|
+
let browser;
|
|
942
|
+
try {
|
|
943
|
+
browser = await dependencies.runBrowserCheck(project, options, motion);
|
|
944
|
+
} catch (error) {
|
|
945
|
+
browser = emptyBrowserResult();
|
|
946
|
+
browser.runtimeFindings.push(runtimeFailure(error));
|
|
947
|
+
}
|
|
948
|
+
const snapshotFiles = options.snapshots ? await writeContrastSnapshots(dependencies, project.dir, browser) : [];
|
|
949
|
+
const report = buildReport(
|
|
950
|
+
options,
|
|
951
|
+
lint,
|
|
952
|
+
browser,
|
|
953
|
+
motion,
|
|
954
|
+
specFindings,
|
|
955
|
+
snapshotFiles,
|
|
956
|
+
hdrPromotion,
|
|
957
|
+
hdrInspection
|
|
958
|
+
);
|
|
959
|
+
return options.snapshots ? await withFindingCrops(dependencies, project, options, report) : report;
|
|
960
|
+
}
|
|
961
|
+
async function writeContrastSnapshots(dependencies, projectDir, browser) {
|
|
962
|
+
const files = [];
|
|
963
|
+
for (let index = 0; index < browser.screenshots.length; index += 1) {
|
|
964
|
+
const shot = browser.screenshots[index];
|
|
965
|
+
if (!shot) continue;
|
|
966
|
+
try {
|
|
967
|
+
files.push(await dependencies.writeSnapshot(projectDir, index, shot.time, shot.pngBase64));
|
|
968
|
+
} catch (error) {
|
|
969
|
+
browser.runtimeFindings.push(runtimeFailure(error, "snapshot_write_failed"));
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
return files;
|
|
973
|
+
}
|
|
974
|
+
async function withFindingCrops(dependencies, project, options, report) {
|
|
975
|
+
const cropRequests = selectFindingCropRequests(report);
|
|
976
|
+
if (cropRequests.length === 0) return report;
|
|
977
|
+
try {
|
|
978
|
+
const findingFiles = await dependencies.captureFindingCrops(project, options, cropRequests);
|
|
979
|
+
return { ...report, snapshots: { ...report.snapshots, findingFiles } };
|
|
980
|
+
} catch (error) {
|
|
981
|
+
console.error(" finding crops skipped: " + normalizeErrorMessage(error));
|
|
982
|
+
trackCommandFailure("check-finding-crops", error);
|
|
983
|
+
return report;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
var MAX_FINDING_CROPS = 12;
|
|
987
|
+
function selectFindingCropRequests(report) {
|
|
988
|
+
const candidates = [
|
|
989
|
+
...report.layout.findings,
|
|
990
|
+
...report.motion.findings,
|
|
991
|
+
...report.contrast.findings,
|
|
992
|
+
...report.runtime.findings
|
|
993
|
+
];
|
|
994
|
+
const requests = [];
|
|
995
|
+
for (const finding of candidates) {
|
|
996
|
+
if (requests.length >= MAX_FINDING_CROPS) break;
|
|
997
|
+
if (finding.severity !== "error" || !hasRealBbox(finding.bbox)) continue;
|
|
998
|
+
requests.push({
|
|
999
|
+
filename: findingCropFilename(requests.length, finding.code),
|
|
1000
|
+
time: finding.time,
|
|
1001
|
+
bbox: finding.bbox
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
return requests;
|
|
1005
|
+
}
|
|
1006
|
+
function hasRealBbox(bbox) {
|
|
1007
|
+
return bbox.width > 0 && bbox.height > 0;
|
|
1008
|
+
}
|
|
1009
|
+
function findingCropFilename(index, code) {
|
|
1010
|
+
const safeCode = code.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1011
|
+
return `finding-${String(index).padStart(2, "0")}-${safeCode}.png`;
|
|
1012
|
+
}
|
|
1013
|
+
function checkExitCode(report) {
|
|
1014
|
+
return report.ok ? 0 : 1;
|
|
1015
|
+
}
|
|
1016
|
+
function contrastFailureHeld(entries) {
|
|
1017
|
+
const sampledTimes = new Set(entries.map((entry) => entry.time)).size;
|
|
1018
|
+
const failureSamples = /* @__PURE__ */ new Map();
|
|
1019
|
+
for (const entry of entries) {
|
|
1020
|
+
if (entry.wcagAA) continue;
|
|
1021
|
+
const key = `${entry.selector}|${entry.text}`;
|
|
1022
|
+
const times = failureSamples.get(key) ?? /* @__PURE__ */ new Set();
|
|
1023
|
+
times.add(entry.time);
|
|
1024
|
+
failureSamples.set(key, times);
|
|
1025
|
+
}
|
|
1026
|
+
return (entry) => sampledTimes < 2 || (failureSamples.get(`${entry.selector}|${entry.text}`)?.size ?? 0) >= 2;
|
|
1027
|
+
}
|
|
1028
|
+
function buildContrastResults(entries) {
|
|
1029
|
+
const findings = [];
|
|
1030
|
+
let passed = 0;
|
|
1031
|
+
const isHeld = contrastFailureHeld(entries);
|
|
1032
|
+
for (const entry of entries) {
|
|
1033
|
+
if (entry.wcagAA) {
|
|
1034
|
+
passed += 1;
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1037
|
+
const held = isHeld(entry);
|
|
1038
|
+
const requiredRatio = requiredContrastRatio(entry.large);
|
|
1039
|
+
findings.push({
|
|
1040
|
+
code: "contrast_aa_failure",
|
|
1041
|
+
severity: held ? "error" : "warning",
|
|
1042
|
+
message: `Contrast is ${entry.ratio}:1; WCAG AA requires ${requiredRatio}:1.`,
|
|
1043
|
+
text: entry.text,
|
|
1044
|
+
fg: entry.fg,
|
|
1045
|
+
bg: entry.bg,
|
|
1046
|
+
ratio: entry.ratio,
|
|
1047
|
+
requiredRatio,
|
|
1048
|
+
suggestedColor: suggestedColor(entry.fg, entry.bg, requiredRatio),
|
|
1049
|
+
large: entry.large,
|
|
1050
|
+
selector: entry.selector,
|
|
1051
|
+
dataAttributes: entry.dataAttributes,
|
|
1052
|
+
sourceFile: entry.sourceFile,
|
|
1053
|
+
bbox: entry.bbox,
|
|
1054
|
+
time: entry.time
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
return { findings, passed };
|
|
1058
|
+
}
|
|
1059
|
+
function suggestedColor(fg, bg, requiredRatio) {
|
|
1060
|
+
const foreground = parseColorRGBA(fg);
|
|
1061
|
+
const background = parseColorRGBA(bg);
|
|
1062
|
+
if (!foreground || !background) return fg;
|
|
1063
|
+
const fgRgb = [foreground[0], foreground[1], foreground[2]];
|
|
1064
|
+
const bgRgb = [background[0], background[1], background[2]];
|
|
1065
|
+
const suggested = suggestCompliantForegroundColor(fgRgb, bgRgb, requiredRatio);
|
|
1066
|
+
return `rgb(${suggested[0]},${suggested[1]},${suggested[2]})`;
|
|
1067
|
+
}
|
|
1068
|
+
function buildLintSection(result) {
|
|
1069
|
+
const findings = result.results.flatMap(
|
|
1070
|
+
({ file, result: fileResult }) => fileResult.findings.map((finding) => ({
|
|
1071
|
+
code: finding.code,
|
|
1072
|
+
severity: finding.severity,
|
|
1073
|
+
message: finding.message,
|
|
1074
|
+
selector: finding.selector ?? (finding.elementId ? `#${finding.elementId}` : "[data-composition-id]"),
|
|
1075
|
+
dataAttributes: {},
|
|
1076
|
+
sourceFile: finding.file ?? file,
|
|
1077
|
+
bbox: ZERO_BBOX,
|
|
1078
|
+
time: 0,
|
|
1079
|
+
fixHint: finding.fixHint
|
|
1080
|
+
}))
|
|
1081
|
+
);
|
|
1082
|
+
return { ...section(findings), filesScanned: result.results.length };
|
|
1083
|
+
}
|
|
1084
|
+
function buildReport(options, lint, browser, motion, extraMotionFindings, snapshotFiles, hdrPromotion = null, hdrInspection = "available") {
|
|
1085
|
+
const layout = shapeLayoutSection(browser.layoutIssues, browser, options);
|
|
1086
|
+
const shapedMotion = shapeLayoutFindings(browser.motionIssues, options);
|
|
1087
|
+
const motionFindings = [...shapedMotion.findings, ...extraMotionFindings];
|
|
1088
|
+
const runtime = section(browser.runtimeFindings);
|
|
1089
|
+
const motionSection = section(motionFindings);
|
|
1090
|
+
const contrastSection = section(browser.contrastFindings);
|
|
1091
|
+
const warningCount = lint.warningCount + runtime.warningCount + layout.warningCount + motionSection.warningCount + contrastSection.warningCount;
|
|
1092
|
+
const errorCount = lint.errorCount + runtime.errorCount + layout.errorCount + motionSection.errorCount + contrastSection.errorCount;
|
|
1093
|
+
const report = {
|
|
1094
|
+
ok: errorCount === 0 && (!options.strict || warningCount === 0),
|
|
1095
|
+
strict: options.strict,
|
|
1096
|
+
browserSkipped: browser.skipped,
|
|
1097
|
+
lint,
|
|
1098
|
+
runtime,
|
|
1099
|
+
layout,
|
|
1100
|
+
motion: {
|
|
1101
|
+
...motionSection,
|
|
1102
|
+
enabled: motion.kind !== "none",
|
|
1103
|
+
specPath: motion.kind === "none" ? void 0 : motion.path,
|
|
1104
|
+
samples: browser.motionSampleCount
|
|
1105
|
+
},
|
|
1106
|
+
contrast: {
|
|
1107
|
+
...contrastSection,
|
|
1108
|
+
enabled: options.contrast,
|
|
1109
|
+
samples: browser.contrastSamples,
|
|
1110
|
+
checked: browser.contrastChecked,
|
|
1111
|
+
passed: browser.contrastPassed
|
|
1112
|
+
},
|
|
1113
|
+
hdr: { autoPromotion: hdrPromotion, inspection: hdrInspection },
|
|
1114
|
+
snapshots: {
|
|
1115
|
+
enabled: options.snapshots,
|
|
1116
|
+
files: snapshotFiles,
|
|
1117
|
+
times: options.snapshots ? browser.screenshots.map((shot) => shot.time) : [],
|
|
1118
|
+
findingFiles: []
|
|
1119
|
+
}
|
|
1120
|
+
};
|
|
1121
|
+
trackCheckReport({
|
|
1122
|
+
contrastGate: options.contrast,
|
|
1123
|
+
motionGate: motion.kind !== "none",
|
|
1124
|
+
captionZoneGate: options.captionZone !== void 0,
|
|
1125
|
+
frameCheckGate: options.frameCheck !== void 0,
|
|
1126
|
+
snapshotsGate: options.snapshots,
|
|
1127
|
+
lintErrors: lint.errorCount,
|
|
1128
|
+
lintWarnings: lint.warningCount,
|
|
1129
|
+
runtimeErrors: runtime.errorCount,
|
|
1130
|
+
runtimeWarnings: runtime.warningCount,
|
|
1131
|
+
layoutErrors: layout.errorCount,
|
|
1132
|
+
layoutWarnings: layout.warningCount,
|
|
1133
|
+
motionErrors: motionSection.errorCount,
|
|
1134
|
+
motionWarnings: motionSection.warningCount,
|
|
1135
|
+
contrastErrors: contrastSection.errorCount,
|
|
1136
|
+
contrastWarnings: contrastSection.warningCount,
|
|
1137
|
+
launchSettleMs: browser.timings.launchSettleMs,
|
|
1138
|
+
seekLoopMs: browser.timings.seekLoopMs,
|
|
1139
|
+
contrastMs: browser.timings.contrastMs,
|
|
1140
|
+
gridPoints: browser.layoutSamples.length,
|
|
1141
|
+
contrastPoints: browser.contrastChecked,
|
|
1142
|
+
ok: report.ok,
|
|
1143
|
+
exitCode: checkExitCode(report),
|
|
1144
|
+
runId: getRunId()
|
|
1145
|
+
});
|
|
1146
|
+
return report;
|
|
1147
|
+
}
|
|
1148
|
+
function shapeLayoutSection(issues, browser, options) {
|
|
1149
|
+
const shaped = shapeLayoutFindings(issues, options, browser.layoutSamples.length);
|
|
1150
|
+
return {
|
|
1151
|
+
...section(shaped.findings),
|
|
1152
|
+
duration: browser.duration,
|
|
1153
|
+
samples: browser.layoutSamples,
|
|
1154
|
+
transitionSamples: browser.transitionSamples,
|
|
1155
|
+
transitionSamplesDropped: browser.transitionSamplesDropped,
|
|
1156
|
+
tolerance: options.tolerance,
|
|
1157
|
+
totalIssueCount: shaped.totalIssueCount,
|
|
1158
|
+
truncated: shaped.truncated
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
function shapeLayoutFindings(issues, options, totalSampleCount) {
|
|
1162
|
+
const deduped = dedupeLayoutIssues(issues);
|
|
1163
|
+
const all = options.collapseStatic ? collapseStaticLayoutIssues(deduped, totalSampleCount) : deduped;
|
|
1164
|
+
const limited = limitLayoutIssues(all, options.maxIssues);
|
|
1165
|
+
return {
|
|
1166
|
+
findings: limited.issues.map(ensureAnchoredLayoutIssue),
|
|
1167
|
+
totalIssueCount: limited.totalIssueCount,
|
|
1168
|
+
truncated: limited.truncated
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
function ensureAnchoredLayoutIssue(issue) {
|
|
1172
|
+
const sourceFile = Reflect.get(issue, "sourceFile");
|
|
1173
|
+
const dataAttributes = Reflect.get(issue, "dataAttributes");
|
|
1174
|
+
const bbox = Reflect.get(issue, "bbox");
|
|
1175
|
+
if (typeof sourceFile === "string" && isStringRecord(dataAttributes) && isBbox(bbox)) {
|
|
1176
|
+
return { ...issue, sourceFile, dataAttributes, bbox };
|
|
1177
|
+
}
|
|
1178
|
+
return {
|
|
1179
|
+
...issue,
|
|
1180
|
+
sourceFile: "index.html",
|
|
1181
|
+
dataAttributes: {},
|
|
1182
|
+
bbox: rectToBbox(issue.rect)
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
function section(findings) {
|
|
1186
|
+
const errorCount = findings.filter((finding) => finding.severity === "error").length;
|
|
1187
|
+
const warningCount = findings.filter((finding) => finding.severity === "warning").length;
|
|
1188
|
+
const infoCount = findings.filter((finding) => finding.severity === "info").length;
|
|
1189
|
+
return { ok: errorCount === 0, errorCount, warningCount, infoCount, findings };
|
|
1190
|
+
}
|
|
1191
|
+
function emptyBrowserResult() {
|
|
1192
|
+
return {
|
|
1193
|
+
duration: 0,
|
|
1194
|
+
layoutSamples: [],
|
|
1195
|
+
transitionSamples: [],
|
|
1196
|
+
transitionSamplesDropped: 0,
|
|
1197
|
+
runtimeFindings: [],
|
|
1198
|
+
layoutIssues: [],
|
|
1199
|
+
motionIssues: [],
|
|
1200
|
+
motionSampleCount: 0,
|
|
1201
|
+
contrastSamples: [],
|
|
1202
|
+
contrastFindings: [],
|
|
1203
|
+
contrastChecked: 0,
|
|
1204
|
+
contrastPassed: 0,
|
|
1205
|
+
screenshots: [],
|
|
1206
|
+
timings: { launchSettleMs: 0, seekLoopMs: 0, contrastMs: 0 },
|
|
1207
|
+
skipped: true
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
function runtimeFailure(error, code = "check_runtime_failure") {
|
|
1211
|
+
return findingAtRoot(code, "error", normalizeErrorMessage(error), "index.html");
|
|
1212
|
+
}
|
|
1213
|
+
function findingAtRoot(code, severity, message, sourceFile) {
|
|
1214
|
+
return {
|
|
1215
|
+
code,
|
|
1216
|
+
severity,
|
|
1217
|
+
message,
|
|
1218
|
+
selector: "[data-composition-id]",
|
|
1219
|
+
dataAttributes: {},
|
|
1220
|
+
sourceFile,
|
|
1221
|
+
bbox: ZERO_BBOX,
|
|
1222
|
+
time: 0
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
function failureReport(options, finding) {
|
|
1226
|
+
const lint = { ...section([]), filesScanned: 0 };
|
|
1227
|
+
const browser = emptyBrowserResult();
|
|
1228
|
+
browser.runtimeFindings.push(finding);
|
|
1229
|
+
return buildReport(options, lint, browser, { kind: "none" }, [], []);
|
|
1230
|
+
}
|
|
1231
|
+
function isBbox(value) {
|
|
1232
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1233
|
+
return ["x", "y", "width", "height"].every((key) => typeof Reflect.get(value, key) === "number");
|
|
1234
|
+
}
|
|
1235
|
+
function isStringRecord(value) {
|
|
1236
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
1237
|
+
return Object.keys(value).every((key) => typeof Reflect.get(value, key) === "string");
|
|
1238
|
+
}
|
|
1239
|
+
function resolveMotionSpec(projectDir) {
|
|
1240
|
+
const path = findMotionSpec(projectDir);
|
|
1241
|
+
if (!path) return { kind: "none" };
|
|
1242
|
+
const result = readMotionSpec(path);
|
|
1243
|
+
return result.ok ? { kind: "valid", path, spec: result.spec } : {
|
|
1244
|
+
kind: "invalid",
|
|
1245
|
+
path,
|
|
1246
|
+
message: `Invalid motion spec ${path}: ${result.errors.join("; ")}`
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
async function runBrowserCheck(project, options, motion) {
|
|
1250
|
+
const module = await import("./checkBrowser-RPMO4OW5.js");
|
|
1251
|
+
return module.runBrowserCheck(project, options, motion, runAuditGrid);
|
|
1252
|
+
}
|
|
1253
|
+
async function writeSnapshot(projectDir, index, time, pngBase64) {
|
|
1254
|
+
const snapshotDir = join(projectDir, "snapshots");
|
|
1255
|
+
mkdirSync(snapshotDir, { recursive: true });
|
|
1256
|
+
const filename = `frame-${String(index).padStart(2, "0")}-at-${time.toFixed(1)}s.png`;
|
|
1257
|
+
const path = join(snapshotDir, filename);
|
|
1258
|
+
writeFileSync(path, Buffer.from(pngBase64, "base64"));
|
|
1259
|
+
return join("snapshots", filename);
|
|
1260
|
+
}
|
|
1261
|
+
async function captureFindingCrops(project, options, requests) {
|
|
1262
|
+
const module = await import("./checkBrowser-RPMO4OW5.js");
|
|
1263
|
+
return module.captureFindingCrops(project, options, requests);
|
|
1264
|
+
}
|
|
1265
|
+
var DEFAULT_DEPENDENCIES2 = {
|
|
1266
|
+
lintProject,
|
|
1267
|
+
resolveMotionSpec,
|
|
1268
|
+
runBrowserCheck,
|
|
1269
|
+
writeSnapshot,
|
|
1270
|
+
captureFindingCrops,
|
|
1271
|
+
inspectHdrAutoPromotion
|
|
1272
|
+
};
|
|
1273
|
+
|
|
1274
|
+
// src/commands/check.ts
|
|
1275
|
+
var examples = [
|
|
1276
|
+
["Run the full verification gate", "hyperframes check"],
|
|
1277
|
+
["Output one agent-readable envelope", "hyperframes check --json"],
|
|
1278
|
+
["Persist the five audited contrast frames", "hyperframes check --snapshots"],
|
|
1279
|
+
["Also fail on warnings", "hyperframes check --strict"]
|
|
1280
|
+
];
|
|
1281
|
+
var DEFAULT_COMMAND_DEPENDENCIES = {
|
|
1282
|
+
resolveProject,
|
|
1283
|
+
runPipeline: runCheckPipeline,
|
|
1284
|
+
withMeta
|
|
1285
|
+
};
|
|
1286
|
+
var CHECK_COMMAND_ARGS = {
|
|
1287
|
+
dir: { type: "positional", description: "Project directory", required: false },
|
|
1288
|
+
json: { type: "boolean", description: "Output agent-readable JSON", default: false },
|
|
1289
|
+
samples: {
|
|
1290
|
+
type: "string",
|
|
1291
|
+
description: "Number of midpoint samples across the duration (default: 9)",
|
|
1292
|
+
default: "9"
|
|
1293
|
+
},
|
|
1294
|
+
at: {
|
|
1295
|
+
type: "string",
|
|
1296
|
+
description: "Comma-separated timestamps in seconds (e.g., --at 1.5,4,7.25)"
|
|
1297
|
+
},
|
|
1298
|
+
"at-transitions": {
|
|
1299
|
+
type: "boolean",
|
|
1300
|
+
description: "Also sample at every tween start/end boundary (plus segment midpoints) to catch transient overlaps at transition seams",
|
|
1301
|
+
default: false
|
|
1302
|
+
},
|
|
1303
|
+
"max-transition-samples": {
|
|
1304
|
+
type: "string",
|
|
1305
|
+
description: "Optional cap on transition-derived samples; when it truncates, the omitted count is reported (default: unlimited)"
|
|
1306
|
+
},
|
|
1307
|
+
"max-issues": {
|
|
1308
|
+
type: "string",
|
|
1309
|
+
description: "Maximum issues to print or return after static collapse (default: 80)",
|
|
1310
|
+
default: "80"
|
|
1311
|
+
},
|
|
1312
|
+
"collapse-static": {
|
|
1313
|
+
type: "boolean",
|
|
1314
|
+
description: "Collapse repeated static issues across samples (default: true)",
|
|
1315
|
+
default: true
|
|
1316
|
+
},
|
|
1317
|
+
tolerance: {
|
|
1318
|
+
type: "string",
|
|
1319
|
+
description: "Allowed pixel overflow before reporting an issue (default: 2)",
|
|
1320
|
+
default: "2"
|
|
1321
|
+
},
|
|
1322
|
+
timeout: {
|
|
1323
|
+
type: "string",
|
|
1324
|
+
description: "Initial render-ready timeout in ms; also sets the navigation minimum (10s floor, default: 3000)",
|
|
1325
|
+
default: "3000"
|
|
1326
|
+
},
|
|
1327
|
+
contrast: {
|
|
1328
|
+
type: "boolean",
|
|
1329
|
+
description: "Run the WCAG AA contrast pass (enabled by default)",
|
|
1330
|
+
default: true
|
|
1331
|
+
},
|
|
1332
|
+
strict: {
|
|
1333
|
+
type: "boolean",
|
|
1334
|
+
description: "Exit non-zero on warnings too",
|
|
1335
|
+
default: false
|
|
1336
|
+
},
|
|
1337
|
+
proxy: {
|
|
1338
|
+
type: "boolean",
|
|
1339
|
+
description: "Auto-transcode browser-hostile video codecs (default: hyperframes.json media.autoProxy, which defaults on)",
|
|
1340
|
+
default: void 0
|
|
1341
|
+
},
|
|
1342
|
+
"browser-gpu": {
|
|
1343
|
+
type: "boolean",
|
|
1344
|
+
description: "Use hardware browser GPU capture; pass --no-browser-gpu for deterministic SwiftShader (default: auto-detect, PRODUCER_BROWSER_GPU_MODE overrides)",
|
|
1345
|
+
default: void 0
|
|
1346
|
+
},
|
|
1347
|
+
snapshots: {
|
|
1348
|
+
type: "boolean",
|
|
1349
|
+
description: "Save the five contrast-pass PNGs under snapshots/",
|
|
1350
|
+
default: false
|
|
1351
|
+
},
|
|
1352
|
+
"caption-zone": {
|
|
1353
|
+
type: "string",
|
|
1354
|
+
description: 'Caption band "x0=0;y0=.82;x1=1;y1=1[;severity=warning|error][;seek=.5,1]" (fractions 0-1; defaults: warning, seek=1)'
|
|
1355
|
+
},
|
|
1356
|
+
"frame-check": {
|
|
1357
|
+
type: "string",
|
|
1358
|
+
description: 'Bare --frame-check uses defaults (tol=2px, severity=warning, seek=.5; breach floor=max(120px, 6% of shorter canvas edge)); or pass "severity=error;seek=.25,.75;tol=4" to tune'
|
|
1359
|
+
},
|
|
1360
|
+
layout: {
|
|
1361
|
+
type: "string",
|
|
1362
|
+
description: 'Layout knobs: "proseCoverageFloor=0.05" (0\u20131; default 0.15).'
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
function createCheckCommand(dependencies = DEFAULT_COMMAND_DEPENDENCIES) {
|
|
1366
|
+
return defineCommand({
|
|
1367
|
+
meta: {
|
|
1368
|
+
name: "check",
|
|
1369
|
+
description: "Run lint, runtime, layout, motion, and WCAG contrast verification in one browser session"
|
|
1370
|
+
},
|
|
1371
|
+
args: CHECK_COMMAND_ARGS,
|
|
1372
|
+
async run({ rawArgs }) {
|
|
1373
|
+
const args = parseArgs(normalizeFrameCheckRawArgs(rawArgs), CHECK_COMMAND_ARGS);
|
|
1374
|
+
const asJson = args.json === true;
|
|
1375
|
+
try {
|
|
1376
|
+
const project = dependencies.resolveProject(args.dir);
|
|
1377
|
+
const options = parseCheckOptions(args);
|
|
1378
|
+
if (!asJson) {
|
|
1379
|
+
console.log(`${c.accent("\u25C6")} Checking ${c.accent(project.name)}`);
|
|
1380
|
+
}
|
|
1381
|
+
const report = await dependencies.runPipeline(project, options);
|
|
1382
|
+
if (asJson) {
|
|
1383
|
+
console.log(JSON.stringify(dependencies.withMeta(report), null, 2));
|
|
1384
|
+
} else {
|
|
1385
|
+
printHumanReport(report);
|
|
1386
|
+
}
|
|
1387
|
+
setCommandExitCode(checkExitCode(report));
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
const message = normalizeErrorMessage(error);
|
|
1390
|
+
if (asJson) {
|
|
1391
|
+
console.log(
|
|
1392
|
+
JSON.stringify(dependencies.withMeta({ ok: false, error: message }), null, 2)
|
|
1393
|
+
);
|
|
1394
|
+
} else {
|
|
1395
|
+
console.error(`${c.error("\u2717")} Check failed: ${message}`);
|
|
1396
|
+
}
|
|
1397
|
+
setCommandExitCode(1);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
function normalizeFrameCheckRawArgs(rawArgs) {
|
|
1403
|
+
return rawArgs.map((arg, index) => {
|
|
1404
|
+
if (arg !== "--frame-check") return arg;
|
|
1405
|
+
const next = rawArgs[index + 1];
|
|
1406
|
+
return next === void 0 || next.startsWith("-") ? "--frame-check=" : arg;
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
function parseCheckOptions(args) {
|
|
1410
|
+
const maxTransitionSamples = positiveInteger(args["max-transition-samples"], 0);
|
|
1411
|
+
return {
|
|
1412
|
+
samples: positiveInteger(args.samples, DEFAULT_CHECK_OPTIONS.samples),
|
|
1413
|
+
at: parseAt(args.at),
|
|
1414
|
+
atTransitions: args["at-transitions"] === true,
|
|
1415
|
+
maxTransitionSamples: maxTransitionSamples > 0 ? maxTransitionSamples : void 0,
|
|
1416
|
+
maxIssues: positiveInteger(args["max-issues"], DEFAULT_CHECK_OPTIONS.maxIssues),
|
|
1417
|
+
collapseStatic: args["collapse-static"] !== false,
|
|
1418
|
+
tolerance: nonNegativeNumber(args.tolerance, DEFAULT_CHECK_OPTIONS.tolerance),
|
|
1419
|
+
timeout: Math.max(500, positiveInteger(args.timeout, DEFAULT_CHECK_OPTIONS.timeout)),
|
|
1420
|
+
contrast: args.contrast !== false,
|
|
1421
|
+
strict: args.strict === true,
|
|
1422
|
+
snapshots: args.snapshots === true,
|
|
1423
|
+
captionZone: parseCaptionZone(args["caption-zone"]),
|
|
1424
|
+
frameCheck: parseFrameCheck(args["frame-check"]),
|
|
1425
|
+
layout: parseLayout(args.layout),
|
|
1426
|
+
autoProxy: args.proxy,
|
|
1427
|
+
browserGpuMode: resolveLocalBrowserGpuMode(args["browser-gpu"])
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
var CAPTION_ZONE_FIELDS = /* @__PURE__ */ new Set(["x0", "y0", "x1", "y1", "severity", "seek"]);
|
|
1431
|
+
var FRAME_CHECK_FIELDS = /* @__PURE__ */ new Set(["severity", "seek", "tol"]);
|
|
1432
|
+
var LAYOUT_FIELDS = /* @__PURE__ */ new Set(["proseCoverageFloor"]);
|
|
1433
|
+
function parseFrameCheck(value) {
|
|
1434
|
+
if (value === void 0 || value === null || value === false) return void 0;
|
|
1435
|
+
if (value === true || value === "") return {};
|
|
1436
|
+
if (typeof value !== "string") throw frameCheckError();
|
|
1437
|
+
if (value.startsWith("-")) throw swallowedOptionError("frame-check", value);
|
|
1438
|
+
const fields = parseFrameCheckFields(value);
|
|
1439
|
+
const severity = captionSeverity(fields.get("severity"), frameCheckError);
|
|
1440
|
+
const seek = captionSeeks(fields.get("seek"), frameCheckError);
|
|
1441
|
+
const tol = parseFrameCheckTolerance(fields.get("tol"));
|
|
1442
|
+
return {
|
|
1443
|
+
...severity ? { severity } : {},
|
|
1444
|
+
...seek ? { seek } : {},
|
|
1445
|
+
...tol !== void 0 ? { tol } : {}
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
function parseFrameCheckFields(value) {
|
|
1449
|
+
const fields = /* @__PURE__ */ new Map();
|
|
1450
|
+
for (const part of value.split(";")) {
|
|
1451
|
+
const { key, entry } = parseCaptionField(part, frameCheckError);
|
|
1452
|
+
if (!FRAME_CHECK_FIELDS.has(key) || fields.has(key)) throw frameCheckError();
|
|
1453
|
+
fields.set(key, entry);
|
|
1454
|
+
}
|
|
1455
|
+
return fields;
|
|
1456
|
+
}
|
|
1457
|
+
function parseFrameCheckTolerance(raw) {
|
|
1458
|
+
if (raw === void 0) return void 0;
|
|
1459
|
+
const tol = parseNumberStrict(raw);
|
|
1460
|
+
if (tol === null || tol < 0) throw frameCheckError();
|
|
1461
|
+
return tol;
|
|
1462
|
+
}
|
|
1463
|
+
function frameCheckError() {
|
|
1464
|
+
return new Error(
|
|
1465
|
+
'Invalid --frame-check: use bare --frame-check or "severity=warning|error;seek=.25,.75;tol=4" (all fields optional)'
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
function swallowedOptionError(flag, value) {
|
|
1469
|
+
return new Error(
|
|
1470
|
+
`Invalid --${flag}: value "${value}" appears to have swallowed the next option; use --${flag}= or move --${flag} to the end`
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
function parseLayout(value) {
|
|
1474
|
+
if (value === void 0 || value === null || value === false) return void 0;
|
|
1475
|
+
if (value === true || value === "") throw layoutError();
|
|
1476
|
+
if (typeof value !== "string") throw layoutError();
|
|
1477
|
+
const fields = parseLayoutFields(value);
|
|
1478
|
+
const proseCoverageFloor = parseProseCoverageFloor(fields.get("proseCoverageFloor"));
|
|
1479
|
+
if (proseCoverageFloor === void 0) throw layoutError();
|
|
1480
|
+
return { proseCoverageFloor };
|
|
1481
|
+
}
|
|
1482
|
+
function parseLayoutFields(value) {
|
|
1483
|
+
const fields = /* @__PURE__ */ new Map();
|
|
1484
|
+
for (const part of value.split(";")) {
|
|
1485
|
+
const trimmed = part.trim();
|
|
1486
|
+
if (!trimmed) continue;
|
|
1487
|
+
const separator = trimmed.indexOf("=");
|
|
1488
|
+
if (separator <= 0) throw layoutError();
|
|
1489
|
+
const key = trimmed.slice(0, separator).trim();
|
|
1490
|
+
const entry = trimmed.slice(separator + 1).trim();
|
|
1491
|
+
if (!LAYOUT_FIELDS.has(key) || fields.has(key)) throw layoutError();
|
|
1492
|
+
fields.set(key, entry);
|
|
1493
|
+
}
|
|
1494
|
+
return fields;
|
|
1495
|
+
}
|
|
1496
|
+
function parseProseCoverageFloor(raw) {
|
|
1497
|
+
if (raw === void 0) return void 0;
|
|
1498
|
+
const floor = parseNumberStrict(raw);
|
|
1499
|
+
if (floor === null || floor < 0 || floor > 1) throw layoutError();
|
|
1500
|
+
return floor;
|
|
1501
|
+
}
|
|
1502
|
+
function layoutError() {
|
|
1503
|
+
return new Error(
|
|
1504
|
+
'Invalid --layout: use "proseCoverageFloor=0.05" with a fraction from 0 to 1 (inclusive)'
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
function parseNumberStrict(raw) {
|
|
1508
|
+
if (raw === "") return null;
|
|
1509
|
+
const value = Number(raw);
|
|
1510
|
+
return Number.isFinite(value) ? value : null;
|
|
1511
|
+
}
|
|
1512
|
+
function parseCaptionZone(value) {
|
|
1513
|
+
if (value === void 0 || value === null) return void 0;
|
|
1514
|
+
const fields = parseCaptionFields(captionZoneString(value));
|
|
1515
|
+
const { x0, y0, x1, y1 } = parseCaptionBounds(fields);
|
|
1516
|
+
const severity = captionSeverity(fields.get("severity"));
|
|
1517
|
+
const seek = captionSeeks(fields.get("seek"));
|
|
1518
|
+
return {
|
|
1519
|
+
x0,
|
|
1520
|
+
y0,
|
|
1521
|
+
x1,
|
|
1522
|
+
y1,
|
|
1523
|
+
...severity ? { severity } : {},
|
|
1524
|
+
...seek ? { seek } : {}
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
function captionZoneString(value) {
|
|
1528
|
+
if (typeof value !== "string" || value.trim() === "") throw captionZoneError();
|
|
1529
|
+
return value;
|
|
1530
|
+
}
|
|
1531
|
+
function parseCaptionFields(value) {
|
|
1532
|
+
const fields = /* @__PURE__ */ new Map();
|
|
1533
|
+
for (const part of value.split(";")) {
|
|
1534
|
+
const { key, entry } = parseCaptionField(part);
|
|
1535
|
+
if (!CAPTION_ZONE_FIELDS.has(key) || fields.has(key)) throw captionZoneError();
|
|
1536
|
+
fields.set(key, entry);
|
|
1537
|
+
}
|
|
1538
|
+
return fields;
|
|
1539
|
+
}
|
|
1540
|
+
function parseCaptionField(part, errorFactory = captionZoneError) {
|
|
1541
|
+
const separator = part.indexOf("=");
|
|
1542
|
+
if (separator <= 0) throw errorFactory();
|
|
1543
|
+
return {
|
|
1544
|
+
key: part.slice(0, separator).trim(),
|
|
1545
|
+
entry: part.slice(separator + 1).trim()
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1548
|
+
function parseCaptionBounds(fields) {
|
|
1549
|
+
const x0 = requiredCaptionFraction(fields, "x0");
|
|
1550
|
+
const y0 = requiredCaptionFraction(fields, "y0");
|
|
1551
|
+
const x1 = requiredCaptionFraction(fields, "x1");
|
|
1552
|
+
const y1 = requiredCaptionFraction(fields, "y1");
|
|
1553
|
+
if (x0 > x1 || y0 > y1) throw captionZoneError();
|
|
1554
|
+
return { x0, y0, x1, y1 };
|
|
1555
|
+
}
|
|
1556
|
+
function requiredCaptionFraction(fields, key) {
|
|
1557
|
+
const value = captionFraction(fields.get(key));
|
|
1558
|
+
if (value === null) throw captionZoneError();
|
|
1559
|
+
return value;
|
|
1560
|
+
}
|
|
1561
|
+
function captionFraction(value) {
|
|
1562
|
+
if (value === void 0 || value === "") return null;
|
|
1563
|
+
const parsed = parseNumberStrict(value);
|
|
1564
|
+
return parsed !== null && parsed >= 0 && parsed <= 1 ? parsed : null;
|
|
1565
|
+
}
|
|
1566
|
+
function captionSeverity(value, errorFactory = captionZoneError) {
|
|
1567
|
+
if (value === void 0) return void 0;
|
|
1568
|
+
if (value === "error" || value === "warning") return value;
|
|
1569
|
+
throw errorFactory();
|
|
1570
|
+
}
|
|
1571
|
+
function captionSeeks(value, errorFactory = captionZoneError) {
|
|
1572
|
+
if (value === void 0) return void 0;
|
|
1573
|
+
if (value === "") return [];
|
|
1574
|
+
const values = value.split(",").map(captionFraction);
|
|
1575
|
+
if (values.some((entry) => entry === null)) throw errorFactory();
|
|
1576
|
+
return values.flatMap((entry) => entry === null ? [] : entry);
|
|
1577
|
+
}
|
|
1578
|
+
function captionZoneError() {
|
|
1579
|
+
return new Error(
|
|
1580
|
+
'Invalid --caption-zone; use "x0=0;y0=.82;x1=1;y1=1[;severity=warning|error][;seek=.5,1]" with fractions from 0 to 1.'
|
|
1581
|
+
);
|
|
1582
|
+
}
|
|
1583
|
+
function positiveInteger(value, fallback) {
|
|
1584
|
+
const parsed = parseInt(String(value ?? ""), 10);
|
|
1585
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
1586
|
+
}
|
|
1587
|
+
function nonNegativeNumber(value, fallback) {
|
|
1588
|
+
const parsed = parseFloat(String(value ?? ""));
|
|
1589
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
1590
|
+
}
|
|
1591
|
+
function printHumanReport(report) {
|
|
1592
|
+
printSection("Lint", report.lint);
|
|
1593
|
+
if (report.browserSkipped) {
|
|
1594
|
+
console.log();
|
|
1595
|
+
console.log(
|
|
1596
|
+
` ${c.warn("\u26A0")} Browser session never ran \u2014 layout, motion, and contrast below are empty placeholders, not a clean pass.`
|
|
1597
|
+
);
|
|
1598
|
+
}
|
|
1599
|
+
printSection("Runtime", report.runtime);
|
|
1600
|
+
printLayoutSection("Layout", report.layout);
|
|
1601
|
+
printSection("Motion", report.motion);
|
|
1602
|
+
printContrastSection(report);
|
|
1603
|
+
printSnapshotSection(report);
|
|
1604
|
+
console.log();
|
|
1605
|
+
const label = report.ok ? c.success("Check passed") : c.error("Check failed");
|
|
1606
|
+
console.log(`${report.ok ? c.success("\u25C7") : c.error("\u25C7")} ${label}`);
|
|
1607
|
+
}
|
|
1608
|
+
function printSection(title, section2) {
|
|
1609
|
+
console.log();
|
|
1610
|
+
console.log(c.bold(title));
|
|
1611
|
+
if (section2.findings.length === 0) {
|
|
1612
|
+
console.log(` ${c.success("\u25C7")} 0 errors, 0 warnings`);
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
for (const finding of section2.findings) printFinding(finding);
|
|
1616
|
+
printCounts(section2);
|
|
1617
|
+
}
|
|
1618
|
+
function printLayoutSection(title, section2) {
|
|
1619
|
+
console.log();
|
|
1620
|
+
console.log(c.bold(title));
|
|
1621
|
+
if (section2.findings.length === 0) {
|
|
1622
|
+
console.log(` ${c.success("\u25C7")} 0 issues across ${section2.samples.length} sample(s)`);
|
|
1623
|
+
} else {
|
|
1624
|
+
for (const finding of section2.findings) {
|
|
1625
|
+
const formatted = formatLayoutIssue(finding).replace(/\n/g, "\n ");
|
|
1626
|
+
console.log(` ${findingIcon(finding)} ${formatted}`);
|
|
1627
|
+
}
|
|
1628
|
+
printCounts(section2);
|
|
1629
|
+
}
|
|
1630
|
+
if (section2.transitionSamplesDropped > 0) {
|
|
1631
|
+
console.log(
|
|
1632
|
+
` ${c.warn("\u26A0")} ${section2.transitionSamplesDropped} transition sample(s) omitted`
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
function printContrastSection(report) {
|
|
1637
|
+
const section2 = report.contrast;
|
|
1638
|
+
console.log();
|
|
1639
|
+
console.log(c.bold("Contrast"));
|
|
1640
|
+
if (!section2.enabled) {
|
|
1641
|
+
console.log(` ${c.dim("\u25C7")} skipped`);
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
if (section2.findings.length === 0) {
|
|
1645
|
+
console.log(
|
|
1646
|
+
` ${c.success("\u25C7")} ${section2.passed}/${section2.checked} text checks pass WCAG AA`
|
|
1647
|
+
);
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
for (const finding of section2.findings) {
|
|
1651
|
+
console.log(
|
|
1652
|
+
` ${c.error("\u2717")} ${finding.selector} ${finding.ratio}:1 (need ${finding.requiredRatio}:1, t=${finding.time}s)`
|
|
1653
|
+
);
|
|
1654
|
+
console.log(` ${c.dim(`Try ${finding.suggestedColor}; source ${finding.sourceFile}`)}`);
|
|
1655
|
+
}
|
|
1656
|
+
printCounts(section2);
|
|
1657
|
+
}
|
|
1658
|
+
function printSnapshotSection(report) {
|
|
1659
|
+
console.log();
|
|
1660
|
+
console.log(c.bold("Snapshots"));
|
|
1661
|
+
if (!report.snapshots.enabled) {
|
|
1662
|
+
console.log(` ${c.dim("\u25C7")} disabled`);
|
|
1663
|
+
} else {
|
|
1664
|
+
console.log(` ${c.success("\u25C7")} ${report.snapshots.files.length} PNG(s) saved`);
|
|
1665
|
+
for (const file of report.snapshots.files) console.log(` ${c.dim(file)}`);
|
|
1666
|
+
if (report.snapshots.findingFiles.length > 0) {
|
|
1667
|
+
console.log(
|
|
1668
|
+
` ${c.success("\u25C7")} ${report.snapshots.findingFiles.length} finding crop(s) saved`
|
|
1669
|
+
);
|
|
1670
|
+
for (const file of report.snapshots.findingFiles) console.log(` ${c.dim(file)}`);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
function printFinding(finding) {
|
|
1675
|
+
const where = `${finding.sourceFile} ${finding.selector} t=${finding.time}s`;
|
|
1676
|
+
console.log(` ${findingIcon(finding)} ${finding.code}: ${finding.message}`);
|
|
1677
|
+
console.log(` ${c.dim(where)}`);
|
|
1678
|
+
if (finding.fixHint) console.log(` ${c.dim(`Fix: ${finding.fixHint}`)}`);
|
|
1679
|
+
}
|
|
1680
|
+
function findingIcon(finding) {
|
|
1681
|
+
if (finding.severity === "error") return c.error("\u2717");
|
|
1682
|
+
if (finding.severity === "warning") return c.warn("\u26A0");
|
|
1683
|
+
return c.dim("\u2139");
|
|
1684
|
+
}
|
|
1685
|
+
function printCounts(section2) {
|
|
1686
|
+
console.log(
|
|
1687
|
+
` ${c.dim(`${section2.errorCount} error(s), ${section2.warningCount} warning(s), ${section2.infoCount} info(s)`)}`
|
|
1688
|
+
);
|
|
1689
|
+
}
|
|
1690
|
+
var check_default = createCheckCommand();
|
|
1691
|
+
export {
|
|
1692
|
+
createCheckCommand,
|
|
1693
|
+
check_default as default,
|
|
1694
|
+
examples,
|
|
1695
|
+
parseFrameCheck,
|
|
1696
|
+
parseLayout
|
|
1697
|
+
};
|