quiver-cli 1.3.1 → 2.0.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/README.md +197 -239
- package/dist/cli.js +3163 -2040
- package/package.json +10 -11
- package/template/.agents/AGENTS.md +0 -26
- package/template/.agents/commands/cp.md +0 -108
- package/template/.agents/commands/next-setup.md +0 -1064
- package/template/.agents/commands/review.md +0 -68
- package/template/.agents/commands/terraform-readme.md +0 -38
- package/template/.agents/config.json +0 -80
- package/template/.agents/plugins/opencode/rtk.ts +0 -34
- package/template/.agents/skills/agent-browser/SKILL.md +0 -52
- package/template/.agents/skills/apps/skybridge/SKILL.md +0 -52
- package/template/.agents/skills/code/cleanup/SKILL.md +0 -26
- package/template/.agents/skills/code/improve/SKILL.md +0 -122
- package/template/.agents/skills/code/improve/references/audit-playbook.md +0 -130
- package/template/.agents/skills/code/improve/references/closing-the-loop.md +0 -96
- package/template/.agents/skills/code/improve/references/plan-template.md +0 -197
- package/template/.agents/skills/code/vercel-react-best-practices/AGENTS.md +0 -3810
- package/template/.agents/skills/code/vercel-react-best-practices/README.md +0 -123
- package/template/.agents/skills/code/vercel-react-best-practices/SKILL.md +0 -149
- package/template/.agents/skills/code/vercel-react-best-practices/metadata.json +0 -15
- package/template/.agents/skills/code/vercel-react-best-practices/rules/_sections.md +0 -46
- package/template/.agents/skills/code/vercel-react-best-practices/rules/_template.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-effect-event-deps.md +0 -56
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-api-routes.md +0 -38
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +0 -37
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-defer-await.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-dependencies.md +0 -51
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-parallel.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-analyzable-paths.md +0 -63
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -60
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-preload.md +0 -50
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-early-exit.md +0 -50
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-index-maps.md +0 -37
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-request-idle-callback.md +0 -105
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-activity.md +0 -26
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo.md +0 -44
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +0 -64
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-deferred-value.md +0 -59
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-react.md +0 -76
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -149
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-no-shared-module-state.md +0 -50
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +0 -34
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-serialization.md +0 -38
- package/template/.agents/skills/data/prisma-cli/SKILL.md +0 -265
- package/template/.agents/skills/data/prisma-cli/references/agent-safety.md +0 -27
- package/template/.agents/skills/data/prisma-cli/references/complete.md +0 -22
- package/template/.agents/skills/data/prisma-cli/references/db-execute.md +0 -78
- package/template/.agents/skills/data/prisma-cli/references/db-pull.md +0 -185
- package/template/.agents/skills/data/prisma-cli/references/db-push.md +0 -150
- package/template/.agents/skills/data/prisma-cli/references/db-seed.md +0 -188
- package/template/.agents/skills/data/prisma-cli/references/debug.md +0 -46
- package/template/.agents/skills/data/prisma-cli/references/dev.md +0 -157
- package/template/.agents/skills/data/prisma-cli/references/format.md +0 -48
- package/template/.agents/skills/data/prisma-cli/references/generate.md +0 -173
- package/template/.agents/skills/data/prisma-cli/references/init.md +0 -139
- package/template/.agents/skills/data/prisma-cli/references/mcp.md +0 -39
- package/template/.agents/skills/data/prisma-cli/references/migrate-deploy.md +0 -127
- package/template/.agents/skills/data/prisma-cli/references/migrate-dev.md +0 -145
- package/template/.agents/skills/data/prisma-cli/references/migrate-diff.md +0 -89
- package/template/.agents/skills/data/prisma-cli/references/migrate-reset.md +0 -80
- package/template/.agents/skills/data/prisma-cli/references/migrate-resolve.md +0 -57
- package/template/.agents/skills/data/prisma-cli/references/migrate-status.md +0 -65
- package/template/.agents/skills/data/prisma-cli/references/studio.md +0 -137
- package/template/.agents/skills/data/prisma-cli/references/validate.md +0 -53
- package/template/.agents/skills/data/prisma-client-api/SKILL.md +0 -216
- package/template/.agents/skills/data/prisma-client-api/references/client-methods.md +0 -223
- package/template/.agents/skills/data/prisma-client-api/references/constructor.md +0 -221
- package/template/.agents/skills/data/prisma-client-api/references/filters.md +0 -256
- package/template/.agents/skills/data/prisma-client-api/references/model-queries.md +0 -281
- package/template/.agents/skills/data/prisma-client-api/references/query-options.md +0 -276
- package/template/.agents/skills/data/prisma-client-api/references/raw-queries.md +0 -198
- package/template/.agents/skills/data/prisma-client-api/references/relations.md +0 -308
- package/template/.agents/skills/data/prisma-client-api/references/transactions.md +0 -184
- package/template/.agents/skills/design/impeccable/SKILL.md +0 -84
- package/template/.agents/skills/design/impeccable/reference/adapt.md +0 -312
- package/template/.agents/skills/design/impeccable/reference/adapt.native.md +0 -58
- package/template/.agents/skills/design/impeccable/reference/android.md +0 -46
- package/template/.agents/skills/design/impeccable/reference/animate.md +0 -89
- package/template/.agents/skills/design/impeccable/reference/audit.md +0 -136
- package/template/.agents/skills/design/impeccable/reference/audit.native.md +0 -139
- package/template/.agents/skills/design/impeccable/reference/bolder.md +0 -33
- package/template/.agents/skills/design/impeccable/reference/clarify.md +0 -94
- package/template/.agents/skills/design/impeccable/reference/colorize.md +0 -86
- package/template/.agents/skills/design/impeccable/reference/craft-floor.md +0 -44
- package/template/.agents/skills/design/impeccable/reference/craft.md +0 -5
- package/template/.agents/skills/design/impeccable/reference/critique.md +0 -806
- package/template/.agents/skills/design/impeccable/reference/degraded/asset-producer.md +0 -37
- package/template/.agents/skills/design/impeccable/reference/degraded/documenter.md +0 -24
- package/template/.agents/skills/design/impeccable/reference/degraded/finish-reviewer.md +0 -38
- package/template/.agents/skills/design/impeccable/reference/degraded/manual-edit-applier.md +0 -92
- package/template/.agents/skills/design/impeccable/reference/delight.md +0 -70
- package/template/.agents/skills/design/impeccable/reference/distill.md +0 -111
- package/template/.agents/skills/design/impeccable/reference/doctor.md +0 -54
- package/template/.agents/skills/design/impeccable/reference/document.md +0 -416
- package/template/.agents/skills/design/impeccable/reference/extract.md +0 -69
- package/template/.agents/skills/design/impeccable/reference/harden.md +0 -336
- package/template/.agents/skills/design/impeccable/reference/hooks.md +0 -111
- package/template/.agents/skills/design/impeccable/reference/init.md +0 -131
- package/template/.agents/skills/design/impeccable/reference/ios.md +0 -51
- package/template/.agents/skills/design/impeccable/reference/layout.md +0 -84
- package/template/.agents/skills/design/impeccable/reference/live-setup.md +0 -102
- package/template/.agents/skills/design/impeccable/reference/live.md +0 -323
- package/template/.agents/skills/design/impeccable/reference/new-work.md +0 -145
- package/template/.agents/skills/design/impeccable/reference/onboard.md +0 -234
- package/template/.agents/skills/design/impeccable/reference/operate.md +0 -61
- package/template/.agents/skills/design/impeccable/reference/optimize.md +0 -258
- package/template/.agents/skills/design/impeccable/reference/overdrive.md +0 -127
- package/template/.agents/skills/design/impeccable/reference/polish.md +0 -105
- package/template/.agents/skills/design/impeccable/reference/quieter.md +0 -99
- package/template/.agents/skills/design/impeccable/reference/routing.md +0 -18
- package/template/.agents/skills/design/impeccable/reference/shape.md +0 -59
- package/template/.agents/skills/design/impeccable/reference/typeset.md +0 -80
- package/template/.agents/skills/design/impeccable/reference/visualize.md +0 -46
- package/template/.agents/skills/design/impeccable/scripts/build-phase.mjs +0 -1022
- package/template/.agents/skills/design/impeccable/scripts/command-metadata.json +0 -94
- package/template/.agents/skills/design/impeccable/scripts/comp-diff.mjs +0 -391
- package/template/.agents/skills/design/impeccable/scripts/comp-spec.mjs +0 -513
- package/template/.agents/skills/design/impeccable/scripts/concept-seed.mjs +0 -814
- package/template/.agents/skills/design/impeccable/scripts/context-signals.mjs +0 -325
- package/template/.agents/skills/design/impeccable/scripts/context.mjs +0 -1565
- package/template/.agents/skills/design/impeccable/scripts/critique-storage.mjs +0 -473
- package/template/.agents/skills/design/impeccable/scripts/data/font-index-failures.json +0 -121
- package/template/.agents/skills/design/impeccable/scripts/data/font-index.json +0 -1
- package/template/.agents/skills/design/impeccable/scripts/detect-csp.mjs +0 -198
- package/template/.agents/skills/design/impeccable/scripts/detect.mjs +0 -30
- package/template/.agents/skills/design/impeccable/scripts/detector/browser/injected/index.mjs +0 -2204
- package/template/.agents/skills/design/impeccable/scripts/detector/cli/main.mjs +0 -432
- package/template/.agents/skills/design/impeccable/scripts/detector/design-system.mjs +0 -1311
- package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns-browser.js +0 -9043
- package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns.mjs +0 -51
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/browser/detect-url.mjs +0 -434
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/regex/detect-text.mjs +0 -1319
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +0 -1241
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/detect-html.mjs +0 -288
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +0 -189
- package/template/.agents/skills/design/impeccable/scripts/detector/findings.mjs +0 -18
- package/template/.agents/skills/design/impeccable/scripts/detector/node/file-system.mjs +0 -213
- package/template/.agents/skills/design/impeccable/scripts/detector/profile/profiler.mjs +0 -166
- package/template/.agents/skills/design/impeccable/scripts/detector/registry/antipatterns.mjs +0 -635
- package/template/.agents/skills/design/impeccable/scripts/detector/rules/checks.mjs +0 -5681
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/color.mjs +0 -596
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/constants.mjs +0 -127
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/fonts.mjs +0 -30
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/inline-ignores.mjs +0 -148
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/page.mjs +0 -7
- package/template/.agents/skills/design/impeccable/scripts/doctor.mjs +0 -329
- package/template/.agents/skills/design/impeccable/scripts/embed-prompt.mjs +0 -166
- package/template/.agents/skills/design/impeccable/scripts/font-match.mjs +0 -457
- package/template/.agents/skills/design/impeccable/scripts/generate-image.mjs +0 -447
- package/template/.agents/skills/design/impeccable/scripts/hook-admin.mjs +0 -819
- package/template/.agents/skills/design/impeccable/scripts/hook-before-edit.mjs +0 -538
- package/template/.agents/skills/design/impeccable/scripts/hook-lib.mjs +0 -2490
- package/template/.agents/skills/design/impeccable/scripts/hook.mjs +0 -79
- package/template/.agents/skills/design/impeccable/scripts/lib/artifact-schema.mjs +0 -93
- package/template/.agents/skills/design/impeccable/scripts/lib/composition-catalog.mjs +0 -200
- package/template/.agents/skills/design/impeccable/scripts/lib/concept-catalog.mjs +0 -396
- package/template/.agents/skills/design/impeccable/scripts/lib/design-parser.mjs +0 -880
- package/template/.agents/skills/design/impeccable/scripts/lib/font-fingerprint.mjs +0 -564
- package/template/.agents/skills/design/impeccable/scripts/lib/font-index.mjs +0 -130
- package/template/.agents/skills/design/impeccable/scripts/lib/hero-checks.mjs +0 -246
- package/template/.agents/skills/design/impeccable/scripts/lib/image-metrics.mjs +0 -306
- package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-config.mjs +0 -640
- package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-paths.mjs +0 -137
- package/template/.agents/skills/design/impeccable/scripts/lib/is-generated.mjs +0 -72
- package/template/.agents/skills/design/impeccable/scripts/lib/live-path-globs.mjs +0 -37
- package/template/.agents/skills/design/impeccable/scripts/lib/open-system-browser.mjs +0 -26
- package/template/.agents/skills/design/impeccable/scripts/lib/png.mjs +0 -281
- package/template/.agents/skills/design/impeccable/scripts/lib/provider.mjs +0 -5
- package/template/.agents/skills/design/impeccable/scripts/lib/raster.mjs +0 -194
- package/template/.agents/skills/design/impeccable/scripts/lib/roll-selection.mjs +0 -369
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness-deep.mjs +0 -485
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness-notice.mjs +0 -169
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness.mjs +0 -533
- package/template/.agents/skills/design/impeccable/scripts/lib/surface-briefs.mjs +0 -149
- package/template/.agents/skills/design/impeccable/scripts/lib/target-args.mjs +0 -42
- package/template/.agents/skills/design/impeccable/scripts/lib/target-slug.mjs +0 -33
- package/template/.agents/skills/design/impeccable/scripts/lib/template-extensions.mjs +0 -146
- package/template/.agents/skills/design/impeccable/scripts/live/accept-css.mjs +0 -617
- package/template/.agents/skills/design/impeccable/scripts/live/accept-verify.mjs +0 -60
- package/template/.agents/skills/design/impeccable/scripts/live/browser-script-parts.mjs +0 -84
- package/template/.agents/skills/design/impeccable/scripts/live/completion.mjs +0 -28
- package/template/.agents/skills/design/impeccable/scripts/live/event-validation.mjs +0 -199
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/astro.mjs +0 -47
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/detect-utils.mjs +0 -73
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/index.mjs +0 -143
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/journal.mjs +0 -197
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nextjs.mjs +0 -49
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nuxt.mjs +0 -161
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/script-src.mjs +0 -17
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/static-html.mjs +0 -26
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/sveltekit.mjs +0 -71
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tag-strategy.mjs +0 -247
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tanstack-start.mjs +0 -70
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/vite-generic.mjs +0 -42
- package/template/.agents/skills/design/impeccable/scripts/live/generation-preflight.mjs +0 -149
- package/template/.agents/skills/design/impeccable/scripts/live/insert-ui.mjs +0 -458
- package/template/.agents/skills/design/impeccable/scripts/live/instructions.mjs +0 -142
- package/template/.agents/skills/design/impeccable/scripts/live/manual-apply.mjs +0 -939
- package/template/.agents/skills/design/impeccable/scripts/live/manual-edit-routes.mjs +0 -357
- package/template/.agents/skills/design/impeccable/scripts/live/manual-edits-buffer.mjs +0 -152
- package/template/.agents/skills/design/impeccable/scripts/live/poll-lanes.mjs +0 -14
- package/template/.agents/skills/design/impeccable/scripts/live/project-ignores.mjs +0 -139
- package/template/.agents/skills/design/impeccable/scripts/live/roots.mjs +0 -508
- package/template/.agents/skills/design/impeccable/scripts/live/session-store.mjs +0 -563
- package/template/.agents/skills/design/impeccable/scripts/live/source-lock.mjs +0 -105
- package/template/.agents/skills/design/impeccable/scripts/live/source-search.mjs +0 -105
- package/template/.agents/skills/design/impeccable/scripts/live/svelte-ast.mjs +0 -969
- package/template/.agents/skills/design/impeccable/scripts/live/svelte-component.mjs +0 -1366
- package/template/.agents/skills/design/impeccable/scripts/live/sveltekit-adapter.mjs +0 -304
- package/template/.agents/skills/design/impeccable/scripts/live/tanstack-adapter.mjs +0 -259
- package/template/.agents/skills/design/impeccable/scripts/live/ui-surfaces.mjs +0 -75
- package/template/.agents/skills/design/impeccable/scripts/live/vocabulary.mjs +0 -171
- package/template/.agents/skills/design/impeccable/scripts/live-accept.mjs +0 -938
- package/template/.agents/skills/design/impeccable/scripts/live-browser-dom.js +0 -146
- package/template/.agents/skills/design/impeccable/scripts/live-browser-ignores.js +0 -242
- package/template/.agents/skills/design/impeccable/scripts/live-browser-session.js +0 -123
- package/template/.agents/skills/design/impeccable/scripts/live-browser.js +0 -12551
- package/template/.agents/skills/design/impeccable/scripts/live-commit-manual-edits.mjs +0 -1200
- package/template/.agents/skills/design/impeccable/scripts/live-complete.mjs +0 -107
- package/template/.agents/skills/design/impeccable/scripts/live-copy-edit-agent.mjs +0 -800
- package/template/.agents/skills/design/impeccable/scripts/live-discard-manual-edits.mjs +0 -51
- package/template/.agents/skills/design/impeccable/scripts/live-inject.mjs +0 -463
- package/template/.agents/skills/design/impeccable/scripts/live-insert.mjs +0 -292
- package/template/.agents/skills/design/impeccable/scripts/live-manual-edit-evidence.mjs +0 -368
- package/template/.agents/skills/design/impeccable/scripts/live-poll.mjs +0 -430
- package/template/.agents/skills/design/impeccable/scripts/live-resume.mjs +0 -123
- package/template/.agents/skills/design/impeccable/scripts/live-server.mjs +0 -1698
- package/template/.agents/skills/design/impeccable/scripts/live-status.mjs +0 -71
- package/template/.agents/skills/design/impeccable/scripts/live-target.mjs +0 -30
- package/template/.agents/skills/design/impeccable/scripts/live-wrap.mjs +0 -927
- package/template/.agents/skills/design/impeccable/scripts/live.mjs +0 -334
- package/template/.agents/skills/design/impeccable/scripts/modern-screenshot.umd.js +0 -14
- package/template/.agents/skills/design/impeccable/scripts/palette.mjs +0 -628
- package/template/.agents/skills/design/impeccable/scripts/pin.mjs +0 -224
- package/template/.agents/skills/design/impeccable/scripts/serve-question.mjs +0 -1783
- package/template/.agents/skills/design/impeccable/scripts/surface-brief.mjs +0 -74
- package/template/.agents/skills/design/shadcn/SKILL.md +0 -277
- package/template/.agents/skills/design/shadcn/agents/openai.yml +0 -5
- package/template/.agents/skills/design/shadcn/assets/shadcn-small.png +0 -0
- package/template/.agents/skills/design/shadcn/assets/shadcn.png +0 -0
- package/template/.agents/skills/design/shadcn/cli.md +0 -290
- package/template/.agents/skills/design/shadcn/customization.md +0 -209
- package/template/.agents/skills/design/shadcn/evals/evals.json +0 -77
- package/template/.agents/skills/design/shadcn/mcp.md +0 -105
- package/template/.agents/skills/design/shadcn/registry.md +0 -277
- package/template/.agents/skills/design/shadcn/rules/base-vs-radix.md +0 -306
- package/template/.agents/skills/design/shadcn/rules/chat.md +0 -250
- package/template/.agents/skills/design/shadcn/rules/composition.md +0 -213
- package/template/.agents/skills/design/shadcn/rules/forms.md +0 -192
- package/template/.agents/skills/design/shadcn/rules/icons.md +0 -101
- package/template/.agents/skills/design/shadcn/rules/styling.md +0 -185
- package/template/.agents/skills/find-skills/SKILL.md +0 -141
- package/template/.agents/skills/hono/SKILL.md +0 -593
- package/template/.agents/skills/integrations/langfuse/SKILL.md +0 -150
- package/template/.agents/skills/integrations/langfuse/references/ci-cd.md +0 -41
- package/template/.agents/skills/integrations/langfuse/references/cli.md +0 -60
- package/template/.agents/skills/integrations/langfuse/references/create-dataset.md +0 -35
- package/template/.agents/skills/integrations/langfuse/references/error-analysis.md +0 -87
- package/template/.agents/skills/integrations/langfuse/references/instrumentation.md +0 -121
- package/template/.agents/skills/integrations/langfuse/references/judge-calibration.md +0 -293
- package/template/.agents/skills/integrations/langfuse/references/prompt-engineering.md +0 -35
- package/template/.agents/skills/integrations/langfuse/references/prompt-migration.md +0 -79
- package/template/.agents/skills/integrations/langfuse/references/sdk-upgrade.md +0 -34
- package/template/.agents/skills/integrations/langfuse/references/setting-up-evals.md +0 -65
- package/template/.agents/skills/integrations/langfuse/references/skill-feedback.md +0 -35
- package/template/.agents/skills/integrations/langfuse/references/trace-evaluator-upgrade.md +0 -76
- package/template/.agents/skills/integrations/langfuse/references/user-feedback.md +0 -66
- package/template/.agents/skills/integrations/langfuse/references/v4-project-migration.md +0 -75
- package/template/.agents/skills/integrations/posthog/SKILL.md +0 -102
- package/template/.agents/skills/integrations/posthog/references/error-tracking-alerts.md +0 -63
- package/template/.agents/skills/integrations/posthog/references/error-tracking-assigning-issues.md +0 -77
- package/template/.agents/skills/integrations/posthog/references/error-tracking-fingerprints.md +0 -57
- package/template/.agents/skills/integrations/posthog/references/error-tracking-monitoring.md +0 -140
- package/template/.agents/skills/integrations/posthog/references/error-tracking-nextjs.md +0 -490
- package/template/.agents/skills/integrations/posthog/references/error-tracking-source-maps.md +0 -45
- package/template/.agents/skills/integrations/posthog/references/feature-flags-best-practices.md +0 -139
- package/template/.agents/skills/integrations/posthog/references/feature-flags-react.md +0 -302
- package/template/.agents/skills/integrations/posthog/references/identify-users.md +0 -202
- package/template/.agents/skills/integrations/posthog/references/integration-example.md +0 -706
- package/template/.agents/skills/integrations/posthog/references/integration-nextjs.md +0 -385
- package/template/.agents/skills/integrations/posthog/references/integration-step-1-begin.md +0 -43
- package/template/.agents/skills/integrations/posthog/references/integration-step-2-edit.md +0 -37
- package/template/.agents/skills/integrations/posthog/references/integration-step-3-revise.md +0 -22
- package/template/.agents/skills/integrations/posthog/references/integration-step-4-conclude.md +0 -38
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-anthropic.md +0 -200
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-basics.md +0 -62
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-costs.md +0 -197
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-manual-capture.md +0 -397
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-traces.md +0 -98
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-vercel-ai.md +0 -120
- package/template/.agents/skills/repo/repo-ci/SKILL.md +0 -265
- package/template/.agents/skills/repo/repo-init-next-js/SKILL.md +0 -129
- package/template/.agents/skills/repo/repo-init-next-js/references/file-contents.md +0 -800
- package/template/.agents/skills/repo/repo-init-next-js/scripts/setup.sh +0 -47
- package/template/.agents/skills/repo/repo-init-node/SKILL.md +0 -196
- package/template/.agents/skills/skill-creator/LICENSE.txt +0 -202
- package/template/.agents/skills/skill-creator/SKILL.md +0 -485
- package/template/.agents/skills/skill-creator/agents/analyzer.md +0 -274
- package/template/.agents/skills/skill-creator/agents/comparator.md +0 -202
- package/template/.agents/skills/skill-creator/agents/grader.md +0 -223
- package/template/.agents/skills/skill-creator/assets/eval_review.html +0 -146
- package/template/.agents/skills/skill-creator/eval-viewer/generate_review.py +0 -471
- package/template/.agents/skills/skill-creator/eval-viewer/viewer.html +0 -1325
- package/template/.agents/skills/skill-creator/references/schemas.md +0 -430
- package/template/.agents/skills/skill-creator/scripts/__init__.py +0 -0
- package/template/.agents/skills/skill-creator/scripts/aggregate_benchmark.py +0 -401
- package/template/.agents/skills/skill-creator/scripts/generate_report.py +0 -326
- package/template/.agents/skills/skill-creator/scripts/improve_description.py +0 -247
- package/template/.agents/skills/skill-creator/scripts/package_skill.py +0 -136
- package/template/.agents/skills/skill-creator/scripts/quick_validate.py +0 -103
- package/template/.agents/skills/skill-creator/scripts/run_eval.py +0 -310
- package/template/.agents/skills/skill-creator/scripts/run_loop.py +0 -328
- package/template/.agents/skills/skill-creator/scripts/utils.py +0 -47
- package/template/.agents/skills/supabase/CHANGELOG.md +0 -78
- package/template/.agents/skills/supabase/SKILL.md +0 -149
- package/template/.agents/skills/supabase/assets/feedback-issue-template.md +0 -17
- package/template/.agents/skills/supabase/references/skill-feedback.md +0 -17
- package/template/.agents/skills/supabase-postgres-best-practices/CHANGELOG.md +0 -73
- package/template/.agents/skills/supabase-postgres-best-practices/SKILL.md +0 -64
- package/template/.agents/skills/supabase-postgres-best-practices/references/_contributing.md +0 -170
- package/template/.agents/skills/supabase-postgres-best-practices/references/_sections.md +0 -39
- package/template/.agents/skills/supabase-postgres-best-practices/references/_template.md +0 -34
- package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +0 -49
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +0 -46
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +0 -44
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +0 -41
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +0 -46
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +0 -54
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +0 -53
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +0 -56
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +0 -68
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +0 -54
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +0 -45
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +0 -44
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +0 -40
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +0 -48
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +0 -43
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +0 -45
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +0 -80
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +0 -46
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +0 -59
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +0 -61
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +0 -54
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +0 -63
- package/template/.agents/skills/writing/humanizer/LICENSE +0 -21
- package/template/.agents/skills/writing/humanizer/README.md +0 -209
- package/template/.agents/skills/writing/humanizer/SKILL.md +0 -456
- package/template/.agents/upstreams.json +0 -115
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* font-index: the fingerprint index of the Google Fonts catalog that
|
|
3
|
-
* font-match.mjs --rank uses as its candidate generator, and the pack/unpack
|
|
4
|
-
* helpers the release-time build (repo scripts/build-font-index.mjs) shares with it.
|
|
5
|
-
*
|
|
6
|
-
* File: skill/scripts/data/font-index.json
|
|
7
|
-
* {
|
|
8
|
-
* schema: 1,
|
|
9
|
-
* text: "<index text every face was rendered with>",
|
|
10
|
-
* sizes: [48, 14], // cap heights (px) the catalog was rendered at
|
|
11
|
-
* features: [...], // feature names, in vector order (the fitted-nonzero subset of FEATURES)
|
|
12
|
-
* categories: ["sans", ...], // category index -> name
|
|
13
|
-
* entries: [[family, weight, categoryIdx, variable(0|1), vec48, vec14], ...]
|
|
14
|
-
* }
|
|
15
|
-
* A vector is a string of 3-char base-36 numbers, one per feature, each the
|
|
16
|
-
* feature value x 1000 (three decimals, clipped at 46.655); "___" is null.
|
|
17
|
-
* That packing keeps ~3,000 faces x 2 sizes x 33 features under 750 KB on
|
|
18
|
-
* disk, which is what makes it shippable inside the skill without gzip.
|
|
19
|
-
*
|
|
20
|
-
* Two sizes because the fingerprint's features are stable within a factor of
|
|
21
|
-
* ~2 in size but not from 48px down to 14px: a crop is routed to the index
|
|
22
|
-
* rendered nearer its own cap height (ROUTE_CAP_PX is the boundary).
|
|
23
|
-
*/
|
|
24
|
-
import fs from 'node:fs';
|
|
25
|
-
import path from 'node:path';
|
|
26
|
-
import { fileURLToPath } from 'node:url';
|
|
27
|
-
import { FEATURES, STATS, distance } from './font-fingerprint.mjs';
|
|
28
|
-
|
|
29
|
-
export const INDEX_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'data', 'font-index.json');
|
|
30
|
-
/** Cap heights the catalog is rendered at. `48c` is the same 48px cap in ALL
|
|
31
|
-
* CAPS text (schema 2), queried for caps crops; a schema-1 index without it
|
|
32
|
-
* routes caps crops to the mixed-case 48 as before. */
|
|
33
|
-
export const INDEX_SIZES = [48, 14, '48c'];
|
|
34
|
-
/** Crops with a cap height under this many px query the 14px index. */
|
|
35
|
-
export const ROUTE_CAP_PX = 22;
|
|
36
|
-
/** Below this cap height the fingerprint is not trustworthy; callers size by the box instead. */
|
|
37
|
-
export const MIN_RANK_CAP_PX = 10;
|
|
38
|
-
export const CATEGORIES = ['sans', 'serif', 'display', 'handwriting', 'mono'];
|
|
39
|
-
/** The features the index stores: the ones the fitted distance gives nonzero weight. */
|
|
40
|
-
export const GROSS_FEATURES = ['advance', 'advTall', 'advX', 'densTall', 'densX', 'stemW'];
|
|
41
|
-
export const INDEX_FEATURES = FEATURES.filter((k) => (STATS[k] && STATS[k].w > 0) || GROSS_FEATURES.includes(k));
|
|
42
|
-
|
|
43
|
-
const NULL_TOKEN = '___';
|
|
44
|
-
const MAX_Q = 36 ** 3 - 1;
|
|
45
|
-
|
|
46
|
-
export function packVector(fp, features = INDEX_FEATURES) {
|
|
47
|
-
return features.map((k) => {
|
|
48
|
-
const v = fp?.[k];
|
|
49
|
-
if (v == null || !Number.isFinite(v)) return NULL_TOKEN;
|
|
50
|
-
return Math.min(MAX_Q, Math.max(0, Math.round(v * 1000))).toString(36).padStart(3, '0');
|
|
51
|
-
}).join('');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function unpackVector(s, features = INDEX_FEATURES) {
|
|
55
|
-
const out = {};
|
|
56
|
-
for (let i = 0; i < features.length; i++) {
|
|
57
|
-
const t = s.slice(i * 3, i * 3 + 3);
|
|
58
|
-
out[features[i]] = t === NULL_TOKEN || t.length < 3 ? null : parseInt(t, 36) / 1000;
|
|
59
|
-
}
|
|
60
|
-
return out;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
let cached = null;
|
|
64
|
-
/**
|
|
65
|
-
* Load and decode the index. Returns null when the file is missing (callers
|
|
66
|
-
* fall back to their built-in shortlist). Result: { schema, text, sizes,
|
|
67
|
-
* features, entries: [{ family, weight, category, variable, fp: { 48: {...}, 14: {...}|null } }] }.
|
|
68
|
-
*/
|
|
69
|
-
export function loadFontIndex(file = INDEX_PATH) {
|
|
70
|
-
if (cached && cached.file === file) return cached.index;
|
|
71
|
-
if (!fs.existsSync(file)) return null;
|
|
72
|
-
const raw = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
73
|
-
const features = raw.features || INDEX_FEATURES;
|
|
74
|
-
const cats = raw.categories || CATEGORIES;
|
|
75
|
-
const sizes = raw.sizes || INDEX_SIZES;
|
|
76
|
-
const entries = raw.entries.map((e) => {
|
|
77
|
-
const fp = {};
|
|
78
|
-
sizes.forEach((sz, i) => { const v = e[4 + i]; fp[sz] = v ? unpackVector(v, features) : null; });
|
|
79
|
-
return { family: e[0], weight: e[1], category: cats[e[2]] ?? String(e[2]), variable: !!e[3], fp };
|
|
80
|
-
});
|
|
81
|
-
const index = { schema: raw.schema, text: raw.text, sizes, features, entries };
|
|
82
|
-
cached = { file, index };
|
|
83
|
-
return index;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Which of the index's cap sizes a crop with this cap height should query. */
|
|
87
|
-
export function routeSize(capHeightPx, sizes = INDEX_SIZES, { allCaps = false } = {}) {
|
|
88
|
-
const numeric = sizes.filter((s) => typeof s === 'number').sort((a, b) => a - b);
|
|
89
|
-
if (allCaps && capHeightPx >= ROUTE_CAP_PX && sizes.includes('48c')) return '48c';
|
|
90
|
-
return capHeightPx < ROUTE_CAP_PX ? numeric[0] : numeric[numeric.length - 1];
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* The n nearest catalog faces to a comp fingerprint, routed by cap height.
|
|
95
|
-
* Returns [{ family, weight, category, variable, d, size }] sorted by distance;
|
|
96
|
-
* at most `perFamily` entries of one family so the shortlist spans faces, not weights.
|
|
97
|
-
*/
|
|
98
|
-
/**
|
|
99
|
-
* Faces that are not lettering: barcodes, redaction bars, placeholder "flow"
|
|
100
|
-
* text, dingbats, symbol fonts, and effect faces (outlines, shades, glitch,
|
|
101
|
-
* pixel, 3D) whose fingerprint lands near heavy condensed text without being
|
|
102
|
-
* usable as it. A comp headline never wants them; a caller who does can pass
|
|
103
|
-
* them by name in `--candidates`.
|
|
104
|
-
*/
|
|
105
|
-
export const NON_TEXT_FAMILY = /barcode|^redacted|^flow (block|circular|rounded)|dings|symbols|^bungee (hairline|outline|shade|spice)|^rubik (80s|beastly|broken|bubbles|burned|dirt|distressed|doodle|gemstones|glitch|iso|lines|marker|maze|microbe|moonrocks|pixels|puddles|scribble|spray|storm|vinyl|wet)|^(nabla|honk|kablammo|sixtyfour|workbench|codystar|rock 3d|zen dots|ballet|butcherman|creepster|eater|faster one|frijole|nosifer|metal mania|miltonian)/i;
|
|
106
|
-
|
|
107
|
-
export function candidatesFromIndex(fp, index, { n = 25, category = null, perFamily = 2, includeNonText = false } = {}) {
|
|
108
|
-
if (!fp || !index) return [];
|
|
109
|
-
const size = routeSize(fp.capHeightPx, index.sizes, { allCaps: !!fp.allCaps });
|
|
110
|
-
const wantCat = category ? String(category).split(',').map((s) => s.trim().toLowerCase()).filter(Boolean) : null;
|
|
111
|
-
const scored = [];
|
|
112
|
-
for (const e of index.entries) {
|
|
113
|
-
if (wantCat && !wantCat.includes(e.category)) continue;
|
|
114
|
-
if (!includeNonText && NON_TEXT_FAMILY.test(e.family)) continue;
|
|
115
|
-
const v = e.fp[size];
|
|
116
|
-
if (!v) continue;
|
|
117
|
-
const d = distance(fp, v);
|
|
118
|
-
if (!Number.isFinite(d)) continue;
|
|
119
|
-
scored.push({ family: e.family, weight: e.weight, category: e.category, variable: e.variable, d, size });
|
|
120
|
-
}
|
|
121
|
-
scored.sort((a, b) => a.d - b.d);
|
|
122
|
-
const perFam = new Map(); const out = [];
|
|
123
|
-
for (const s of scored) {
|
|
124
|
-
const c = perFam.get(s.family) || 0;
|
|
125
|
-
if (c >= perFamily) continue;
|
|
126
|
-
perFam.set(s.family, c + 1); out.push(s);
|
|
127
|
-
if (out.length >= n) break;
|
|
128
|
-
}
|
|
129
|
-
return out;
|
|
130
|
-
}
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hero-gate checks that name a miss as a number the model can act on.
|
|
3
|
-
*
|
|
4
|
-
* comp-diff scores regions; these read what a designer reads when the two
|
|
5
|
-
* frames sit side by side and says it as numbers: the headline is set at
|
|
6
|
-
* cap 78px where the comp's is 103; it wraps to four lines where the comp
|
|
7
|
-
* has three; its ink is #2a2a2a where the comp's is #a72f1b; it starts
|
|
8
|
-
* 60px lower in its box; the masthead is 92px tall where the comp's is 58;
|
|
9
|
-
* these grid cells carry ink the comp does not have (a kicker, a divider, a
|
|
10
|
-
* second nav row). Every one of those was a pin in the first human review
|
|
11
|
-
* of the third sweep, on builds the region scores had already let through.
|
|
12
|
-
*
|
|
13
|
-
* All functions are pure over decoded rasters and the spec; the gate wires
|
|
14
|
-
* them and decides what vetoes.
|
|
15
|
-
*/
|
|
16
|
-
import { fingerprint } from './font-fingerprint.mjs';
|
|
17
|
-
import { crop } from './raster.mjs';
|
|
18
|
-
import { dominantColors, deltaE, detailGrid } from './image-metrics.mjs';
|
|
19
|
-
import { inkBox } from '../comp-diff.mjs';
|
|
20
|
-
|
|
21
|
-
/** Dominant ink colour of a crop: the heaviest cluster that is not the ground. */
|
|
22
|
-
export function inkColor(img) {
|
|
23
|
-
const cols = dominantColors(img, 4);
|
|
24
|
-
if (!cols.length) return null;
|
|
25
|
-
const ground = cols[0];
|
|
26
|
-
const ink = cols.find((c) => c !== ground && deltaE(c.lab, ground.lab) > 20) || null;
|
|
27
|
-
return { ground, ink };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Compare one text region's build crop against the comp's measurement.
|
|
32
|
-
* `region` is a spec region with `type.comp` (font-match --measure) and
|
|
33
|
-
* `px`; `compCrop` / `buildCrop` are the region crops at comp scale.
|
|
34
|
-
* Returns { findings: string[], metrics }.
|
|
35
|
-
*/
|
|
36
|
-
export function textRegionCheck(region, compCrop, buildCrop, { capTol = 0.22, minCap = 10 } = {}) {
|
|
37
|
-
const findings = [];
|
|
38
|
-
// Measure the comp crop now rather than trusting spec.type.comp: the spec
|
|
39
|
-
// may carry an older fingerprint's reading, and this check has to agree
|
|
40
|
-
// with itself on both sides.
|
|
41
|
-
const comp = fingerprint(compCrop);
|
|
42
|
-
// colour reads on any text region, measured or not: a spine set vertical
|
|
43
|
-
// (unmeasurable) came back white on red where the comp had black on red
|
|
44
|
-
// in five builds
|
|
45
|
-
const colourOnly = () => {
|
|
46
|
-
const ca = inkColor(compCrop), cb = inkColor(buildCrop);
|
|
47
|
-
if (ca && cb && ca.ink && cb.ink && deltaE(ca.ink.lab, cb.ink.lab) > 22) findings.push(`text ${region.id}: ink is ${cb.ink.hex} in the build, ${ca.ink.hex} in the comp; use the comp's colour`);
|
|
48
|
-
return { findings, metrics: null };
|
|
49
|
-
};
|
|
50
|
-
if (!comp || !comp.capHeightPx || comp.capHeightPx < minCap || comp.glyphs < 6) return colourOnly();
|
|
51
|
-
// rotated type (a spine set vertical) reads as many short 'lines' of one
|
|
52
|
-
// or two glyphs; the fingerprint has nothing to say about it
|
|
53
|
-
if (comp.lines >= 5 && comp.glyphs / comp.lines < 3) return colourOnly();
|
|
54
|
-
// a cap taller than half the box is a drawing read as a glyph, not type
|
|
55
|
-
if (comp.capHeightPx > compCrop.height * 0.6) return colourOnly();
|
|
56
|
-
const bfp = fingerprint(buildCrop);
|
|
57
|
-
const metrics = { comp: { cap: comp.capHeightPx, lines: comp.lines, glyphs: comp.glyphs }, build: bfp ? { cap: bfp.capHeightPx, lines: bfp.lines, glyphs: bfp.glyphs } : null };
|
|
58
|
-
if (!bfp || bfp.glyphs < 4) {
|
|
59
|
-
// nothing legible in the box: comp-diff's missing/contradicted covers it
|
|
60
|
-
return { findings, metrics };
|
|
61
|
-
}
|
|
62
|
-
const capDelta = (bfp.capHeightPx - comp.capHeightPx) / comp.capHeightPx;
|
|
63
|
-
if (Math.abs(capDelta) > capTol) {
|
|
64
|
-
findings.push(`text ${region.id}: cap height ${bfp.capHeightPx}px in the build, ${comp.capHeightPx}px in the comp (${capDelta > 0 ? '+' : ''}${Math.round(capDelta * 100)}%); set font-size so the cap height renders at ${comp.capHeightPx}px${region.type.chosen ? ` (font-match ranked ${region.type.chosen.family} ${region.type.chosen.weight} at ${region.type.chosen.fontSizePx}px)` : ''}`);
|
|
65
|
-
}
|
|
66
|
-
if (comp.lines >= 2 && bfp.lines !== comp.lines && Math.abs(bfp.lines - comp.lines) >= 1) {
|
|
67
|
-
findings.push(`text ${region.id}: ${bfp.lines} line${bfp.lines === 1 ? '' : 's'} in the build, ${comp.lines} in the comp; the measure (max-width, font-size, letter-spacing) wraps it differently, so the block is a different shape`);
|
|
68
|
-
} else if (comp.lines >= 3 && bfp.lines === comp.lines && Math.abs(capDelta) <= capTol) {
|
|
69
|
-
// same lines at the same size: the leading is the remaining shape
|
|
70
|
-
const ba0 = inkBox(compCrop), bb0 = inkBox(buildCrop);
|
|
71
|
-
if (ba0 && bb0) {
|
|
72
|
-
const pa = ba0.h / comp.lines, pb = bb0.h / bfp.lines;
|
|
73
|
-
const dp = (pb - pa) / pa;
|
|
74
|
-
if (Math.abs(dp) > 0.2) findings.push(`text ${region.id}: line pitch ${Math.round(pb)}px in the build, ${Math.round(pa)}px in the comp (${dp > 0 ? '+' : ''}${Math.round(dp * 100)}%); set line-height so ${comp.lines} lines stand ${Math.round(ba0.h)}px tall`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
// tracking: the gap between glyphs in cap units, when both sides read it
|
|
78
|
-
if (comp.gap != null && bfp.gap != null && Math.abs(capDelta) <= capTol && comp.glyphs >= 8 && bfp.glyphs >= 8) {
|
|
79
|
-
const dg = bfp.gap - comp.gap;
|
|
80
|
-
if (Math.abs(dg) > Math.max(0.03, comp.gap * 0.5)) findings.push(`text ${region.id}: letter-spacing is ${dg > 0 ? 'wider' : 'tighter'} than the comp's (gap ${bfp.gap.toFixed(3)} vs ${comp.gap.toFixed(3)} of the cap height); set letter-spacing to ${dg > 0 ? 'close' : 'open'} it by about ${Math.abs(Math.round(dg * comp.capHeightPx))}px`);
|
|
81
|
-
}
|
|
82
|
-
// weight: compare ink density of tall glyphs when both sides have it and
|
|
83
|
-
// the sizes agree (density at a different cap is a different reading)
|
|
84
|
-
if (comp.densTall != null && bfp.densTall != null && Math.abs(capDelta) <= capTol) {
|
|
85
|
-
const r = bfp.densTall / comp.densTall;
|
|
86
|
-
if (r > 1.25) findings.push(`text ${region.id}: the face renders ${Math.round((r - 1) * 100)}% heavier than the comp's (ink density ${bfp.densTall.toFixed(2)} vs ${comp.densTall.toFixed(2)}); drop a weight step or use the ranked face`);
|
|
87
|
-
else if (r < 0.75) findings.push(`text ${region.id}: the face renders ${Math.round((1 - r) * 100)}% lighter than the comp's (ink density ${bfp.densTall.toFixed(2)} vs ${comp.densTall.toFixed(2)}); raise a weight step or use the ranked face`);
|
|
88
|
-
}
|
|
89
|
-
// colour: dominant ink of each crop. Small type on a ruled or grainy
|
|
90
|
-
// ground (a track row across staff lines at cap 14) has no reliable ink
|
|
91
|
-
// cluster; the reading fired both ways on neighbouring rows of one list.
|
|
92
|
-
if (comp.capHeightPx >= 16) {
|
|
93
|
-
const ca = inkColor(compCrop), cb = inkColor(buildCrop);
|
|
94
|
-
if (ca && cb && ca.ink && cb.ink) {
|
|
95
|
-
const d = deltaE(ca.ink.lab, cb.ink.lab);
|
|
96
|
-
if (d > 22) findings.push(`text ${region.id}: ink is ${cb.ink.hex} in the build, ${ca.ink.hex} in the comp; use the comp's colour`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// vertical placement inside the box: top of ink
|
|
100
|
-
const ba = inkBox(compCrop), bb = inkBox(buildCrop);
|
|
101
|
-
if (ba && bb) {
|
|
102
|
-
const dy = bb.y - ba.y;
|
|
103
|
-
if (Math.abs(dy) > Math.max(12, compCrop.height * 0.15)) findings.push(`text ${region.id}: its first line starts ${Math.abs(Math.round(dy))}px ${dy > 0 ? 'lower' : 'higher'} than in the comp (${bb.y}px vs ${ba.y}px into the region box); the spacing above it is ${dy > 0 ? 'too large' : 'too small'}`);
|
|
104
|
-
const dx = bb.x - ba.x;
|
|
105
|
-
if (Math.abs(dx) > Math.max(12, compCrop.width * 0.15)) findings.push(`text ${region.id}: it starts ${Math.abs(Math.round(dx))}px ${dx > 0 ? 'further right' : 'further left'} than in the comp`);
|
|
106
|
-
}
|
|
107
|
-
metrics.capDelta = +capDelta.toFixed(3);
|
|
108
|
-
return { findings, metrics };
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Rows of a crop that carry a horizontal rule: a row whose gray step from
|
|
113
|
-
* the row above (or below) is strong across at least `span` of the width.
|
|
114
|
-
* Returns row indices sorted top to bottom.
|
|
115
|
-
*/
|
|
116
|
-
export function ruleRows(img, { span = 0.5, step = 28 } = {}) {
|
|
117
|
-
const W = img.width, H = img.height;
|
|
118
|
-
const gray = (x, y) => { const i = (y * W + x) * 4; return 0.299 * img.data[i] + 0.587 * img.data[i + 1] + 0.114 * img.data[i + 2]; };
|
|
119
|
-
const rows = [];
|
|
120
|
-
for (let y = 1; y < H - 1; y++) {
|
|
121
|
-
let strong = 0;
|
|
122
|
-
for (let x = 0; x < W; x++) { const d = Math.max(Math.abs(gray(x, y) - gray(x, y - 1)), Math.abs(gray(x, y) - gray(x, y + 1))); if (d > step) strong++; }
|
|
123
|
-
if (strong >= W * span) rows.push(y);
|
|
124
|
-
}
|
|
125
|
-
// collapse adjacent rows into one edge
|
|
126
|
-
const out = [];
|
|
127
|
-
for (const y of rows) if (!out.length || y - out[out.length - 1] > 3) out.push(y);
|
|
128
|
-
return out;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* A thin chrome region (masthead, nav bar, footer strip) has a height, and
|
|
133
|
-
* its height is where its rule sits. Compare the first horizontal rule's row
|
|
134
|
-
* in comp vs build; fall back to the ink extents when neither has a rule.
|
|
135
|
-
*/
|
|
136
|
-
export function chromeStripCheck(region, compCrop, buildCrop) {
|
|
137
|
-
const findings = [];
|
|
138
|
-
const strip = compCrop.height <= compCrop.width * 0.35;
|
|
139
|
-
if (!strip) return { findings };
|
|
140
|
-
// a control that is one link or one button, not a bar across its box, has
|
|
141
|
-
// no strip height to compare (its underline read as a 'rule' for 27
|
|
142
|
-
// attempts in one session)
|
|
143
|
-
if (region.kind === 'control') {
|
|
144
|
-
const ib = inkBox(compCrop);
|
|
145
|
-
if (!ib || ib.w < compCrop.width * 0.6) return { findings };
|
|
146
|
-
}
|
|
147
|
-
const ra = ruleRows(compCrop), rb = ruleRows(buildCrop);
|
|
148
|
-
if (ra.length && rb.length) {
|
|
149
|
-
// the rule that closes the strip is the first one from the top (a grid
|
|
150
|
-
// row often carries the next element's top edge lower down)
|
|
151
|
-
const ya = ra[0], yb = rb[0];
|
|
152
|
-
const dy = yb - ya;
|
|
153
|
-
if (Math.abs(dy) > Math.max(5, compCrop.height * 0.06)) findings.push(`${region.kind} ${region.id}: its rule sits ${ya}px into the box in the comp and ${yb}px in the build (${dy > 0 ? '+' : ''}${dy}px), so the strip is ${dy > 0 ? 'taller' : 'shorter'} than the comp's; match the height, not only the position`);
|
|
154
|
-
return { findings, comp: ya, build: yb };
|
|
155
|
-
}
|
|
156
|
-
const ba = inkBox(compCrop), bb = inkBox(buildCrop);
|
|
157
|
-
if (!ba || !bb) return { findings };
|
|
158
|
-
if (ba.w >= compCrop.width * 0.6 && ba.h <= compCrop.height * 0.6) {
|
|
159
|
-
const dh = bb.h - ba.h;
|
|
160
|
-
if (Math.abs(dh) > Math.max(10, ba.h * 0.25)) findings.push(`${region.kind} ${region.id}: its ink is ${bb.h}px tall in the build and ${ba.h}px in the comp (${dh > 0 ? '+' : ''}${dh}px); match the height, not only the position`);
|
|
161
|
-
}
|
|
162
|
-
return { findings, comp: ba, build: bb };
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Cells of the frame where the build carries ink and the comp is calm.
|
|
167
|
-
* Returns { cells: [{col,row,label}], fraction } on a cols x rows grid.
|
|
168
|
-
* `floor` is the comp energy under which a cell counts as calm; `added` is
|
|
169
|
-
* the build energy over which the build counts as inked.
|
|
170
|
-
*/
|
|
171
|
-
export function inventedInk(comp, build, { cols = 10, rows = 10, floor = 10, added = 12, ratio = 2.5 } = {}) {
|
|
172
|
-
const a = detailGrid(comp, cols, rows, 512), b = detailGrid(build, cols, rows, 512);
|
|
173
|
-
const cells = [];
|
|
174
|
-
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
|
|
175
|
-
const i = r * cols + c;
|
|
176
|
-
// calm in the comp (grain, flat ground) and inked in the build well past
|
|
177
|
-
// what grain would give: a kicker over paper, a divider, a nav row
|
|
178
|
-
if (!(a.cells[i] < floor && b.cells[i] > Math.max(added, a.cells[i] * ratio))) continue;
|
|
179
|
-
// the comp must be calm around the cell too: a hard edge one pixel over
|
|
180
|
-
// the cell boundary in the build (a bar shifted by a subpixel of the
|
|
181
|
-
// alignment) reads as invented otherwise
|
|
182
|
-
let neighbourhood = 0, n = 0;
|
|
183
|
-
for (let dr = -1; dr <= 1; dr++) for (let dc = -1; dc <= 1; dc++) { const rr = r + dr, cc = c + dc; if (rr < 0 || cc < 0 || rr >= rows || cc >= cols) continue; neighbourhood += a.cells[rr * cols + cc]; n++; }
|
|
184
|
-
if (neighbourhood / n >= floor * 2) continue;
|
|
185
|
-
cells.push({ col: c, row: r, label: `${String.fromCharCode(65 + c)}${r}`, comp: +a.cells[i].toFixed(1), build: +b.cells[i].toFixed(1) });
|
|
186
|
-
}
|
|
187
|
-
return { cells, fraction: cells.length / (cols * rows) };
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* A plate cropped by its box: the comp's artwork keeps a margin inside the
|
|
192
|
-
* region on some side and the build's ink runs flush to that edge (object-fit:
|
|
193
|
-
* cover on a box smaller than the artwork's aspect, or an <img> sized to the
|
|
194
|
-
* column). The best build of the fifth sweep passed the hero at 87% with the
|
|
195
|
-
* cover arch cut off at the left and bottom; the human review called it a
|
|
196
|
-
* bug in one word. Returns the sides clipped, or [].
|
|
197
|
-
*/
|
|
198
|
-
export function plateClipCheck(region, compCrop, buildCrop, { margin = 6 } = {}) {
|
|
199
|
-
const a = inkBox(compCrop), b = inkBox(buildCrop);
|
|
200
|
-
if (!a || !b) return { sides: [] };
|
|
201
|
-
const W = compCrop.width, H = compCrop.height;
|
|
202
|
-
const sides = [];
|
|
203
|
-
const flush = (v) => v <= 1;
|
|
204
|
-
if (a.x >= margin && flush(b.x)) sides.push('left');
|
|
205
|
-
if (a.y >= margin && flush(b.y)) sides.push('top');
|
|
206
|
-
if (W - (a.x + a.w) >= margin && flush(W - (b.x + b.w))) sides.push('right');
|
|
207
|
-
if (H - (a.y + a.h) >= margin && flush(H - (b.y + b.h))) sides.push('bottom');
|
|
208
|
-
return { sides, comp: a, build: b };
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Inline SVG that is an illustration, not an icon. An icon is small (a
|
|
213
|
-
* viewBox or box under `iconPx` on its long side) with a few paths; anything
|
|
214
|
-
* with a real path budget is a drawing in code: a diagram, a rack of
|
|
215
|
-
* carburetors, staff notation, leader lines with arrows, a "terrible svg
|
|
216
|
-
* approximation of the asset". Those ship as plates or as part of the plate
|
|
217
|
-
* they annotate. Returns one entry per offending <svg> with a snippet.
|
|
218
|
-
*
|
|
219
|
-
* `html` is the artifact source. `pathBudget` counts characters of path
|
|
220
|
-
* data (d="..."), points, and polyline/polygon points across the element.
|
|
221
|
-
*/
|
|
222
|
-
export function svgIllustrations(html, { iconPx = 64, pathBudget = 480, maxPaths = 8 } = {}) {
|
|
223
|
-
const out = [];
|
|
224
|
-
const re = /<svg\b([^>]*)>([\s\S]*?)<\/svg>/gi;
|
|
225
|
-
let m;
|
|
226
|
-
while ((m = re.exec(html))) {
|
|
227
|
-
const attrs = m[1], body = m[2];
|
|
228
|
-
const paths = (body.match(/<path\b/gi) || []).length + (body.match(/<(polyline|polygon|line|circle|ellipse|rect)\b/gi) || []).length;
|
|
229
|
-
let budget = 0;
|
|
230
|
-
for (const d of body.matchAll(/\sd="([^"]*)"/g)) budget += d[1].length;
|
|
231
|
-
for (const pts of body.matchAll(/\spoints="([^"]*)"/g)) budget += pts[1].length;
|
|
232
|
-
const vb = /viewBox="\s*[-\d.]+\s+[-\d.]+\s+([\d.]+)\s+([\d.]+)/.exec(attrs);
|
|
233
|
-
const w = /\swidth="([\d.]+)(px)?"/.exec(attrs), h = /\sheight="([\d.]+)(px)?"/.exec(attrs);
|
|
234
|
-
const long = Math.max(vb ? Math.max(+vb[1], +vb[2]) : 0, w ? +w[1] : 0, h ? +h[1] : 0);
|
|
235
|
-
const iconSized = long > 0 && long <= iconPx && paths <= maxPaths;
|
|
236
|
-
const uses = /<use\b/i.test(body) && paths === 0; // a sprite reference
|
|
237
|
-
if (uses) continue;
|
|
238
|
-
if (iconSized && budget <= pathBudget) continue;
|
|
239
|
-
if (budget <= pathBudget && paths <= maxPaths && long === 0 && !/<(text|image)\b/i.test(body)) continue; // a tiny inline glyph with no size hint
|
|
240
|
-
if (budget > pathBudget || paths > maxPaths || (long > iconPx && paths > 0)) {
|
|
241
|
-
const id = /\b(id|class|aria-label|data-region)="([^"]+)"/i.exec(attrs);
|
|
242
|
-
out.push({ snippet: `<svg${attrs.slice(0, 80).replace(/\s+/g, ' ')}...> (${paths} shapes, ${budget} chars of path data${long ? `, ${long}px` : ''})`, label: id ? id[2] : null, paths, budget, long });
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
return out;
|
|
246
|
-
}
|