@vfrey/vfrey 0.0.1 → 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +33 -0
- package/README.md +78 -3
- package/accounts.example.json +61 -0
- package/accounts.first-run.json +41 -0
- package/bin/vfrey.mjs +36 -0
- package/integration-tools/README.md +43 -0
- package/integration-tools/image/pillow.md +32 -0
- package/integration-tools/image/playwright.md +33 -0
- package/integration-tools/image/resvg.md +36 -0
- package/integration-tools/image/satori.md +36 -0
- package/integration-tools/image/sharp.md +38 -0
- package/integration-tools/video/blender.md +34 -0
- package/integration-tools/video/ffmpeg.md +41 -0
- package/integration-tools/video/manim.md +37 -0
- package/integration-tools/video/motion-canvas.md +37 -0
- package/integration-tools/video/remotion.md +50 -0
- package/integration-tools/video/revideo.md +32 -0
- package/package.json +74 -6
- package/skills/vfrey-orchestrator/SKILL.md +15 -0
- package/skills/vfrey-orchestrator/channel-video/SKILL.md +41 -0
- package/skills/vfrey-product/SKILL.md +63 -0
- package/skills/vfrey-product/examples/concurrency-vs-parallelism/framey/cook-one.svg +14 -0
- package/skills/vfrey-product/examples/concurrency-vs-parallelism/framey/cook-two.svg +22 -0
- package/skills/vfrey-product/examples/concurrency-vs-parallelism/framey/index.html +70 -0
- package/skills/vfrey-product/examples/concurrency-vs-parallelism/remotion/cook-one.svg +14 -0
- package/skills/vfrey-product/examples/concurrency-vs-parallelism/remotion/cook-two.svg +22 -0
- package/skills/vfrey-product/examples/concurrency-vs-parallelism/remotion/index.tsx +49 -0
- package/skills/vfrey-product/examples/concurrency-vs-parallelism/script.json +15 -0
- package/skills/vfrey-product/examples/octopus-facts/index.html +60 -0
- package/skills/vfrey-product/examples/octopus-facts/octopus.svg +8 -0
- package/skills/vfrey-product/examples/octopus-facts/script.json +14 -0
- package/skills/vfrey-product/push/SKILL.md +15 -0
- package/skills/vfrey-product/scenes/NOTICE +5 -0
- package/skills/vfrey-product/scenes/blocks.md +57 -0
- package/skills/vfrey-product/scenes/craft.md +118 -0
- package/skills/vfrey-product/scenes/motion.md +88 -0
- package/src/analytics/dashboard.ts +109 -0
- package/src/analytics/index.ts +260 -0
- package/src/api/client.ts +282 -0
- package/src/api/commands.ts +330 -0
- package/src/api/config.ts +34 -0
- package/src/api/creators.ts +463 -0
- package/src/api/credentials.ts +152 -0
- package/src/api/mail.ts +333 -0
- package/src/api/topics.ts +207 -0
- package/src/api/types.ts +205 -0
- package/src/cli.ts +467 -0
- package/src/cloud/executor.ts +281 -0
- package/src/cloud/job.ts +106 -0
- package/src/cloud/render-job.ts +187 -0
- package/src/config.ts +309 -0
- package/src/dashboard-link.ts +180 -0
- package/src/dashboard-start.ts +103 -0
- package/src/desk/channel.ts +64 -0
- package/src/desk/cli.ts +216 -0
- package/src/desk/creators-route.ts +129 -0
- package/src/desk/fonts/JetBrainsMono-OFL.txt +93 -0
- package/src/desk/fonts/google-sans-flex-latin.woff2 +0 -0
- package/src/desk/fonts/jetbrains-mono-medium.woff2 +0 -0
- package/src/desk/http.ts +460 -0
- package/src/desk/mail-route.ts +103 -0
- package/src/desk/overlay.ts +112 -0
- package/src/desk/preview.ts +422 -0
- package/src/desk/screens.ts +149 -0
- package/src/desk/secrets.ts +143 -0
- package/src/desk/series.ts +127 -0
- package/src/desk/state.ts +77 -0
- package/src/desk/studio-route.ts +119 -0
- package/src/desk/tick-runner.ts +66 -0
- package/src/desk/tick.ts +56 -0
- package/src/desk/topics-route.ts +41 -0
- package/src/desk/ui/app.css +505 -0
- package/src/desk/ui/app.js +185 -0
- package/src/desk/ui/apple-icon.png +0 -0
- package/src/desk/ui/components.js +79 -0
- package/src/desk/ui/core.js +156 -0
- package/src/desk/ui/favicon.ico +0 -0
- package/src/desk/ui/icon.svg +1 -0
- package/src/desk/ui/icons.js +49 -0
- package/src/desk/ui/index.html +41 -0
- package/src/desk/ui/metrics-math.d.ts +22 -0
- package/src/desk/ui/metrics-math.js +135 -0
- package/src/desk/ui/theme.js +5 -0
- package/src/desk/ui/views-creators.js +209 -0
- package/src/desk/ui/views-keys.js +114 -0
- package/src/desk/ui/views-mail.js +188 -0
- package/src/desk/ui/views-misc.js +123 -0
- package/src/desk/ui/views-review.js +119 -0
- package/src/desk/ui/views-runs.js +350 -0
- package/src/desk/ui/views-screens.js +163 -0
- package/src/desk/ui/views-series.js +318 -0
- package/src/desk/ui/views-topics.js +87 -0
- package/src/desk/verbs.ts +361 -0
- package/src/doctor.ts +212 -0
- package/src/drain.ts +14 -0
- package/src/engage/index.ts +217 -0
- package/src/generate/index.ts +110 -0
- package/src/generate/script.ts +152 -0
- package/src/generate/title.ts +78 -0
- package/src/help.ts +233 -0
- package/src/home.ts +45 -0
- package/src/llm/client.ts +177 -0
- package/src/log.ts +7 -0
- package/src/oauth/tokens.ts +189 -0
- package/src/oauth/vault.ts +72 -0
- package/src/pipeline/review.ts +642 -0
- package/src/pipeline/run.ts +443 -0
- package/src/pipeline/series-guard.ts +26 -0
- package/src/pipeline/source-fetch.ts +69 -0
- package/src/pipeline/stages.ts +728 -0
- package/src/pipeline/topics-source.ts +90 -0
- package/src/product/commands.ts +296 -0
- package/src/product/config-file.ts +38 -0
- package/src/product/engine-choice.ts +89 -0
- package/src/product/engines.ts +103 -0
- package/src/product/insights.ts +50 -0
- package/src/product/keys.ts +67 -0
- package/src/product/paths.ts +18 -0
- package/src/product/probes.ts +88 -0
- package/src/product/push-flow.ts +90 -0
- package/src/product/render-video.ts +21 -0
- package/src/product/short.ts +62 -0
- package/src/product/update.ts +32 -0
- package/src/project/canonical.ts +14 -0
- package/src/project/commands.ts +177 -0
- package/src/project/dashboard-status.ts +28 -0
- package/src/project/discover.ts +19 -0
- package/src/project/index-file.ts +73 -0
- package/src/project/marker.ts +87 -0
- package/src/project/migrate.ts +201 -0
- package/src/project/names.ts +27 -0
- package/src/project/notice.ts +16 -0
- package/src/project/open.ts +88 -0
- package/src/project/scaffold.ts +112 -0
- package/src/project/templates.ts +42 -0
- package/src/project/videos.ts +64 -0
- package/src/publish/facebook.ts +91 -0
- package/src/publish/index.ts +12 -0
- package/src/publish/instagram.ts +97 -0
- package/src/publish/rate.ts +62 -0
- package/src/publish/session.ts +242 -0
- package/src/publish/tiktok.ts +202 -0
- package/src/publish/youtube.ts +177 -0
- package/src/queue/desk-ops.ts +1170 -0
- package/src/queue/seal.ts +3 -0
- package/src/queue/store.ts +1006 -0
- package/src/remotion/AiLabel.tsx +26 -0
- package/src/remotion/Root.tsx +73 -0
- package/src/remotion/defaults.ts +26 -0
- package/src/remotion/films/claude/ClaudeFilm.tsx +1014 -0
- package/src/remotion/films/engine/EngineMark.tsx +17 -0
- package/src/remotion/films/rea/ReaShort.tsx +552 -0
- package/src/remotion/films/rea/drawings.tsx +907 -0
- package/src/remotion/films/rea/timing.ts +144 -0
- package/src/remotion/index.ts +4 -0
- package/src/remotion/templates/EditorialSplit.tsx +39 -0
- package/src/remotion/templates/KineticType.tsx +39 -0
- package/src/remotion/templates/SignalBoard.tsx +50 -0
- package/src/remotion/timing.ts +22 -0
- package/src/render/chrome.ts +78 -0
- package/src/render/engine-mark.ts +29 -0
- package/src/render/framey-template.ts +130 -0
- package/src/render/html-engine.ts +149 -0
- package/src/render/node-crypto-stub.ts +11 -0
- package/src/render/probe.ts +29 -0
- package/src/render/props.ts +17 -0
- package/src/render/vertical-short.ts +35 -0
- package/src/render/webpack.ts +33 -0
- package/src/render/worker.ts +65 -0
- package/src/scene/assets/fonts/TitanOne-OFL.txt +94 -0
- package/src/scene/assets/fonts/titan-one.woff2 +0 -0
- package/src/scene/assets/gsap/LICENSE.txt +8 -0
- package/src/scene/assets/gsap/gsap.min.js +11 -0
- package/src/scene/audio.ts +54 -0
- package/src/scene/blocks/LICENSE +190 -0
- package/src/scene/blocks/NOTICE +5 -0
- package/src/scene/blocks/bar-chart-race/bar-chart-race.html +585 -0
- package/src/scene/blocks/beat-freeze-cut/beat-freeze-cut.html +874 -0
- package/src/scene/blocks/camcorder-hud/camcorder-hud.html +164 -0
- package/src/scene/blocks/camera-dolly-zoom/camera-dolly-zoom.html +355 -0
- package/src/scene/blocks/code-diff/code-diff.html +817 -0
- package/src/scene/blocks/code-snippet-apple-terminal-pro/code-snippet-apple-terminal-pro.html +248 -0
- package/src/scene/blocks/code-typing/code-typing.html +764 -0
- package/src/scene/blocks/data-chart/data-chart.html +452 -0
- package/src/scene/blocks/flowchart-vertical/flowchart-vertical.html +454 -0
- package/src/scene/blocks/hw-scribble-transition/hw-scribble-transition.html +153 -0
- package/src/scene/blocks/index.json +824 -0
- package/src/scene/blocks/lt-accent-underline/lt-accent-underline.html +107 -0
- package/src/scene/blocks/lt-bold-block/lt-bold-block.html +109 -0
- package/src/scene/blocks/lt-clean-bar/lt-clean-bar.html +112 -0
- package/src/scene/blocks/lt-dark-card/lt-dark-card.html +111 -0
- package/src/scene/blocks/lt-kicker-name/lt-kicker-name.html +114 -0
- package/src/scene/blocks/lt-mask-reveal/lt-mask-reveal.html +120 -0
- package/src/scene/blocks/lt-neon-border/lt-neon-border.html +391 -0
- package/src/scene/blocks/lt-stack-bars/lt-stack-bars.html +109 -0
- package/src/scene/blocks/macos-notification/macos-notification.html +194 -0
- package/src/scene/blocks/mk-background/mk-background.html +236 -0
- package/src/scene/blocks/mk-callout-highlight/mk-callout-highlight.html +183 -0
- package/src/scene/blocks/mk-clone-wall-transition/mk-clone-wall-transition.html +226 -0
- package/src/scene/blocks/mk-line-graph/mk-line-graph.html +293 -0
- package/src/scene/blocks/mk-progress-stat/mk-progress-stat.html +186 -0
- package/src/scene/blocks/mk-specs-list/mk-specs-list.html +223 -0
- package/src/scene/blocks/news-ticker/news-ticker.html +409 -0
- package/src/scene/blocks/organic-light-leak-overlay/organic-light-leak-overlay.html +126 -0
- package/src/scene/blocks/oscilloscope-trace/oscilloscope-trace.html +519 -0
- package/src/scene/blocks/snow/snow.html +205 -0
- package/src/scene/blocks/split-flap-board/split-flap-board.html +347 -0
- package/src/scene/blocks/spotify-card/spotify-card.html +294 -0
- package/src/scene/blocks/starfield/starfield.html +188 -0
- package/src/scene/blocks/thread-message-stack/thread-message-stack.html +239 -0
- package/src/scene/blocks/week-in-merges/week-in-merges.html +470 -0
- package/src/scene/blocks/x-post/x-post.html +437 -0
- package/src/scene/blocks/yt-comment-card/yt-comment-card.html +319 -0
- package/src/scene/blocks/yt-lcd-background/yt-lcd-background.html +307 -0
- package/src/scene/blocks/yt-prism-title/yt-prism-title.html +205 -0
- package/src/scene/blocks.ts +229 -0
- package/src/scene/command.ts +272 -0
- package/src/scene/figure.ts +181 -0
- package/src/scene/glyphs.ts +107 -0
- package/src/scene/init.ts +86 -0
- package/src/scene/inspect/css-tree.d.ts +6 -0
- package/src/scene/inspect/page-scripts.ts +272 -0
- package/src/scene/inspect/report.ts +405 -0
- package/src/scene/inspect/run.ts +200 -0
- package/src/scene/inspect/source.ts +236 -0
- package/src/scene/label.ts +131 -0
- package/src/scene/net-guard.ts +74 -0
- package/src/scene/render.ts +292 -0
- package/src/scene/runtime/browser.ts +199 -0
- package/src/scene/runtime/core.ts +181 -0
- package/src/scene/runtime/react.tsx +115 -0
- package/src/scene/runtime/transitions.ts +133 -0
- package/src/scene/sanitize.ts +181 -0
- package/src/scene/scene.ts +152 -0
- package/src/scene/studio-command.ts +48 -0
- package/src/scene/studio-skin.ts +59 -0
- package/src/scene/studio.ts +337 -0
- package/src/scene/supply.ts +111 -0
- package/src/scene/timing.ts +288 -0
- package/src/scene/transitions/LICENSE +190 -0
- package/src/scene/transitions/NOTICE +5 -0
- package/src/scene/transitions/SOURCE.json +24 -0
- package/src/scene/transitions/transitions.global.js +38 -0
- package/src/scene/transitions.ts +26 -0
- package/src/service/all-projects.ts +153 -0
- package/src/service/commands.ts +256 -0
- package/src/service/due.ts +82 -0
- package/src/service/lock.ts +101 -0
- package/src/service/log-file.ts +56 -0
- package/src/service/state.ts +41 -0
- package/src/service/units.ts +90 -0
- package/src/service/worker.ts +51 -0
- package/src/skill-agents.ts +74 -0
- package/src/skill-install.ts +334 -0
- package/src/sync-write.ts +21 -0
- package/src/tick-report.ts +205 -0
- package/src/tts.ts +124 -0
- package/vendor/@vfrey/contracts/dist/account.d.ts +97 -0
- package/vendor/@vfrey/contracts/dist/account.js +27 -0
- package/vendor/@vfrey/contracts/dist/checks.d.ts +8 -0
- package/vendor/@vfrey/contracts/dist/checks.js +1 -0
- package/vendor/@vfrey/contracts/dist/credentials/crypto.d.ts +4 -0
- package/vendor/@vfrey/contracts/dist/credentials/crypto.js +38 -0
- package/vendor/@vfrey/contracts/dist/domain/advice-persona.d.ts +10 -0
- package/vendor/@vfrey/contracts/dist/domain/advice-persona.js +24 -0
- package/vendor/@vfrey/contracts/dist/domain/backoff.d.ts +13 -0
- package/vendor/@vfrey/contracts/dist/domain/backoff.js +27 -0
- package/vendor/@vfrey/contracts/dist/domain/cadence.d.ts +29 -0
- package/vendor/@vfrey/contracts/dist/domain/cadence.js +95 -0
- package/vendor/@vfrey/contracts/dist/domain/creators.d.ts +146 -0
- package/vendor/@vfrey/contracts/dist/domain/creators.js +2 -0
- package/vendor/@vfrey/contracts/dist/domain/disclosure.d.ts +127 -0
- package/vendor/@vfrey/contracts/dist/domain/disclosure.js +250 -0
- package/vendor/@vfrey/contracts/dist/domain/errors.d.ts +34 -0
- package/vendor/@vfrey/contracts/dist/domain/errors.js +68 -0
- package/vendor/@vfrey/contracts/dist/domain/redact.d.ts +1 -0
- package/vendor/@vfrey/contracts/dist/domain/redact.js +21 -0
- package/vendor/@vfrey/contracts/dist/domain/revenue.d.ts +13 -0
- package/vendor/@vfrey/contracts/dist/domain/revenue.js +16 -0
- package/vendor/@vfrey/contracts/dist/domain/safety.d.ts +20 -0
- package/vendor/@vfrey/contracts/dist/domain/safety.js +61 -0
- package/vendor/@vfrey/contracts/dist/domain/similarity.d.ts +13 -0
- package/vendor/@vfrey/contracts/dist/domain/similarity.js +100 -0
- package/vendor/@vfrey/contracts/dist/domain/templates.d.ts +18 -0
- package/vendor/@vfrey/contracts/dist/domain/templates.js +67 -0
- package/vendor/@vfrey/contracts/dist/domain/tiktok-chunks.d.ts +19 -0
- package/vendor/@vfrey/contracts/dist/domain/tiktok-chunks.js +52 -0
- package/vendor/@vfrey/contracts/dist/domain/topics.d.ts +78 -0
- package/vendor/@vfrey/contracts/dist/domain/topics.js +4 -0
- package/vendor/@vfrey/contracts/dist/domain/types.d.ts +216 -0
- package/vendor/@vfrey/contracts/dist/domain/types.js +1 -0
- package/vendor/@vfrey/contracts/dist/domain/variation.d.ts +57 -0
- package/vendor/@vfrey/contracts/dist/domain/variation.js +278 -0
- package/vendor/@vfrey/contracts/dist/events.d.ts +20 -0
- package/vendor/@vfrey/contracts/dist/events.js +1 -0
- package/vendor/@vfrey/contracts/dist/http.d.ts +11 -0
- package/vendor/@vfrey/contracts/dist/http.js +37 -0
- package/vendor/@vfrey/contracts/dist/index.d.ts +22 -0
- package/vendor/@vfrey/contracts/dist/index.js +22 -0
- package/vendor/@vfrey/contracts/dist/log.d.ts +2 -0
- package/vendor/@vfrey/contracts/dist/log.js +10 -0
- package/vendor/@vfrey/contracts/dist/mail.d.ts +55 -0
- package/vendor/@vfrey/contracts/dist/mail.js +1 -0
- package/vendor/@vfrey/contracts/package.json +18 -0
- package/vendor/@vfrey/ingest/dist/index.d.ts +41 -0
- package/vendor/@vfrey/ingest/dist/index.js +221 -0
- package/vendor/@vfrey/ingest/dist/parse.d.ts +5 -0
- package/vendor/@vfrey/ingest/dist/parse.js +165 -0
- package/vendor/@vfrey/ingest/package.json +21 -0
- package/vendor/framey/LICENSE +190 -0
- package/vendor/framey/NOTICE +15 -0
- package/vendor/framey/SOURCE.json +24 -0
- package/vendor/framey/STUDIO-SOURCE.json +9 -0
- package/vendor/framey/bin/framey-localize-fonts.mjs +12 -0
- package/vendor/framey/bin/framey.mjs +16 -0
- package/vendor/framey/dist/add-VMJD5KBS.js +75 -0
- package/vendor/framey/dist/animatedGifPrep-QPKGJ6PM.js +43 -0
- package/vendor/framey/dist/api.d.ts +211 -0
- package/vendor/framey/dist/api.js +76 -0
- package/vendor/framey/dist/appHistory-WW56FZTT.js +31 -0
- package/vendor/framey/dist/asset-WQKGOELE.js +26 -0
- package/vendor/framey/dist/audio-RSJWVWRA.js +1936 -0
- package/vendor/framey/dist/batchRender-3HPICDCT.js +366 -0
- package/vendor/framey/dist/beats-HL2BDUZI.js +273 -0
- package/vendor/framey/dist/benchmark-RWCWHI5Z.js +230 -0
- package/vendor/framey/dist/browser-ECYET3Q2.js +206 -0
- package/vendor/framey/dist/bundleWithLocalizedFonts-ALYBQEQT.js +52 -0
- package/vendor/framey/dist/captureCompositionFrame-4DA6SEH2.js +94 -0
- package/vendor/framey/dist/catalog-5JVDEUWK.js +979 -0
- package/vendor/framey/dist/catch-up-NEBCL5NO.js +106 -0
- package/vendor/framey/dist/check-F5N544ML.js +111 -0
- package/vendor/framey/dist/checkBrowser-LZ66CMJG.js +110 -0
- package/vendor/framey/dist/chunk-2K7Z2HVP.js +372 -0
- package/vendor/framey/dist/chunk-2UZQHDM7.js +323 -0
- package/vendor/framey/dist/chunk-2X4PQEYM.js +34 -0
- package/vendor/framey/dist/chunk-3422KMTD.js +168 -0
- package/vendor/framey/dist/chunk-3FYD4YEK.js +72 -0
- package/vendor/framey/dist/chunk-3GXQPCJC.js +682 -0
- package/vendor/framey/dist/chunk-3LM6YPBR.js +179 -0
- package/vendor/framey/dist/chunk-442JNXRM.js +20 -0
- package/vendor/framey/dist/chunk-4BNN5FGX.js +182 -0
- package/vendor/framey/dist/chunk-4P7NX5BM.js +11532 -0
- package/vendor/framey/dist/chunk-4UMPIPCQ.js +88 -0
- package/vendor/framey/dist/chunk-4YYJOFKS.js +28 -0
- package/vendor/framey/dist/chunk-54HJ63Q2.js +29 -0
- package/vendor/framey/dist/chunk-5ETJX6WM.js +89 -0
- package/vendor/framey/dist/chunk-5SG54JRS.js +68 -0
- package/vendor/framey/dist/chunk-634HSJ3J.js +58 -0
- package/vendor/framey/dist/chunk-66LREXGS.js +48 -0
- package/vendor/framey/dist/chunk-6BEFEWFB.js +25 -0
- package/vendor/framey/dist/chunk-6BNTGNGD.js +286 -0
- package/vendor/framey/dist/chunk-6DDPOHMK.js +140 -0
- package/vendor/framey/dist/chunk-6GV5XSOR.js +214 -0
- package/vendor/framey/dist/chunk-6JR2XUEE.js +127 -0
- package/vendor/framey/dist/chunk-73QVATIM.js +362 -0
- package/vendor/framey/dist/chunk-7FMUTGOH.js +279 -0
- package/vendor/framey/dist/chunk-7JQFJ6JJ.js +291 -0
- package/vendor/framey/dist/chunk-AHPGAESX.js +113 -0
- package/vendor/framey/dist/chunk-AHX34EFP.js +15 -0
- package/vendor/framey/dist/chunk-AJ5CSAEZ.js +487 -0
- package/vendor/framey/dist/chunk-B7RJV74O.js +5047 -0
- package/vendor/framey/dist/chunk-BL4U6U52.js +254 -0
- package/vendor/framey/dist/chunk-BSQ7XANM.js +210 -0
- package/vendor/framey/dist/chunk-BZ56MTDX.js +6 -0
- package/vendor/framey/dist/chunk-C5BO7PMT.js +282 -0
- package/vendor/framey/dist/chunk-CFUCHO4T.js +358 -0
- package/vendor/framey/dist/chunk-CZGHFATT.js +31 -0
- package/vendor/framey/dist/chunk-DLA44CMS.js +5649 -0
- package/vendor/framey/dist/chunk-DPVXBVLL.js +31292 -0
- package/vendor/framey/dist/chunk-DQBY7FRR.js +397 -0
- package/vendor/framey/dist/chunk-EAMLBAHA.js +154 -0
- package/vendor/framey/dist/chunk-EOVYQ3IG.js +143 -0
- package/vendor/framey/dist/chunk-EVMY7IPL.js +612 -0
- package/vendor/framey/dist/chunk-FG4BBFZI.js +122 -0
- package/vendor/framey/dist/chunk-FI4I7CME.js +56 -0
- package/vendor/framey/dist/chunk-FLREUEHW.js +2081 -0
- package/vendor/framey/dist/chunk-FUFP7A7S.js +1126 -0
- package/vendor/framey/dist/chunk-FV3PIKGH.js +56 -0
- package/vendor/framey/dist/chunk-FXMKHHPO.js +123 -0
- package/vendor/framey/dist/chunk-GGZAM5VH.js +1187 -0
- package/vendor/framey/dist/chunk-GKZEVJIB.js +39 -0
- package/vendor/framey/dist/chunk-GMECXFAN.js +57 -0
- package/vendor/framey/dist/chunk-GNEFDLFB.js +621 -0
- package/vendor/framey/dist/chunk-GPMLSOEG.js +19274 -0
- package/vendor/framey/dist/chunk-GPYVT5EE.js +59 -0
- package/vendor/framey/dist/chunk-H6IEMZEV.js +40 -0
- package/vendor/framey/dist/chunk-HEFQCIXR.js +170 -0
- package/vendor/framey/dist/chunk-HFQ4CWHA.js +118 -0
- package/vendor/framey/dist/chunk-HPDTCOKE.js +304 -0
- package/vendor/framey/dist/chunk-HTUHQKDB.js +548 -0
- package/vendor/framey/dist/chunk-HU2SPFNG.js +103 -0
- package/vendor/framey/dist/chunk-HVW7ABXD.js +19 -0
- package/vendor/framey/dist/chunk-IG7NDKXO.js +26 -0
- package/vendor/framey/dist/chunk-II3J3WXK.js +246 -0
- package/vendor/framey/dist/chunk-IR35BCLK.js +13 -0
- package/vendor/framey/dist/chunk-ISN5GRYI.js +20 -0
- package/vendor/framey/dist/chunk-IUONB55J.js +669 -0
- package/vendor/framey/dist/chunk-IVSUQR2B.js +161 -0
- package/vendor/framey/dist/chunk-IXU6PQSW.js +259 -0
- package/vendor/framey/dist/chunk-IZCW2NKT.js +29 -0
- package/vendor/framey/dist/chunk-JGXJU5PF.js +68 -0
- package/vendor/framey/dist/chunk-JHOCK3DG.js +27 -0
- package/vendor/framey/dist/chunk-JVBRJMOP.js +121 -0
- package/vendor/framey/dist/chunk-K4MJX7SR.js +17 -0
- package/vendor/framey/dist/chunk-K4WKGXRC.js +18 -0
- package/vendor/framey/dist/chunk-KGPLIH7B.js +127 -0
- package/vendor/framey/dist/chunk-KLIKCX6Q.js +63 -0
- package/vendor/framey/dist/chunk-KXTKKBOC.js +61 -0
- package/vendor/framey/dist/chunk-KZI44OPA.js +185 -0
- package/vendor/framey/dist/chunk-LEKZNRKI.js +45 -0
- package/vendor/framey/dist/chunk-LFGJWOVA.js +61 -0
- package/vendor/framey/dist/chunk-LLMSX6V6.js +17 -0
- package/vendor/framey/dist/chunk-LTGTN2TH.js +195 -0
- package/vendor/framey/dist/chunk-M2WBOQ2Q.js +54 -0
- package/vendor/framey/dist/chunk-MI5FTLYK.js +399 -0
- package/vendor/framey/dist/chunk-MLQP2QUF.js +1809 -0
- package/vendor/framey/dist/chunk-MMQ52NIZ.js +956 -0
- package/vendor/framey/dist/chunk-ND46XKK3.js +742 -0
- package/vendor/framey/dist/chunk-NYEXNSHM.js +504 -0
- package/vendor/framey/dist/chunk-O4YRB27L.js +57 -0
- package/vendor/framey/dist/chunk-O7BGSQ5F.js +92 -0
- package/vendor/framey/dist/chunk-OFQWTKPW.js +117 -0
- package/vendor/framey/dist/chunk-P5ZBLXJ6.js +91 -0
- package/vendor/framey/dist/chunk-P6LJ4Y32.js +4662 -0
- package/vendor/framey/dist/chunk-PKZ7RK5N.js +281 -0
- package/vendor/framey/dist/chunk-PURHAXFL.js +15 -0
- package/vendor/framey/dist/chunk-Q5X2B5WT.js +29 -0
- package/vendor/framey/dist/chunk-QAMKOG67.js +248 -0
- package/vendor/framey/dist/chunk-R6YBK4XX.js +514 -0
- package/vendor/framey/dist/chunk-RGLQURIX.js +2997 -0
- package/vendor/framey/dist/chunk-RNV3DM4S.js +3573 -0
- package/vendor/framey/dist/chunk-ROEW726S.js +4638 -0
- package/vendor/framey/dist/chunk-RQVDTPGD.js +6 -0
- package/vendor/framey/dist/chunk-RVZHGOGR.js +26 -0
- package/vendor/framey/dist/chunk-RXATE6FZ.js +385 -0
- package/vendor/framey/dist/chunk-S3S4TGEH.js +424 -0
- package/vendor/framey/dist/chunk-SDYDNHEE.js +11202 -0
- package/vendor/framey/dist/chunk-SSWBU67I.js +173 -0
- package/vendor/framey/dist/chunk-ST35C4K6.js +28 -0
- package/vendor/framey/dist/chunk-SZNTYTIV.js +990 -0
- package/vendor/framey/dist/chunk-T2EUWCJE.js +29 -0
- package/vendor/framey/dist/chunk-T6AGUTZJ.js +444 -0
- package/vendor/framey/dist/chunk-THJALHFJ.js +11131 -0
- package/vendor/framey/dist/chunk-TIQB63MX.js +18128 -0
- package/vendor/framey/dist/chunk-U242RTCT.js +134 -0
- package/vendor/framey/dist/chunk-UJZREAV6.js +3901 -0
- package/vendor/framey/dist/chunk-UMD3V7CU.js +264 -0
- package/vendor/framey/dist/chunk-UOFAE5RF.js +42 -0
- package/vendor/framey/dist/chunk-UTEIUGAZ.js +29 -0
- package/vendor/framey/dist/chunk-VAS6HQX3.js +138 -0
- package/vendor/framey/dist/chunk-VC76R6W2.js +27 -0
- package/vendor/framey/dist/chunk-VFZ7W5W7.js +226 -0
- package/vendor/framey/dist/chunk-VHNLZAE2.js +348 -0
- package/vendor/framey/dist/chunk-VMC4WSH5.js +278 -0
- package/vendor/framey/dist/chunk-VORQIH64.js +108 -0
- package/vendor/framey/dist/chunk-VTXFRIHO.js +186 -0
- package/vendor/framey/dist/chunk-W2LGJSEN.js +182 -0
- package/vendor/framey/dist/chunk-WKBM7NDG.js +32 -0
- package/vendor/framey/dist/chunk-WMQNIQDJ.js +2057 -0
- package/vendor/framey/dist/chunk-WN4XZC5F.js +504 -0
- package/vendor/framey/dist/chunk-WQ6ZXHFQ.js +133 -0
- package/vendor/framey/dist/chunk-X7HBSTCZ.js +53 -0
- package/vendor/framey/dist/chunk-X7MTZ4T2.js +6 -0
- package/vendor/framey/dist/chunk-XPTOJZJF.js +308 -0
- package/vendor/framey/dist/chunk-XT6MXC7A.js +6 -0
- package/vendor/framey/dist/chunk-XT7X6QCP.js +6 -0
- package/vendor/framey/dist/chunk-XTMDWNEC.js +2820 -0
- package/vendor/framey/dist/chunk-XUHOIDKG.js +6 -0
- package/vendor/framey/dist/chunk-XX7LTW5Y.js +138 -0
- package/vendor/framey/dist/chunk-Y3YGTZEG.js +382 -0
- package/vendor/framey/dist/chunk-Y5SBSGN7.js +346 -0
- package/vendor/framey/dist/chunk-YCMVI4MZ.js +625 -0
- package/vendor/framey/dist/chunk-YOR4CTCE.js +261 -0
- package/vendor/framey/dist/chunk-YPRBGITP.js +2748 -0
- package/vendor/framey/dist/chunk-ZKDMAOFU.js +32 -0
- package/vendor/framey/dist/chunk-ZW6DURPF.js +1318 -0
- package/vendor/framey/dist/clean-ZJOGDKDM.js +336 -0
- package/vendor/framey/dist/cli.js +439 -0
- package/vendor/framey/dist/cloudrun-HGJ3B6ZV.js +767 -0
- package/vendor/framey/dist/commands/contrast-audit.browser.js +643 -0
- package/vendor/framey/dist/commands/layout-audit.browser.js +2914 -0
- package/vendor/framey/dist/commands/motion-sample.browser.js +74 -0
- package/vendor/framey/dist/commands/motion-signature.browser.js +475 -0
- package/vendor/framey/dist/compare-W7UY3BAZ.js +463 -0
- package/vendor/framey/dist/compiler-TM3W6GYF.js +136 -0
- package/vendor/framey/dist/component-QF5VGYMU.js +176 -0
- package/vendor/framey/dist/compositions-XT3PMNDF.js +238 -0
- package/vendor/framey/dist/contactSheet-7W6GYHBQ.js +24 -0
- package/vendor/framey/dist/deploy-6FJPWKF2.js +299 -0
- package/vendor/framey/dist/destroy-HE2RIPKZ.js +57 -0
- package/vendor/framey/dist/deterministicFonts-RADD3BSX.js +50 -0
- package/vendor/framey/dist/dist-4S2FGGVY.js +422 -0
- package/vendor/framey/dist/dist-BE4B2EZE.js +32 -0
- package/vendor/framey/dist/dist-EWXJGN63.js +129 -0
- package/vendor/framey/dist/docs-VKIRFEEX.js +131 -0
- package/vendor/framey/dist/doctor-2UNJ2G7U.js +74 -0
- package/vendor/framey/dist/dom-37K6YOH4.js +14 -0
- package/vendor/framey/dist/dotEnv-7PZQTVIM.js +54 -0
- package/vendor/framey/dist/events-ACY3P2PA.js +76 -0
- package/vendor/framey/dist/events-IHB3B2MK.js +69 -0
- package/vendor/framey/dist/ffmpeg-DR5LGGSK.js +63 -0
- package/vendor/framey/dist/figma-BODVUPHB.js +63 -0
- package/vendor/framey/dist/fontData.generated-NXAOI4GH.js +13 -0
- package/vendor/framey/dist/fontLocalizeCli.js +142 -0
- package/vendor/framey/dist/gpuPolicy-XLEXORZY.js +49 -0
- package/vendor/framey/dist/grade-compare-GAXFQ74C.js +661 -0
- package/vendor/framey/dist/gsapParser-IEUSLYDJ.js +2885 -0
- package/vendor/framey/dist/gsapParserAcorn-LZJKCFQI.js +30 -0
- package/vendor/framey/dist/help-VCB5X2HS.js +184 -0
- package/vendor/framey/dist/history-ENGZEVFT.js +471 -0
- package/vendor/framey/dist/hyperframe.manifest.json +22 -0
- package/vendor/framey/dist/hyperframe.runtime.iife.js +1132 -0
- package/vendor/framey/dist/hyperframes-player.global.js +478 -0
- package/vendor/framey/dist/hyperframes-slideshow.global.js +148 -0
- package/vendor/framey/dist/info-WPCJHBMU.js +182 -0
- package/vendor/framey/dist/init-G4WGLYGD.js +1176 -0
- package/vendor/framey/dist/inspect-5IQ6CNEQ.js +106 -0
- package/vendor/framey/dist/installer-ML4HWUV7.js +40 -0
- package/vendor/framey/dist/keyframes-Q6XJO7VW.js +2755 -0
- package/vendor/framey/dist/lambda-A7JC74JF.js +468 -0
- package/vendor/framey/dist/layout-YET6XNXA.js +95 -0
- package/vendor/framey/dist/lint-I7FZN2VJ.js +162 -0
- package/vendor/framey/dist/lintProject-PDB3UN72.js +30 -0
- package/vendor/framey/dist/manager-CD6LJ7ZN.js +45 -0
- package/vendor/framey/dist/manager-WA4F2GST.js +67 -0
- package/vendor/framey/dist/media-treatment-BXYS4WVA.js +1030 -0
- package/vendor/framey/dist/media-use-LWH3MANK.js +113 -0
- package/vendor/framey/dist/models-K363FYM4.js +195 -0
- package/vendor/framey/dist/motionShot-GPAVWXLH.js +640 -0
- package/vendor/framey/dist/normalize-FASIPBUM.js +24 -0
- package/vendor/framey/dist/normalize-audio-VDWYRHN6.js +268 -0
- package/vendor/framey/dist/open-E3TB6P6J.js +128 -0
- package/vendor/framey/dist/parakeetRunner-UP34UOI2.js +58 -0
- package/vendor/framey/dist/pipeline-VXIUYEBU.js +64 -0
- package/vendor/framey/dist/play-BUTDQ4DV.js +353 -0
- package/vendor/framey/dist/policies-OLDYGFK5.js +309 -0
- package/vendor/framey/dist/preflight-2KZ2GWAZ.js +55 -0
- package/vendor/framey/dist/present-GXYSM7NX.js +353 -0
- package/vendor/framey/dist/preview-EKZ33JOJ.js +1910 -0
- package/vendor/framey/dist/producer-SKU5EV3J.js +13 -0
- package/vendor/framey/dist/progress-ZWB4Z4ET.js +76 -0
- package/vendor/framey/dist/projectConfig-3MZAYVTS.js +60 -0
- package/vendor/framey/dist/publication-DTKWNF74.js +33 -0
- package/vendor/framey/dist/remove-background-OY5L7XN2.js +265 -0
- package/vendor/framey/dist/render-CDV4GDFX.js +187 -0
- package/vendor/framey/dist/render-YE5YAMOD.js +2620 -0
- package/vendor/framey/dist/render-batch-ZAMFPCLL.js +274 -0
- package/vendor/framey/dist/renderSetupWorker.js +120 -0
- package/vendor/framey/dist/resolver-D5BIPSEW.js +42 -0
- package/vendor/framey/dist/runtimeVersion.js +18 -0
- package/vendor/framey/dist/sam-WFZXI4F7.js +23 -0
- package/vendor/framey/dist/shaderTransitionWorker.js +44 -0
- package/vendor/framey/dist/sherpa-RQWLV7I3.js +79 -0
- package/vendor/framey/dist/sherpaWorker.js +84 -0
- package/vendor/framey/dist/sites-AMOVABTK.js +54 -0
- package/vendor/framey/dist/skill-ZHVLH7KX.js +15 -0
- package/vendor/framey/dist/slideshow-SJGK4RQS.js +24 -0
- package/vendor/framey/dist/snapshot-TUXL6LBQ.js +1515 -0
- package/vendor/framey/dist/src-JHQGB2S6.js +215 -0
- package/vendor/framey/dist/src-Z5PGEMXB.js +532 -0
- package/vendor/framey/dist/state-B6H3WHCF.js +28 -0
- package/vendor/framey/dist/staticProjectServer-DFVZOUGI.js +63 -0
- package/vendor/framey/dist/studio/assets/hyperframes-player-DLaKjw0L.js +478 -0
- package/vendor/framey/dist/studio/assets/index-BX3KHhGX.js +71 -0
- package/vendor/framey/dist/studio/assets/index-CYbvOVp-.css +1 -0
- package/vendor/framey/dist/studio/assets/index-Dp3QEUGL.js +402 -0
- package/vendor/framey/dist/studio/assets/index-qrTAXbqc.js +531 -0
- package/vendor/framey/dist/studio/favicon.svg +14 -0
- package/vendor/framey/dist/studio/icons/timeline/audio.svg +7 -0
- package/vendor/framey/dist/studio/icons/timeline/captions.svg +5 -0
- package/vendor/framey/dist/studio/icons/timeline/composition.svg +12 -0
- package/vendor/framey/dist/studio/icons/timeline/image.svg +18 -0
- package/vendor/framey/dist/studio/icons/timeline/music.svg +10 -0
- package/vendor/framey/dist/studio/icons/timeline/text.svg +3 -0
- package/vendor/framey/dist/studio/index.html +23 -0
- package/vendor/framey/dist/studio-api-2NECGRMB.js +179 -0
- package/vendor/framey/dist/studioSelectionClient-IUUPKUHZ.js +25 -0
- package/vendor/framey/dist/studioServer-N2OPUMOQ.js +1569 -0
- package/vendor/framey/dist/synthesize-PKTB5ATG.js +183 -0
- package/vendor/framey/dist/system-7F3UEHQT.js +27 -0
- package/vendor/framey/dist/telemetry-DQGPEKM6.js +145 -0
- package/vendor/framey/dist/telemetry-UN55N6U6.js +77 -0
- package/vendor/framey/dist/timeline-LHUUMK63.js +1295 -0
- package/vendor/framey/dist/tokens-OLECWDFK.js +92 -0
- package/vendor/framey/dist/transcribe-O7HQKMIV.js +331 -0
- package/vendor/framey/dist/transcribe-UJESPBT5.js +76 -0
- package/vendor/framey/dist/tts-YCCQHZD4.js +234 -0
- package/vendor/framey/dist/urlDownloader-H2LXLG4U.js +48 -0
- package/vendor/framey/dist/usage-HG4WMM7A.js +2167 -0
- package/vendor/framey/dist/validate-F2XMN6EV.js +87 -0
- package/vendor/framey/dist/vendor/npm/gsap@3.15.0/GSAP-LICENSE.txt +8 -0
- package/vendor/framey/dist/vendor/npm/gsap@3.15.0/dist/CustomEase.min.js +11 -0
- package/vendor/framey/dist/vendor/npm/gsap@3.15.0/dist/MotionPathPlugin.min.js +11 -0
- package/vendor/framey/dist/vendor/npm/gsap@3.15.0/dist/gsap.min.js +11 -0
- package/vendor/framey/dist/warmCheck.js +220 -0
- package/vendor/framey/dist/warmCheckClient.js +139 -0
- package/vendor/framey/dist/workspaceBuildCheck-XYD2YTFW.js +133 -0
- package/vendor/framey-player/LICENSE +190 -0
- package/vendor/framey-player/NOTICE +16 -0
- package/vendor/framey-player/SOURCE.json +6 -0
- package/vendor/framey-player/hyperframes-player.global.js +478 -0
- package/vendor/framey.pin +1 -0
- package/bin/index.js +0 -3
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
// Browser-side WCAG contrast audit, injected as a raw string so esbuild can't mangle it.
|
|
2
|
+
// __contrastAuditPrepare() hides each text element's own paint (layout-neutral) and returns candidates;
|
|
3
|
+
// the caller takes one screenshot, full frame or clipped to the candidates (collectContrast in checkBrowser.ts);
|
|
4
|
+
// __contrastAuditFinish(png, time, candidates, region) restores paint first, then samples inside each box.
|
|
5
|
+
|
|
6
|
+
// Sampling inside the box reads the exact pixels behind the glyphs; a ring outside the text misreads
|
|
7
|
+
// neighbouring panels, rounded pills, blurred glass and partial decorations.
|
|
8
|
+
// __contrastAuditRestoreIfPending() restores hidden paint if the screenshot or finish() throws.
|
|
9
|
+
|
|
10
|
+
// The "which rect to sample" decision is mirrored and unit-tested in contrast-sample.ts.
|
|
11
|
+
|
|
12
|
+
/* eslint-disable */
|
|
13
|
+
window.__contrastAuditPrepare = function () {
|
|
14
|
+
// SVG text (<text>, <tspan>, <textPath>) is painted via the `fill`
|
|
15
|
+
// property, not `color` — the two are independent CSS properties in SVG.
|
|
16
|
+
// A page can set `fill` (inline style, `fill` attribute, or a CSS rule)
|
|
17
|
+
// without ever touching `color`, in which case getComputedStyle(el).color
|
|
18
|
+
// resolves to the inherited/initial value (often black) and does not
|
|
19
|
+
// reflect what's actually rendered on screen.
|
|
20
|
+
function isSvgTextElement(el) {
|
|
21
|
+
return !!el.ownerSVGElement;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Raster-free contrast: a leaf text box whose backdrop is provably one opaque CSS colour needs no
|
|
25
|
+
// screenshot. Anything this cannot prove (overlays, images, blending, rotation, round corners) returns null.
|
|
26
|
+
var REPLACED = /^(IMG|VIDEO|CANVAS|IFRAME|OBJECT|EMBED|INPUT|TEXTAREA|SELECT|svg|PICTURE)$/;
|
|
27
|
+
var paintCache = new Map();
|
|
28
|
+
function blends(cs) {
|
|
29
|
+
return (
|
|
30
|
+
cs.opacity !== "1" ||
|
|
31
|
+
cs.filter !== "none" ||
|
|
32
|
+
(cs.backdropFilter || cs.webkitBackdropFilter || "none") !== "none" ||
|
|
33
|
+
cs.mixBlendMode !== "normal" ||
|
|
34
|
+
(cs.maskImage || cs.webkitMaskImage || "none") !== "none" ||
|
|
35
|
+
cs.clipPath !== "none"
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
function axisAligned(cs) {
|
|
39
|
+
var t = cs.transform;
|
|
40
|
+
if (t === "none") return true;
|
|
41
|
+
var m = t.match(/^matrix\(([^)]+)\)$/);
|
|
42
|
+
if (!m) return false;
|
|
43
|
+
var v = m[1].split(",").map(parseFloat);
|
|
44
|
+
return v[1] === 0 && v[2] === 0;
|
|
45
|
+
}
|
|
46
|
+
function pseudoPaints(el) {
|
|
47
|
+
return ["::before", "::after"].some(function (pseudo) {
|
|
48
|
+
var content = getComputedStyle(el, pseudo).content;
|
|
49
|
+
return content !== "none" && content !== "normal";
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function hasOwnText(el) {
|
|
53
|
+
for (var n = el.firstChild; n; n = n.nextSibling) {
|
|
54
|
+
if (n.nodeType === 3 && /\S/.test(n.nodeValue || "")) return true;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
function boxPaints(el, cs) {
|
|
59
|
+
var bg = parseColor(cs.backgroundColor || "");
|
|
60
|
+
return (
|
|
61
|
+
(cs.backgroundImage || "none") !== "none" ||
|
|
62
|
+
!bg ||
|
|
63
|
+
bg[3] !== 0 ||
|
|
64
|
+
["Top", "Right", "Bottom", "Left"].some(function (side) {
|
|
65
|
+
return (
|
|
66
|
+
cs["border" + side + "Style"] !== "none" && parseFloat(cs["border" + side + "Width"]) > 0
|
|
67
|
+
);
|
|
68
|
+
}) ||
|
|
69
|
+
cs.boxShadow !== "none" ||
|
|
70
|
+
(cs.outlineStyle !== "none" && parseFloat(cs.outlineWidth) > 0) ||
|
|
71
|
+
pseudoPaints(el)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
// True unless the element provably adds no pixels of its own.
|
|
75
|
+
function paints(el) {
|
|
76
|
+
if (paintCache.has(el)) return paintCache.get(el);
|
|
77
|
+
var cs = getComputedStyle(el);
|
|
78
|
+
var result =
|
|
79
|
+
cs.visibility === "hidden" && cs.filter === "none"
|
|
80
|
+
? false
|
|
81
|
+
: REPLACED.test(el.tagName) ||
|
|
82
|
+
!!el.ownerSVGElement ||
|
|
83
|
+
hasOwnText(el) ||
|
|
84
|
+
boxPaints(el, cs) ||
|
|
85
|
+
blends(cs);
|
|
86
|
+
paintCache.set(el, result);
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
function intersects(a, b) {
|
|
90
|
+
return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom;
|
|
91
|
+
}
|
|
92
|
+
function solidBackdrop(el, rect, cs) {
|
|
93
|
+
if (el.children.length > 0 || el.ownerSVGElement || cs.textShadow !== "none") return null;
|
|
94
|
+
if (cs.textDecorationLine !== "none" || boxPaints(el, cs) || !axisAligned(cs)) return null;
|
|
95
|
+
if ((cs.backdropFilter || cs.webkitBackdropFilter || "none") !== "none") return null;
|
|
96
|
+
var region = {
|
|
97
|
+
left: Math.max(0, rect.left),
|
|
98
|
+
top: Math.max(0, rect.top),
|
|
99
|
+
right: Math.min(window.innerWidth, rect.right),
|
|
100
|
+
bottom: Math.min(window.innerHeight, rect.bottom),
|
|
101
|
+
};
|
|
102
|
+
if (region.right <= region.left || region.bottom <= region.top) return null;
|
|
103
|
+
var chain = new Set([el]);
|
|
104
|
+
var solid = null;
|
|
105
|
+
for (var a = el.parentElement; a; a = a.parentElement) {
|
|
106
|
+
chain.add(a);
|
|
107
|
+
var acs = getComputedStyle(a);
|
|
108
|
+
if (blends(acs) || !axisAligned(acs) || pseudoPaints(a)) return null;
|
|
109
|
+
if (a === document.body || a === document.documentElement) {
|
|
110
|
+
if (!solid) solid = canvasColor(a, acs, region);
|
|
111
|
+
if (!solid && (a === document.documentElement || boxPaints(a, acs))) return null;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (solid) {
|
|
115
|
+
if (acs.overflow !== "visible" && !contains(a.getBoundingClientRect(), acs, region))
|
|
116
|
+
return null;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
var bg =
|
|
120
|
+
(acs.backgroundImage || "none") === "none" ? parseColor(acs.backgroundColor || "") : null;
|
|
121
|
+
if (bg && bg[3] === 1) {
|
|
122
|
+
var radius = ["TopLeft", "TopRight", "BottomRight", "BottomLeft"].some(function (corner) {
|
|
123
|
+
return parseFloat(acs["border" + corner + "Radius"]) > 0;
|
|
124
|
+
});
|
|
125
|
+
if (radius || !contains(a.getBoundingClientRect(), acs, region)) return null;
|
|
126
|
+
solid = bg;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (hasOwnText(a) || boxPaints(a, acs)) return null;
|
|
130
|
+
}
|
|
131
|
+
if (!solid) return null;
|
|
132
|
+
var all = document.querySelectorAll("*");
|
|
133
|
+
for (var i = 0; i < all.length; i++) {
|
|
134
|
+
var other = all[i];
|
|
135
|
+
if (chain.has(other) || !intersects(other.getBoundingClientRect(), region)) continue;
|
|
136
|
+
if (paints(other)) return null;
|
|
137
|
+
}
|
|
138
|
+
return [solid[0], solid[1], solid[2]];
|
|
139
|
+
}
|
|
140
|
+
// body's background paints the whole canvas unless html has its own (CSS background propagation).
|
|
141
|
+
function canvasColor(el, cs, region) {
|
|
142
|
+
var bg =
|
|
143
|
+
(cs.backgroundImage || "none") === "none" ? parseColor(cs.backgroundColor || "") : null;
|
|
144
|
+
var html = document.documentElement;
|
|
145
|
+
var htmlCs = getComputedStyle(html);
|
|
146
|
+
var htmlBg = parseColor(htmlCs.backgroundColor || "");
|
|
147
|
+
var htmlPaints = (htmlCs.backgroundImage || "none") !== "none" || !htmlBg || htmlBg[3] !== 0;
|
|
148
|
+
if (el === html) return bg && bg[3] === 1 ? bg : null;
|
|
149
|
+
if (!bg || bg[3] !== 1) return null;
|
|
150
|
+
return htmlPaints && !contains(el.getBoundingClientRect(), cs, region) ? null : bg;
|
|
151
|
+
}
|
|
152
|
+
function contains(box, cs, region) {
|
|
153
|
+
return (
|
|
154
|
+
box.left + parseFloat(cs.borderLeftWidth) <= region.left &&
|
|
155
|
+
box.top + parseFloat(cs.borderTopWidth) <= region.top &&
|
|
156
|
+
box.right - parseFloat(cs.borderRightWidth) >= region.right &&
|
|
157
|
+
box.bottom - parseFloat(cs.borderBottomWidth) >= region.bottom
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function parseColor(c) {
|
|
162
|
+
var m = (c || "").match(/^rgba?\(([^)]+)\)$/i);
|
|
163
|
+
if (!m) {
|
|
164
|
+
var mix = (c || "").match(
|
|
165
|
+
/^color-mix\(\s*in\s+srgb\s*,\s*(rgba?\([^)]+\))\s+(\d+(?:\.\d+)?|\.\d+)%\s*,\s*(rgba?\([^)]+\))\s+(\d+(?:\.\d+)?|\.\d+)%\s*\)$/i,
|
|
166
|
+
);
|
|
167
|
+
if (!mix) return null;
|
|
168
|
+
var first = parseColor(mix[1]);
|
|
169
|
+
var second = parseColor(mix[3]);
|
|
170
|
+
var firstWeight = parseFloat(mix[2]);
|
|
171
|
+
var secondWeight = parseFloat(mix[4]);
|
|
172
|
+
var weightTotal = firstWeight + secondWeight;
|
|
173
|
+
if (!first || !second || !isFinite(weightTotal) || weightTotal <= 0) return null;
|
|
174
|
+
return first.map(function (channel, index) {
|
|
175
|
+
return (channel * firstWeight + second[index] * secondWeight) / weightTotal;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
var p = m[1].split(",").map(function (s) {
|
|
179
|
+
return parseFloat(s.trim());
|
|
180
|
+
});
|
|
181
|
+
if (
|
|
182
|
+
(p.length !== 3 && p.length !== 4) ||
|
|
183
|
+
p.some(function (v) {
|
|
184
|
+
return !isFinite(v);
|
|
185
|
+
})
|
|
186
|
+
)
|
|
187
|
+
return null;
|
|
188
|
+
return [p[0], p[1], p[2], p[3] != null ? p[3] : 1];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function selectorOf(el) {
|
|
192
|
+
if (el.id) return "#" + el.id;
|
|
193
|
+
var cls = Array.from(el.classList).slice(0, 2).join(".");
|
|
194
|
+
return cls ? el.tagName.toLowerCase() + "." + cls : el.tagName.toLowerCase();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function hasClipPath(el) {
|
|
198
|
+
for (var ce = el; ce; ce = ce.parentElement) {
|
|
199
|
+
var cp = getComputedStyle(ce).clipPath;
|
|
200
|
+
if (cp && cp !== "none") return true;
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
var CLIP_PROBE_COLS = [0.05, 0.25, 0.5, 0.75, 0.95];
|
|
206
|
+
var CLIP_PROBE_ROWS = [0.25, 0.5, 0.75];
|
|
207
|
+
|
|
208
|
+
var compositionBoxPaint = new WeakMap();
|
|
209
|
+
var COMPOSITION_BOX_TAGS = new Set(["DIV", "SECTION"]);
|
|
210
|
+
|
|
211
|
+
function hasContainerPaint(style) {
|
|
212
|
+
var background = parseColor(style.backgroundColor);
|
|
213
|
+
if (
|
|
214
|
+
style.backgroundColor &&
|
|
215
|
+
style.backgroundColor !== "transparent" &&
|
|
216
|
+
(!background || background[3] > 0)
|
|
217
|
+
)
|
|
218
|
+
return true;
|
|
219
|
+
if (
|
|
220
|
+
["backgroundImage", "boxShadow", "filter", "backdropFilter"].some(function (property) {
|
|
221
|
+
return style[property] && style[property] !== "none";
|
|
222
|
+
})
|
|
223
|
+
)
|
|
224
|
+
return true;
|
|
225
|
+
if (parseFloat(style.outlineWidth) > 0 && style.outlineStyle !== "none") return true;
|
|
226
|
+
return ["Top", "Right", "Bottom", "Left"].some(function (side) {
|
|
227
|
+
return (
|
|
228
|
+
parseFloat(style["border" + side + "Width"]) > 0 &&
|
|
229
|
+
style["border" + side + "Style"] !== "none"
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function isUnpaintedCompositionBox(el) {
|
|
235
|
+
if (!el || !el.matches("[data-composition-id], [data-hf-inner-root]")) return false;
|
|
236
|
+
if (!el.closest("[data-composition-id]")) return false;
|
|
237
|
+
if (
|
|
238
|
+
el.namespaceURI !== "http://www.w3.org/1999/xhtml" ||
|
|
239
|
+
!COMPOSITION_BOX_TAGS.has(el.tagName) ||
|
|
240
|
+
el.shadowRoot
|
|
241
|
+
)
|
|
242
|
+
return false;
|
|
243
|
+
if (compositionBoxPaint.has(el)) return !compositionBoxPaint.get(el);
|
|
244
|
+
var painted =
|
|
245
|
+
Array.from(el.childNodes).some(function (child) {
|
|
246
|
+
return child.nodeType === 3 && (child.textContent || "").trim().length > 0;
|
|
247
|
+
}) || hasContainerPaint(getComputedStyle(el));
|
|
248
|
+
if (!painted) {
|
|
249
|
+
painted = ["::before", "::after"].some(function (pseudo) {
|
|
250
|
+
var content = getComputedStyle(el, pseudo).content;
|
|
251
|
+
return content && content !== "none" && content !== "normal";
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
compositionBoxPaint.set(el, !!painted);
|
|
255
|
+
return !painted;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function paintsAnyProbePoint(el, rect, skipCompositionBoxes) {
|
|
259
|
+
// Keep probe resolution aligned with layout-audit.browser.js. Edge strips
|
|
260
|
+
// narrower than the nearest probe point are treated as clipped away to
|
|
261
|
+
// avoid noisy typewriter pre-reveal contrast reports.
|
|
262
|
+
for (var ci = 0; ci < CLIP_PROBE_COLS.length; ci++) {
|
|
263
|
+
for (var ri = 0; ri < CLIP_PROBE_ROWS.length; ri++) {
|
|
264
|
+
var x = rect.left + rect.width * CLIP_PROBE_COLS[ci];
|
|
265
|
+
var y = rect.top + rect.height * CLIP_PROBE_ROWS[ri];
|
|
266
|
+
var hits =
|
|
267
|
+
skipCompositionBoxes && typeof document.elementsFromPoint === "function"
|
|
268
|
+
? document.elementsFromPoint(x, y)
|
|
269
|
+
: [document.elementFromPoint(x, y)];
|
|
270
|
+
for (var hit of hits) {
|
|
271
|
+
if (hit === el || el.contains(hit)) return true;
|
|
272
|
+
if (!skipCompositionBoxes || !isUnpaintedCompositionBox(hit)) break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// A clip-path can shrink an element's painted region to nothing (a typewriter
|
|
280
|
+
// span pre-reveal at `inset(0 100% 0 0)`, or `circle(0px)`) while its box and
|
|
281
|
+
// colours read normally; it then paints zero pixels and measures a meaningless
|
|
282
|
+
// background-on-background ratio. clip-path drives hit-testing, so a fully
|
|
283
|
+
// clipped element is unreachable by elementFromPoint across its box. Probe only
|
|
284
|
+
// when a clip-path is in effect (self or ancestor) so genuinely-occluded but
|
|
285
|
+
// unclipped text is not skipped.
|
|
286
|
+
function isClippedAway(el, rect) {
|
|
287
|
+
if (typeof document.elementFromPoint !== "function") return false;
|
|
288
|
+
if (!hasClipPath(el)) return false;
|
|
289
|
+
return !paintsAnyProbePoint(el, rect, true);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function isIntentionallyOccluded(el, rect) {
|
|
293
|
+
if (typeof document.elementFromPoint !== "function") return false;
|
|
294
|
+
if (!el.closest || !el.closest("[data-layout-allow-occlusion]")) return false;
|
|
295
|
+
return !paintsAnyProbePoint(el, rect, true);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
var out = [];
|
|
299
|
+
var restores = [];
|
|
300
|
+
// Registered BEFORE the walk starts (not after it finishes) and pushed to
|
|
301
|
+
// incrementally as each element is hidden: if getComputedStyle/
|
|
302
|
+
// getBoundingClientRect/etc. throws partway through the walk (e.g. on a
|
|
303
|
+
// detached or otherwise pathological element), everything hidden before
|
|
304
|
+
// the throw is still reachable for restore instead of leaking hidden
|
|
305
|
+
// indefinitely.
|
|
306
|
+
window.__contrastAuditRestores = restores;
|
|
307
|
+
var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);
|
|
308
|
+
var node;
|
|
309
|
+
while ((node = walker.nextNode())) {
|
|
310
|
+
var el = node;
|
|
311
|
+
|
|
312
|
+
// Must have a direct text node child
|
|
313
|
+
var hasText = false;
|
|
314
|
+
for (var i = 0; i < el.childNodes.length; i++) {
|
|
315
|
+
if (
|
|
316
|
+
el.childNodes[i].nodeType === 3 &&
|
|
317
|
+
(el.childNodes[i].textContent || "").trim().length > 0
|
|
318
|
+
) {
|
|
319
|
+
hasText = true;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (!hasText) continue;
|
|
324
|
+
|
|
325
|
+
// Same decorative opt-out the layout audit honors: text marked (or inside)
|
|
326
|
+
// data-layout-ignore is set dressing, not copy a viewer must read —
|
|
327
|
+
// deliberately dim rail labels, ghost typography, texture text.
|
|
328
|
+
if (el.closest && el.closest("[data-layout-ignore]")) continue;
|
|
329
|
+
|
|
330
|
+
// Text that has (nearly) left the canvas — a cursor exiting the frame, an
|
|
331
|
+
// element parked off-screen — is not readable content, and sampling its
|
|
332
|
+
// clamped edge reads whatever pixels happen to sit at the border (the
|
|
333
|
+
// classic false "white-on-white"). Require a minimally-visible on-canvas
|
|
334
|
+
// intersection before judging contrast; the layout audit separately owns
|
|
335
|
+
// off-canvas detection as its own finding class.
|
|
336
|
+
var vis = el.getBoundingClientRect();
|
|
337
|
+
var onX = Math.min(vis.right, window.innerWidth) - Math.max(vis.left, 0);
|
|
338
|
+
var onY = Math.min(vis.bottom, window.innerHeight) - Math.max(vis.top, 0);
|
|
339
|
+
if (onX < 8 || onY < 8) continue;
|
|
340
|
+
|
|
341
|
+
var cs = getComputedStyle(el);
|
|
342
|
+
if (cs.visibility === "hidden" || cs.display === "none") continue;
|
|
343
|
+
if (parseFloat(cs.opacity) <= 0.01) continue;
|
|
344
|
+
// Also skip when an ANCESTOR is effectively invisible (opacity≈0 / hidden / display:none).
|
|
345
|
+
// Karaoke captions keep every word at opacity 1 but toggle the GROUP's opacity per beat,
|
|
346
|
+
// so an inactive word's OWN opacity is 1 — only an ancestor reveals it's hidden. Without
|
|
347
|
+
// this, the hidden caption words flood the audit with false ~1:1 contrast warnings.
|
|
348
|
+
var anc = el.parentElement,
|
|
349
|
+
ancHidden = false;
|
|
350
|
+
while (anc && anc !== document.body) {
|
|
351
|
+
var acs = getComputedStyle(anc);
|
|
352
|
+
if (
|
|
353
|
+
acs.visibility === "hidden" ||
|
|
354
|
+
acs.display === "none" ||
|
|
355
|
+
parseFloat(acs.opacity) <= 0.01
|
|
356
|
+
) {
|
|
357
|
+
ancHidden = true;
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
anc = anc.parentElement;
|
|
361
|
+
}
|
|
362
|
+
if (ancHidden) continue;
|
|
363
|
+
var rect = el.getBoundingClientRect();
|
|
364
|
+
if (rect.width < 8 || rect.height < 8) continue;
|
|
365
|
+
if (rect.right <= 0 || rect.bottom <= 0) continue;
|
|
366
|
+
if (isClippedAway(el, rect)) continue;
|
|
367
|
+
// The layout audit's explicit occlusion opt-out means this text is allowed
|
|
368
|
+
// to sit behind another scene. Skip contrast only while every probe point
|
|
369
|
+
// is actually covered; the same copy is audited normally when visible.
|
|
370
|
+
if (isIntentionallyOccluded(el, rect)) continue;
|
|
371
|
+
|
|
372
|
+
// For SVG text, `fill` is the paint that's actually rendered; `color` is
|
|
373
|
+
// frequently just the inherited/initial value and unrelated to what's on
|
|
374
|
+
// screen. Only trust `fill` when it resolves to a solid color — "none",
|
|
375
|
+
// "context-fill", and gradient/pattern refs (url(#...)) fall back to
|
|
376
|
+
// `color` rather than crashing parseColor or reporting a fabricated
|
|
377
|
+
// black.
|
|
378
|
+
var isSvgText = isSvgTextElement(el);
|
|
379
|
+
var fg = isSvgText ? parseColor(cs.fill) || parseColor(cs.color) : parseColor(cs.color);
|
|
380
|
+
if (!fg) continue;
|
|
381
|
+
if (fg[3] <= 0.01) continue;
|
|
382
|
+
var strokeWidth = parseFloat(cs.webkitTextStrokeWidth || "0");
|
|
383
|
+
var stroke = strokeWidth > 0 ? parseColor(cs.webkitTextStrokeColor || "") : null;
|
|
384
|
+
if (stroke && stroke[3] <= 0.01) stroke = null;
|
|
385
|
+
|
|
386
|
+
var fontSize = parseFloat(cs.fontSize);
|
|
387
|
+
var fontWeight = Number(cs.fontWeight) || 400;
|
|
388
|
+
var large = fontSize >= 24 || (fontSize >= 19 && fontWeight >= 700);
|
|
389
|
+
|
|
390
|
+
// Glyphs sit on this element's own fill. The bounding box also contains
|
|
391
|
+
// border-radius corners and neighbouring pixels, and those read as the
|
|
392
|
+
// panel behind a circular avatar. An opaque background with no image is
|
|
393
|
+
// the fill; pixel sampling stays for transparent text.
|
|
394
|
+
var ownBg = null;
|
|
395
|
+
if ((cs.backgroundImage || "none") === "none") {
|
|
396
|
+
var parsedOwnBg = parseColor(cs.backgroundColor || "");
|
|
397
|
+
if (parsedOwnBg && parsedOwnBg[3] >= 0.99) ownBg = parsedOwnBg;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Hide this element's OWN text paint so the caller's next screenshot
|
|
401
|
+
// reveals the true pixels behind the glyphs. Layout-neutral: color/fill
|
|
402
|
+
// never affect box geometry. `!important` beats any non-!important rule
|
|
403
|
+
// that might otherwise win on specificity; we restore the exact prior
|
|
404
|
+
// inline value (or remove the property entirely) afterward.
|
|
405
|
+
//
|
|
406
|
+
// A `transition` on color/fill would otherwise animate this hide instead
|
|
407
|
+
// of applying it instantly — the caller's screenshot lands in the same
|
|
408
|
+
// task-queue gap as the transition's own frames, so it can catch a
|
|
409
|
+
// partially-transparent (still partly the original color) glyph instead
|
|
410
|
+
// of a fully hidden one, contaminating the background sample. Force
|
|
411
|
+
// `transition: none` alongside color/fill so the hide is atomic, and
|
|
412
|
+
// restore it alongside them.
|
|
413
|
+
var origTransition = el.style.getPropertyValue("transition");
|
|
414
|
+
var origTransitionPriority = el.style.getPropertyPriority("transition");
|
|
415
|
+
el.style.setProperty("transition", "none", "important");
|
|
416
|
+
var origColor = el.style.getPropertyValue("color");
|
|
417
|
+
var origColorPriority = el.style.getPropertyPriority("color");
|
|
418
|
+
el.style.setProperty("color", "transparent", "important");
|
|
419
|
+
var origFill = null,
|
|
420
|
+
origFillPriority = null;
|
|
421
|
+
if (isSvgText) {
|
|
422
|
+
origFill = el.style.getPropertyValue("fill");
|
|
423
|
+
origFillPriority = el.style.getPropertyPriority("fill");
|
|
424
|
+
el.style.setProperty("fill", "transparent", "important");
|
|
425
|
+
}
|
|
426
|
+
var origStrokeColor = null,
|
|
427
|
+
origStrokeColorPriority = null;
|
|
428
|
+
if (stroke) {
|
|
429
|
+
origStrokeColor = el.style.getPropertyValue("-webkit-text-stroke-color");
|
|
430
|
+
origStrokeColorPriority = el.style.getPropertyPriority("-webkit-text-stroke-color");
|
|
431
|
+
el.style.setProperty("-webkit-text-stroke-color", "transparent", "important");
|
|
432
|
+
}
|
|
433
|
+
restores.push({
|
|
434
|
+
el: el,
|
|
435
|
+
origTransition: origTransition,
|
|
436
|
+
origTransitionPriority: origTransitionPriority,
|
|
437
|
+
origColor: origColor,
|
|
438
|
+
origColorPriority: origColorPriority,
|
|
439
|
+
origFill: origFill,
|
|
440
|
+
origFillPriority: origFillPriority,
|
|
441
|
+
origStrokeColor: origStrokeColor,
|
|
442
|
+
origStrokeColorPriority: origStrokeColorPriority,
|
|
443
|
+
hasStroke: !!stroke,
|
|
444
|
+
isSvgText: isSvgText,
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
out.push({
|
|
448
|
+
selector: selectorOf(el),
|
|
449
|
+
text: (el.textContent || "").trim().slice(0, 50),
|
|
450
|
+
fg: fg,
|
|
451
|
+
stroke: stroke,
|
|
452
|
+
fontSize: fontSize,
|
|
453
|
+
fontWeight: fontWeight,
|
|
454
|
+
large: large,
|
|
455
|
+
ownBg: ownBg,
|
|
456
|
+
solidBg: ownBg ? null : solidBackdrop(el, rect, cs),
|
|
457
|
+
bbox: { x: rect.x, y: rect.y, w: rect.width, h: rect.height },
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return out;
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
function __contrastAuditRestoreAll() {
|
|
465
|
+
var restores = window.__contrastAuditRestores;
|
|
466
|
+
if (!restores) return;
|
|
467
|
+
for (var i = 0; i < restores.length; i++) {
|
|
468
|
+
var r = restores[i];
|
|
469
|
+
if (r.origColor) r.el.style.setProperty("color", r.origColor, r.origColorPriority);
|
|
470
|
+
else r.el.style.removeProperty("color");
|
|
471
|
+
if (r.isSvgText) {
|
|
472
|
+
if (r.origFill) r.el.style.setProperty("fill", r.origFill, r.origFillPriority);
|
|
473
|
+
else r.el.style.removeProperty("fill");
|
|
474
|
+
}
|
|
475
|
+
if (r.hasStroke) {
|
|
476
|
+
if (r.origStrokeColor)
|
|
477
|
+
r.el.style.setProperty(
|
|
478
|
+
"-webkit-text-stroke-color",
|
|
479
|
+
r.origStrokeColor,
|
|
480
|
+
r.origStrokeColorPriority,
|
|
481
|
+
);
|
|
482
|
+
else r.el.style.removeProperty("-webkit-text-stroke-color");
|
|
483
|
+
}
|
|
484
|
+
if (r.origTransition)
|
|
485
|
+
r.el.style.setProperty("transition", r.origTransition, r.origTransitionPriority);
|
|
486
|
+
else r.el.style.removeProperty("transition");
|
|
487
|
+
}
|
|
488
|
+
window.__contrastAuditRestores = null;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Safety net for the caller: if the screenshot or finish() call throws
|
|
492
|
+
// between prepare() and finish(), call this to restore any still-hidden
|
|
493
|
+
// paint so the next sample in the loop isn't auditing a page with stale
|
|
494
|
+
// invisible text. No-op if finish() already ran normally.
|
|
495
|
+
window.__contrastAuditRestoreIfPending = function () {
|
|
496
|
+
__contrastAuditRestoreAll();
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
window.__contrastAuditFinish = async function (imgBase64, time, candidates, region) {
|
|
500
|
+
function relLum(r, g, b) {
|
|
501
|
+
function ch(v) {
|
|
502
|
+
var s = v / 255;
|
|
503
|
+
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
504
|
+
}
|
|
505
|
+
return 0.2126 * ch(r) + 0.7152 * ch(g) + 0.0722 * ch(b);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function wcagRatio(r1, g1, b1, r2, g2, b2) {
|
|
509
|
+
var l1 = relLum(r1, g1, b1),
|
|
510
|
+
l2 = relLum(r2, g2, b2);
|
|
511
|
+
var hi = l1 > l2 ? l1 : l2,
|
|
512
|
+
lo = l1 > l2 ? l2 : l1;
|
|
513
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function median(arr) {
|
|
517
|
+
var s = arr.slice().sort(function (a, b) {
|
|
518
|
+
return a - b;
|
|
519
|
+
});
|
|
520
|
+
return s[Math.floor(s.length / 2)];
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Restore original paint first — we already have the screenshot, and we
|
|
524
|
+
// never want a decode failure below to leave the page's text invisible.
|
|
525
|
+
__contrastAuditRestoreAll();
|
|
526
|
+
|
|
527
|
+
// No image when every candidate's background is known from styles.
|
|
528
|
+
var canvas = { width: region ? region.frameWidth : 0, height: region ? region.frameHeight : 0 };
|
|
529
|
+
var px = null;
|
|
530
|
+
if (imgBase64) {
|
|
531
|
+
var img = new Image();
|
|
532
|
+
await new Promise(function (resolve) {
|
|
533
|
+
img.onload = resolve;
|
|
534
|
+
img.onerror = function () {
|
|
535
|
+
resolve();
|
|
536
|
+
};
|
|
537
|
+
img.src = "data:image/png;base64," + imgBase64;
|
|
538
|
+
});
|
|
539
|
+
if (!img.naturalWidth) return [];
|
|
540
|
+
canvas = document.createElement("canvas");
|
|
541
|
+
canvas.width = img.naturalWidth || 1920;
|
|
542
|
+
canvas.height = img.naturalHeight || 1080;
|
|
543
|
+
var ctx = canvas.getContext("2d");
|
|
544
|
+
if (!ctx) return [];
|
|
545
|
+
ctx.drawImage(img, 0, 0);
|
|
546
|
+
px = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
|
|
547
|
+
}
|
|
548
|
+
// A clipped shot holds `region.clip` of the frame: clamp to the frame, read at the offset.
|
|
549
|
+
var w = region ? region.frameWidth : canvas.width;
|
|
550
|
+
var h = region ? region.frameHeight : canvas.height;
|
|
551
|
+
var ox = region ? region.clip.x : 0;
|
|
552
|
+
var oy = region ? region.clip.y : 0;
|
|
553
|
+
|
|
554
|
+
var out = [];
|
|
555
|
+
for (var ci = 0; ci < candidates.length; ci++) {
|
|
556
|
+
var c = candidates[ci];
|
|
557
|
+
var bbox = c.bbox;
|
|
558
|
+
|
|
559
|
+
// Sample the element's OWN box (glyphs are hidden in this screenshot),
|
|
560
|
+
// inset 1px on each side to dodge anti-aliased edge pixels, clamped to
|
|
561
|
+
// the canvas. Mirrors contrast-sample.ts's computeSampleRect.
|
|
562
|
+
var x0 = Math.max(0, Math.round(bbox.x) + 1);
|
|
563
|
+
var x1 = Math.min(w - 1, Math.round(bbox.x + bbox.w) - 1);
|
|
564
|
+
var y0 = Math.max(0, Math.round(bbox.y) + 1);
|
|
565
|
+
var y1 = Math.min(h - 1, Math.round(bbox.y + bbox.h) - 1);
|
|
566
|
+
if (x1 <= x0 || y1 <= y0) continue;
|
|
567
|
+
|
|
568
|
+
// Bounded grid, not a full scan — dense enough to catch a
|
|
569
|
+
// partially-overlapping decoration without turning a wide caption bar
|
|
570
|
+
// into thousands of samples. Mirrors contrast-sample.ts's
|
|
571
|
+
// sampleGridPoints.
|
|
572
|
+
var stepX = Math.max(1, Math.floor((x1 - x0) / 12));
|
|
573
|
+
var stepY = Math.max(1, Math.floor((y1 - y0) / 6));
|
|
574
|
+
var known = c.ownBg && c.ownBg.length >= 4 && c.ownBg[3] >= 0.99 ? c.ownBg : c.solidBg;
|
|
575
|
+
var rr = [],
|
|
576
|
+
gg = [],
|
|
577
|
+
bb = [],
|
|
578
|
+
aa = [];
|
|
579
|
+
for (var y = y0; !known && y <= y1; y += stepY) {
|
|
580
|
+
for (var x = x0; x <= x1; x += stepX) {
|
|
581
|
+
var idx = ((y - oy) * canvas.width + (x - ox)) * 4;
|
|
582
|
+
rr.push(px[idx]);
|
|
583
|
+
gg.push(px[idx + 1]);
|
|
584
|
+
bb.push(px[idx + 2]);
|
|
585
|
+
aa.push(px[idx + 3]);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (!known && rr.length === 0) continue;
|
|
589
|
+
|
|
590
|
+
var bgR, bgG, bgB;
|
|
591
|
+
if (known) {
|
|
592
|
+
bgR = known[0];
|
|
593
|
+
bgG = known[1];
|
|
594
|
+
bgB = known[2];
|
|
595
|
+
} else {
|
|
596
|
+
// A transparent sampled backdrop is supplied by the downstream editor,
|
|
597
|
+
// not this composition. WCAG contrast cannot be inferred until that live
|
|
598
|
+
// video/image is known, so do not invent an opaque browser default and
|
|
599
|
+
// hard-fail an otherwise valid alpha overlay.
|
|
600
|
+
if (median(aa) < 255) continue;
|
|
601
|
+
bgR = median(rr);
|
|
602
|
+
bgG = median(gg);
|
|
603
|
+
bgB = median(bb);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Composite foreground alpha over the measured background
|
|
607
|
+
var fg = c.fg;
|
|
608
|
+
var compR = Math.round(fg[0] * fg[3] + bgR * (1 - fg[3]));
|
|
609
|
+
var compG = Math.round(fg[1] * fg[3] + bgG * (1 - fg[3]));
|
|
610
|
+
var compB = Math.round(fg[2] * fg[3] + bgB * (1 - fg[3]));
|
|
611
|
+
|
|
612
|
+
var ratio = +wcagRatio(compR, compG, compB, bgR, bgG, bgB).toFixed(2);
|
|
613
|
+
|
|
614
|
+
// A solid text stroke is part of the visible glyph paint. Use whichever
|
|
615
|
+
// of fill or stroke provides the stronger edge contrast, rather than
|
|
616
|
+
// failing readable outlined captions based on fill alone.
|
|
617
|
+
if (c.stroke) {
|
|
618
|
+
var stroke = c.stroke;
|
|
619
|
+
var strokeR = Math.round(stroke[0] * stroke[3] + bgR * (1 - stroke[3]));
|
|
620
|
+
var strokeG = Math.round(stroke[1] * stroke[3] + bgG * (1 - stroke[3]));
|
|
621
|
+
var strokeB = Math.round(stroke[2] * stroke[3] + bgB * (1 - stroke[3]));
|
|
622
|
+
var strokeRatio = +wcagRatio(strokeR, strokeG, strokeB, bgR, bgG, bgB).toFixed(2);
|
|
623
|
+
if (strokeRatio > ratio) {
|
|
624
|
+
compR = strokeR;
|
|
625
|
+
compG = strokeG;
|
|
626
|
+
compB = strokeB;
|
|
627
|
+
ratio = strokeRatio;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
out.push({
|
|
632
|
+
time: time,
|
|
633
|
+
selector: c.selector,
|
|
634
|
+
text: c.text,
|
|
635
|
+
ratio: ratio,
|
|
636
|
+
wcagAA: c.large ? ratio >= 3 : ratio >= 4.5,
|
|
637
|
+
large: c.large,
|
|
638
|
+
fg: "rgb(" + compR + "," + compG + "," + compB + ")",
|
|
639
|
+
bg: "rgb(" + bgR + "," + bgG + "," + bgB + ")",
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
return out;
|
|
643
|
+
};
|