@palate/cli 0.0.0-stage → 0.0.1
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 +20 -0
- package/README.md +151 -2
- package/bin/palate.mjs +894 -0
- package/kb/anatomy/data-table.md +24 -0
- package/kb/anatomy/empty-state.md +16 -0
- package/kb/anatomy/filter-toolbar.md +19 -0
- package/kb/anatomy/meter.md +16 -0
- package/kb/anatomy/product-window.md +18 -0
- package/kb/anatomy/settings-page.md +18 -0
- package/kb/anatomy/status-indicator.md +17 -0
- package/kb/anatomy/toast-undo.md +16 -0
- package/kb/bench/briefs.json +618 -0
- package/kb/craft/SOURCES.md +48 -0
- package/kb/craft/creativity.md +55 -0
- package/kb/craft/details.md +75 -0
- package/kb/craft/landing-demos.md +46 -0
- package/kb/craft/mistakes.md +73 -0
- package/kb/craft/motion.md +53 -0
- package/kb/craft/principles.md +68 -0
- package/kb/index/discovery.json +1 -0
- package/kb/inspiration/index.json +79 -0
- package/kb/moves/animated-comparison-table.md +58 -0
- package/kb/moves/before-after-slider.md +58 -0
- package/kb/moves/bento-live-tiles.md +57 -0
- package/kb/moves/calm-motion-system.md +63 -0
- package/kb/moves/canvas-grain.md +58 -0
- package/kb/moves/changelog-as-magazine.md +56 -0
- package/kb/moves/code-drawn-diagram.md +56 -0
- package/kb/moves/colophon.md +54 -0
- package/kb/moves/command-palette-site-nav.md +58 -0
- package/kb/moves/confetti-free-celebration.md +58 -0
- package/kb/moves/console-easter-egg.md +57 -0
- package/kb/moves/copy-confirmation.md +57 -0
- package/kb/moves/cursor-reactive-light.md +57 -0
- package/kb/moves/dark-band-contrast-section.md +55 -0
- package/kb/moves/designed-dark-mode.md +58 -0
- package/kb/moves/duotone-photography.md +55 -0
- package/kb/moves/editorial-drop-cap.md +58 -0
- package/kb/moves/editorial-grid-pull-quotes.md +55 -0
- package/kb/moves/engraving-colour-lens.md +64 -0
- package/kb/moves/explorable-control.md +57 -0
- package/kb/moves/feature-films-on-painted-stages.md +58 -0
- package/kb/moves/first-win-onboarding.md +59 -0
- package/kb/moves/footer-live-status.md +56 -0
- package/kb/moves/footer-rewards-the-end.md +58 -0
- package/kb/moves/generative-brand-pattern.md +55 -0
- package/kb/moves/gentle-error-nudge.md +59 -0
- package/kb/moves/halftone-dot-imagery.md +55 -0
- package/kb/moves/hand-drawn-annotations.md +55 -0
- package/kb/moves/hero-paints-itself-in.md +65 -0
- package/kb/moves/honest-progress-narration.md +58 -0
- package/kb/moves/honest-testimonial-wall.md +57 -0
- package/kb/moves/inline-sparklines-in-copy.md +57 -0
- package/kb/moves/inspect-our-taste.md +58 -0
- package/kb/moves/interactive-pricing-calculator.md +59 -0
- package/kb/moves/isometric-illustration-system.md +56 -0
- package/kb/moves/kinetic-variable-type.md +57 -0
- package/kb/moves/konami-secret.md +59 -0
- package/kb/moves/layered-paper-depth.md +56 -0
- package/kb/moves/lightweight-3d-object-hero.md +59 -0
- package/kb/moves/line-engraving-from-image.md +63 -0
- package/kb/moves/link-preview-peek.md +57 -0
- package/kb/moves/live-data-ticker.md +61 -0
- package/kb/moves/made-with-proof.md +51 -0
- package/kb/moves/magnetic-buttons.md +55 -0
- package/kb/moves/marquee-done-right.md +58 -0
- package/kb/moves/moves.yaml +450 -0
- package/kb/moves/museum-painting-backdrop.md +59 -0
- package/kb/moves/one-colour-brand-world.md +56 -0
- package/kb/moves/playful-404.md +58 -0
- package/kb/moves/pointer-highlight-word.md +56 -0
- package/kb/moves/product-in-context.md +56 -0
- package/kb/moves/real-world-data.md +58 -0
- package/kb/moves/referral-reward-reveal.md +59 -0
- package/kb/moves/riso-print-texture.md +57 -0
- package/kb/moves/screenshot-detail-crops.md +56 -0
- package/kb/moves/scroll-progress-chapters.md +57 -0
- package/kb/moves/scroll-scrubbed-product-film.md +62 -0
- package/kb/moves/self-playing-product-demo.md +61 -0
- package/kb/moves/shape-continuity-morph.md +58 -0
- package/kb/moves/sliding-nav-indicator.md +58 -0
- package/kb/moves/sticky-scroll-story.md +56 -0
- package/kb/moves/story-led-long-scroll.md +56 -0
- package/kb/moves/tactile-button.md +63 -0
- package/kb/moves/technical-drawing-lines.md +57 -0
- package/kb/moves/time-of-day-theming.md +56 -0
- package/kb/moves/tiny-game-easter-egg.md +60 -0
- package/kb/moves/type-decode-reveal.md +57 -0
- package/kb/moves/typographic-numeral-hero.md +58 -0
- package/kb/moves/view-transitions-between-pages.md +57 -0
- package/kb/moves/waitlist-position-live.md +60 -0
- package/kb/patterns/app-team-members.md +27 -0
- package/kb/patterns/chat-agent-approvals.md +31 -0
- package/kb/patterns/commerce-product-page.md +34 -0
- package/kb/patterns/dashboard-entity-table.md +37 -0
- package/kb/patterns/dashboard-home-today.md +24 -0
- package/kb/patterns/docs-api-reference.md +31 -0
- package/kb/patterns/marketing-product-led-landing.md +30 -0
- package/kb/patterns/mobile-daily-checklist.md +26 -0
- package/kb/references/index.json +1 -0
- package/kb/references/thumbs/004c5e9072.jpg +0 -0
- package/kb/references/thumbs/008915eb21.jpg +0 -0
- package/kb/references/thumbs/0098cf66c2.jpg +0 -0
- package/kb/references/thumbs/012e61b31f.jpg +0 -0
- package/kb/references/thumbs/014d4e46fc.jpg +0 -0
- package/kb/references/thumbs/01e54f394a.jpg +0 -0
- package/kb/references/thumbs/01e99a579c.jpg +0 -0
- package/kb/references/thumbs/01fd014575.jpg +0 -0
- package/kb/references/thumbs/022778ca72.jpg +0 -0
- package/kb/references/thumbs/02717bf1e1.jpg +0 -0
- package/kb/references/thumbs/02a5cfdbe9.jpg +0 -0
- package/kb/references/thumbs/02c9823f8d.jpg +0 -0
- package/kb/references/thumbs/02f3974613.jpg +0 -0
- package/kb/references/thumbs/032427f1ce.jpg +0 -0
- package/kb/references/thumbs/03ba677d07.jpg +0 -0
- package/kb/references/thumbs/04f2476cfe.jpg +0 -0
- package/kb/references/thumbs/0563e7c52e.jpg +0 -0
- package/kb/references/thumbs/05fa6b8eef.jpg +0 -0
- package/kb/references/thumbs/065bce1517.jpg +0 -0
- package/kb/references/thumbs/06c017f113.jpg +0 -0
- package/kb/references/thumbs/0770e2d8d3.jpg +0 -0
- package/kb/references/thumbs/078a26c4cb.jpg +0 -0
- package/kb/references/thumbs/08679b6e84.jpg +0 -0
- package/kb/references/thumbs/088c45a34c.jpg +0 -0
- package/kb/references/thumbs/089e9fd4e4.jpg +0 -0
- package/kb/references/thumbs/08f773231e.jpg +0 -0
- package/kb/references/thumbs/093ca3e2e3.jpg +0 -0
- package/kb/references/thumbs/0963320f74.jpg +0 -0
- package/kb/references/thumbs/09fc1ded85.jpg +0 -0
- package/kb/references/thumbs/0a368f3963.jpg +0 -0
- package/kb/references/thumbs/0a9e0e5201.jpg +0 -0
- package/kb/references/thumbs/0aace67ee7.jpg +0 -0
- package/kb/references/thumbs/0b61ecf793.jpg +0 -0
- package/kb/references/thumbs/0bde18ae09.jpg +0 -0
- package/kb/references/thumbs/0bf7ee8143.jpg +0 -0
- package/kb/references/thumbs/0ca20a13e0.jpg +0 -0
- package/kb/references/thumbs/0cdc0198c4.jpg +0 -0
- package/kb/references/thumbs/0cf9790b28.jpg +0 -0
- package/kb/references/thumbs/0d0202904b.jpg +0 -0
- package/kb/references/thumbs/0d053aba18.jpg +0 -0
- package/kb/references/thumbs/0d0c2c13d2.jpg +0 -0
- package/kb/references/thumbs/0d30be99b0.jpg +0 -0
- package/kb/references/thumbs/0d503da1b7.jpg +0 -0
- package/kb/references/thumbs/0ddad7b740.jpg +0 -0
- package/kb/references/thumbs/0e0a148101.jpg +0 -0
- package/kb/references/thumbs/0e401b6b75.jpg +0 -0
- package/kb/references/thumbs/0e8f32ba0f.jpg +0 -0
- package/kb/references/thumbs/0ef1966a7d.jpg +0 -0
- package/kb/references/thumbs/0efd416d11.jpg +0 -0
- package/kb/references/thumbs/0f3af263ae.jpg +0 -0
- package/kb/references/thumbs/0f9644c3a5.jpg +0 -0
- package/kb/references/thumbs/1020552737.jpg +0 -0
- package/kb/references/thumbs/1037626587.jpg +0 -0
- package/kb/references/thumbs/10512b7e94.jpg +0 -0
- package/kb/references/thumbs/106dc4a7b5.jpg +0 -0
- package/kb/references/thumbs/108943f6f7.jpg +0 -0
- package/kb/references/thumbs/10a5551d51.jpg +0 -0
- package/kb/references/thumbs/10dd01076c.jpg +0 -0
- package/kb/references/thumbs/11b06e39da.jpg +0 -0
- package/kb/references/thumbs/11baa1ec83.jpg +0 -0
- package/kb/references/thumbs/11bbe12167.jpg +0 -0
- package/kb/references/thumbs/11ca37feb8.jpg +0 -0
- package/kb/references/thumbs/11f14d3f12.jpg +0 -0
- package/kb/references/thumbs/124530ceb5.jpg +0 -0
- package/kb/references/thumbs/1276402336.jpg +0 -0
- package/kb/references/thumbs/1280e5c9d6.jpg +0 -0
- package/kb/references/thumbs/12cac0d172.jpg +0 -0
- package/kb/references/thumbs/138be6623a.jpg +0 -0
- package/kb/references/thumbs/13a0c544d1.jpg +0 -0
- package/kb/references/thumbs/13a32cb94c.jpg +0 -0
- package/kb/references/thumbs/144035d641.jpg +0 -0
- package/kb/references/thumbs/1457e41924.jpg +0 -0
- package/kb/references/thumbs/14972e3a86.jpg +0 -0
- package/kb/references/thumbs/15a47f2e4c.jpg +0 -0
- package/kb/references/thumbs/15aa15d22e.jpg +0 -0
- package/kb/references/thumbs/160dcd24b7.jpg +0 -0
- package/kb/references/thumbs/1610978529.jpg +0 -0
- package/kb/references/thumbs/16db30ba37.jpg +0 -0
- package/kb/references/thumbs/16f19ae4f3.jpg +0 -0
- package/kb/references/thumbs/16f758b03f.jpg +0 -0
- package/kb/references/thumbs/1748e5b751.jpg +0 -0
- package/kb/references/thumbs/175d0b0e69.jpg +0 -0
- package/kb/references/thumbs/178f571a36.jpg +0 -0
- package/kb/references/thumbs/17c43dc025.jpg +0 -0
- package/kb/references/thumbs/17c7f05b50.jpg +0 -0
- package/kb/references/thumbs/17f97e61dd.jpg +0 -0
- package/kb/references/thumbs/1804e17365.jpg +0 -0
- package/kb/references/thumbs/195c162ed1.jpg +0 -0
- package/kb/references/thumbs/19e3699c29.jpg +0 -0
- package/kb/references/thumbs/1a48e0a4d5.jpg +0 -0
- package/kb/references/thumbs/1a6cda265e.jpg +0 -0
- package/kb/references/thumbs/1a7e012091.jpg +0 -0
- package/kb/references/thumbs/1a9173a172.jpg +0 -0
- package/kb/references/thumbs/1b34a6b4d2.jpg +0 -0
- package/kb/references/thumbs/1b5284f3b2.jpg +0 -0
- package/kb/references/thumbs/1b93fbd6d3.jpg +0 -0
- package/kb/references/thumbs/1c6728fef6.jpg +0 -0
- package/kb/references/thumbs/1c6f101618.jpg +0 -0
- package/kb/references/thumbs/1cf7011a94.jpg +0 -0
- package/kb/references/thumbs/1d1769e539.jpg +0 -0
- package/kb/references/thumbs/1d1fd23199.jpg +0 -0
- package/kb/references/thumbs/1d7b6602ac.jpg +0 -0
- package/kb/references/thumbs/1dbbc61b9e.jpg +0 -0
- package/kb/references/thumbs/1dbdd6d21d.jpg +0 -0
- package/kb/references/thumbs/1dd873744b.jpg +0 -0
- package/kb/references/thumbs/1df4dd7cf9.jpg +0 -0
- package/kb/references/thumbs/1ece8c35b8.jpg +0 -0
- package/kb/references/thumbs/1f0e5b9aa4.jpg +0 -0
- package/kb/references/thumbs/1f1419651b.jpg +0 -0
- package/kb/references/thumbs/1f2a6da92d.jpg +0 -0
- package/kb/references/thumbs/1f651f33c0.jpg +0 -0
- package/kb/references/thumbs/1f8b697d18.jpg +0 -0
- package/kb/references/thumbs/1fee3824cd.jpg +0 -0
- package/kb/references/thumbs/1ff7757853.jpg +0 -0
- package/kb/references/thumbs/2043182f01.jpg +0 -0
- package/kb/references/thumbs/2059dabcd5.jpg +0 -0
- package/kb/references/thumbs/209d9dbb95.jpg +0 -0
- package/kb/references/thumbs/20d8923554.jpg +0 -0
- package/kb/references/thumbs/210dd3b671.jpg +0 -0
- package/kb/references/thumbs/2120719116.jpg +0 -0
- package/kb/references/thumbs/21a7384429.jpg +0 -0
- package/kb/references/thumbs/225f187391.jpg +0 -0
- package/kb/references/thumbs/230caf7dd2.jpg +0 -0
- package/kb/references/thumbs/235afad355.jpg +0 -0
- package/kb/references/thumbs/2378066687.jpg +0 -0
- package/kb/references/thumbs/241faf68a1.jpg +0 -0
- package/kb/references/thumbs/24d9f1a9b9.jpg +0 -0
- package/kb/references/thumbs/2505c8b9a0.jpg +0 -0
- package/kb/references/thumbs/25593638ca.jpg +0 -0
- package/kb/references/thumbs/25dd454f18.jpg +0 -0
- package/kb/references/thumbs/2602e123e2.jpg +0 -0
- package/kb/references/thumbs/26095c0b11.jpg +0 -0
- package/kb/references/thumbs/26260d6238.jpg +0 -0
- package/kb/references/thumbs/26bba21836.jpg +0 -0
- package/kb/references/thumbs/26bde3520b.jpg +0 -0
- package/kb/references/thumbs/272e22067c.jpg +0 -0
- package/kb/references/thumbs/27421b3226.jpg +0 -0
- package/kb/references/thumbs/2769ebca41.jpg +0 -0
- package/kb/references/thumbs/27e2f6e8b0.jpg +0 -0
- package/kb/references/thumbs/28432ba373.jpg +0 -0
- package/kb/references/thumbs/2846626f19.jpg +0 -0
- package/kb/references/thumbs/28750e821e.jpg +0 -0
- package/kb/references/thumbs/289481230f.jpg +0 -0
- package/kb/references/thumbs/2897967408.jpg +0 -0
- package/kb/references/thumbs/28c0a5fa17.jpg +0 -0
- package/kb/references/thumbs/28c181fba5.jpg +0 -0
- package/kb/references/thumbs/29806f539f.jpg +0 -0
- package/kb/references/thumbs/2997f56ee7.jpg +0 -0
- package/kb/references/thumbs/29b34a10fb.jpg +0 -0
- package/kb/references/thumbs/29bd78cdb4.jpg +0 -0
- package/kb/references/thumbs/29c8c6c22a.jpg +0 -0
- package/kb/references/thumbs/2ac23f7fae.jpg +0 -0
- package/kb/references/thumbs/2b76e13f79.jpg +0 -0
- package/kb/references/thumbs/2b84226479.jpg +0 -0
- package/kb/references/thumbs/2bf2dbf737.jpg +0 -0
- package/kb/references/thumbs/2bf89abbf6.jpg +0 -0
- package/kb/references/thumbs/2c562cd534.jpg +0 -0
- package/kb/references/thumbs/2cfe9d48c4.jpg +0 -0
- package/kb/references/thumbs/2d49f19b27.jpg +0 -0
- package/kb/references/thumbs/2dc8670da7.jpg +0 -0
- package/kb/references/thumbs/2de947c469.jpg +0 -0
- package/kb/references/thumbs/2e075ca79f.jpg +0 -0
- package/kb/references/thumbs/2eb0820e6b.jpg +0 -0
- package/kb/references/thumbs/2ec56a9dc0.jpg +0 -0
- package/kb/references/thumbs/30bb4ad607.jpg +0 -0
- package/kb/references/thumbs/30d19b8444.jpg +0 -0
- package/kb/references/thumbs/3173c71d73.jpg +0 -0
- package/kb/references/thumbs/31e59e4518.jpg +0 -0
- package/kb/references/thumbs/322b8960e8.jpg +0 -0
- package/kb/references/thumbs/325c9be6f4.jpg +0 -0
- package/kb/references/thumbs/3273338982.jpg +0 -0
- package/kb/references/thumbs/32f8387f38.jpg +0 -0
- package/kb/references/thumbs/332f6b74c3.jpg +0 -0
- package/kb/references/thumbs/334b146b6a.jpg +0 -0
- package/kb/references/thumbs/339abd60e4.jpg +0 -0
- package/kb/references/thumbs/33e88ec295.jpg +0 -0
- package/kb/references/thumbs/340931b5d4.jpg +0 -0
- package/kb/references/thumbs/34165a93bd.jpg +0 -0
- package/kb/references/thumbs/34d0575dd7.jpg +0 -0
- package/kb/references/thumbs/3549e75f0a.jpg +0 -0
- package/kb/references/thumbs/35827f1561.jpg +0 -0
- package/kb/references/thumbs/37c50280ec.jpg +0 -0
- package/kb/references/thumbs/37e66ecf11.jpg +0 -0
- package/kb/references/thumbs/3841a04fdc.jpg +0 -0
- package/kb/references/thumbs/38490c088f.jpg +0 -0
- package/kb/references/thumbs/3850319e9f.jpg +0 -0
- package/kb/references/thumbs/3856a64166.jpg +0 -0
- package/kb/references/thumbs/3881f211c2.jpg +0 -0
- package/kb/references/thumbs/38c7dde2f3.jpg +0 -0
- package/kb/references/thumbs/38ce9e486c.jpg +0 -0
- package/kb/references/thumbs/390ea8e01b.jpg +0 -0
- package/kb/references/thumbs/391b7fc27c.jpg +0 -0
- package/kb/references/thumbs/395f7214dc.jpg +0 -0
- package/kb/references/thumbs/39e81a5db2.jpg +0 -0
- package/kb/references/thumbs/3a67c8d655.jpg +0 -0
- package/kb/references/thumbs/3a89c25e3b.jpg +0 -0
- package/kb/references/thumbs/3aa0837542.jpg +0 -0
- package/kb/references/thumbs/3aae18aa8a.jpg +0 -0
- package/kb/references/thumbs/3bdbe767db.jpg +0 -0
- package/kb/references/thumbs/3c0616fc7f.jpg +0 -0
- package/kb/references/thumbs/3c18e9db1d.jpg +0 -0
- package/kb/references/thumbs/3c5a14076c.jpg +0 -0
- package/kb/references/thumbs/3ca9ec15c6.jpg +0 -0
- package/kb/references/thumbs/3d7756fd35.jpg +0 -0
- package/kb/references/thumbs/3dd45bd33d.jpg +0 -0
- package/kb/references/thumbs/3de72d5414.jpg +0 -0
- package/kb/references/thumbs/3dede597af.jpg +0 -0
- package/kb/references/thumbs/3ea948619e.jpg +0 -0
- package/kb/references/thumbs/402c12054c.jpg +0 -0
- package/kb/references/thumbs/403ab4af90.jpg +0 -0
- package/kb/references/thumbs/40773a8c63.jpg +0 -0
- package/kb/references/thumbs/407d9583db.jpg +0 -0
- package/kb/references/thumbs/415dc1d84c.jpg +0 -0
- package/kb/references/thumbs/420b676a4f.jpg +0 -0
- package/kb/references/thumbs/42a1ee85eb.jpg +0 -0
- package/kb/references/thumbs/43059221aa.jpg +0 -0
- package/kb/references/thumbs/432fa0d22c.jpg +0 -0
- package/kb/references/thumbs/43826f20e3.jpg +0 -0
- package/kb/references/thumbs/43ac55c98a.jpg +0 -0
- package/kb/references/thumbs/43d098f3c3.jpg +0 -0
- package/kb/references/thumbs/4449d80c2c.jpg +0 -0
- package/kb/references/thumbs/44625727dc.jpg +0 -0
- package/kb/references/thumbs/4482bb87a1.jpg +0 -0
- package/kb/references/thumbs/44b078acdc.jpg +0 -0
- package/kb/references/thumbs/44d0305850.jpg +0 -0
- package/kb/references/thumbs/456bb6b59e.jpg +0 -0
- package/kb/references/thumbs/45df73ce48.jpg +0 -0
- package/kb/references/thumbs/45edb45d87.jpg +0 -0
- package/kb/references/thumbs/4671d57cd5.jpg +0 -0
- package/kb/references/thumbs/46cc108518.jpg +0 -0
- package/kb/references/thumbs/470022e614.jpg +0 -0
- package/kb/references/thumbs/4719a669ce.jpg +0 -0
- package/kb/references/thumbs/47404f5ad4.jpg +0 -0
- package/kb/references/thumbs/479d3eb977.jpg +0 -0
- package/kb/references/thumbs/479ed92ceb.jpg +0 -0
- package/kb/references/thumbs/47baed50c7.jpg +0 -0
- package/kb/references/thumbs/47fdcfd7b0.jpg +0 -0
- package/kb/references/thumbs/48fd5e94c5.jpg +0 -0
- package/kb/references/thumbs/493807917b.jpg +0 -0
- package/kb/references/thumbs/49a1c67293.jpg +0 -0
- package/kb/references/thumbs/49e2d7fafe.jpg +0 -0
- package/kb/references/thumbs/49f540fcb6.jpg +0 -0
- package/kb/references/thumbs/4a67ec4028.jpg +0 -0
- package/kb/references/thumbs/4a93275b04.jpg +0 -0
- package/kb/references/thumbs/4aae6f52da.jpg +0 -0
- package/kb/references/thumbs/4b1bae66bd.jpg +0 -0
- package/kb/references/thumbs/4b75da15a9.jpg +0 -0
- package/kb/references/thumbs/4b77789b88.jpg +0 -0
- package/kb/references/thumbs/4bc2f3f3a4.jpg +0 -0
- package/kb/references/thumbs/4c48f27b88.jpg +0 -0
- package/kb/references/thumbs/4c52bd8bfb.jpg +0 -0
- package/kb/references/thumbs/4c9b4acc60.jpg +0 -0
- package/kb/references/thumbs/4cbf0752d4.jpg +0 -0
- package/kb/references/thumbs/4cd2672517.jpg +0 -0
- package/kb/references/thumbs/4dd22a8181.jpg +0 -0
- package/kb/references/thumbs/4ee3447314.jpg +0 -0
- package/kb/references/thumbs/4ef29c8144.jpg +0 -0
- package/kb/references/thumbs/4f82fadfd6.jpg +0 -0
- package/kb/references/thumbs/4fc9b643d8.jpg +0 -0
- package/kb/references/thumbs/50549524b0.jpg +0 -0
- package/kb/references/thumbs/509a615883.jpg +0 -0
- package/kb/references/thumbs/50c03ef855.jpg +0 -0
- package/kb/references/thumbs/50cf9acad6.jpg +0 -0
- package/kb/references/thumbs/51131b025c.jpg +0 -0
- package/kb/references/thumbs/51da1124f0.jpg +0 -0
- package/kb/references/thumbs/524d5e7288.jpg +0 -0
- package/kb/references/thumbs/5251247c81.jpg +0 -0
- package/kb/references/thumbs/526b91b7ec.jpg +0 -0
- package/kb/references/thumbs/52f02f6c2e.jpg +0 -0
- package/kb/references/thumbs/530ab530dc.jpg +0 -0
- package/kb/references/thumbs/5335ee4404.jpg +0 -0
- package/kb/references/thumbs/5385b90939.jpg +0 -0
- package/kb/references/thumbs/53c54654cc.jpg +0 -0
- package/kb/references/thumbs/5420794c6c.jpg +0 -0
- package/kb/references/thumbs/542a9dce8b.jpg +0 -0
- package/kb/references/thumbs/5571530a5f.jpg +0 -0
- package/kb/references/thumbs/56cc68d804.jpg +0 -0
- package/kb/references/thumbs/577b7f7c44.jpg +0 -0
- package/kb/references/thumbs/57adf8f1bb.jpg +0 -0
- package/kb/references/thumbs/57c5f5e3a6.jpg +0 -0
- package/kb/references/thumbs/57ffe4e839.jpg +0 -0
- package/kb/references/thumbs/5817dfc7d6.jpg +0 -0
- package/kb/references/thumbs/581a182a7a.jpg +0 -0
- package/kb/references/thumbs/58807679c8.jpg +0 -0
- package/kb/references/thumbs/589a1d9111.jpg +0 -0
- package/kb/references/thumbs/59167391ab.jpg +0 -0
- package/kb/references/thumbs/5a70420166.jpg +0 -0
- package/kb/references/thumbs/5b10df1b8d.jpg +0 -0
- package/kb/references/thumbs/5b7a712fdb.jpg +0 -0
- package/kb/references/thumbs/5bc46b92ad.jpg +0 -0
- package/kb/references/thumbs/5c0546a120.jpg +0 -0
- package/kb/references/thumbs/5c2b6125a8.jpg +0 -0
- package/kb/references/thumbs/5c536b9e42.jpg +0 -0
- package/kb/references/thumbs/5c8e441d30.jpg +0 -0
- package/kb/references/thumbs/5cb6f1baa5.jpg +0 -0
- package/kb/references/thumbs/5ce6c1f21e.jpg +0 -0
- package/kb/references/thumbs/5cef052c0a.jpg +0 -0
- package/kb/references/thumbs/5d08438209.jpg +0 -0
- package/kb/references/thumbs/5d0f9af9b0.jpg +0 -0
- package/kb/references/thumbs/5d300ed332.jpg +0 -0
- package/kb/references/thumbs/5d708a4794.jpg +0 -0
- package/kb/references/thumbs/5de8826a98.jpg +0 -0
- package/kb/references/thumbs/5df7bff22c.jpg +0 -0
- package/kb/references/thumbs/5e087d0f00.jpg +0 -0
- package/kb/references/thumbs/5e44e70ca0.jpg +0 -0
- package/kb/references/thumbs/5eff5d80ce.jpg +0 -0
- package/kb/references/thumbs/5f015c96b1.jpg +0 -0
- package/kb/references/thumbs/5f3289b7c4.jpg +0 -0
- package/kb/references/thumbs/5f830c40eb.jpg +0 -0
- package/kb/references/thumbs/60c4c3527b.jpg +0 -0
- package/kb/references/thumbs/60e9e594dd.jpg +0 -0
- package/kb/references/thumbs/615421d7be.jpg +0 -0
- package/kb/references/thumbs/6176e4004f.jpg +0 -0
- package/kb/references/thumbs/61f0fe5e06.jpg +0 -0
- package/kb/references/thumbs/6213785db4.jpg +0 -0
- package/kb/references/thumbs/62a670ae09.jpg +0 -0
- package/kb/references/thumbs/63cc12981b.jpg +0 -0
- package/kb/references/thumbs/641f15cc71.jpg +0 -0
- package/kb/references/thumbs/642ab2081d.jpg +0 -0
- package/kb/references/thumbs/644a59bf6e.jpg +0 -0
- package/kb/references/thumbs/644da8a8e3.jpg +0 -0
- package/kb/references/thumbs/6458986897.jpg +0 -0
- package/kb/references/thumbs/64cfbd7b93.jpg +0 -0
- package/kb/references/thumbs/661a57686a.jpg +0 -0
- package/kb/references/thumbs/66355a813a.jpg +0 -0
- package/kb/references/thumbs/664396dd44.jpg +0 -0
- package/kb/references/thumbs/66d832d65f.jpg +0 -0
- package/kb/references/thumbs/66de9e9833.jpg +0 -0
- package/kb/references/thumbs/6750964fd9.jpg +0 -0
- package/kb/references/thumbs/67c7164832.jpg +0 -0
- package/kb/references/thumbs/681600b6cd.jpg +0 -0
- package/kb/references/thumbs/682e75afe4.jpg +0 -0
- package/kb/references/thumbs/69274bc952.jpg +0 -0
- package/kb/references/thumbs/696ec08c52.jpg +0 -0
- package/kb/references/thumbs/69760111cc.jpg +0 -0
- package/kb/references/thumbs/697e32664f.jpg +0 -0
- package/kb/references/thumbs/69df92544b.jpg +0 -0
- package/kb/references/thumbs/69e48c5229.jpg +0 -0
- package/kb/references/thumbs/6a5fb75de1.jpg +0 -0
- package/kb/references/thumbs/6a7389e472.jpg +0 -0
- package/kb/references/thumbs/6a9b041e02.jpg +0 -0
- package/kb/references/thumbs/6ab2fa93ee.jpg +0 -0
- package/kb/references/thumbs/6ae3400319.jpg +0 -0
- package/kb/references/thumbs/6b21344bf3.jpg +0 -0
- package/kb/references/thumbs/6bd1b67a8a.jpg +0 -0
- package/kb/references/thumbs/6c99156c4f.jpg +0 -0
- package/kb/references/thumbs/6cc9b65384.jpg +0 -0
- package/kb/references/thumbs/6d15830a73.jpg +0 -0
- package/kb/references/thumbs/6d4c33d180.jpg +0 -0
- package/kb/references/thumbs/6e36815799.jpg +0 -0
- package/kb/references/thumbs/6eddb9cbfc.jpg +0 -0
- package/kb/references/thumbs/6f97968a7c.jpg +0 -0
- package/kb/references/thumbs/6fa0716a7d.jpg +0 -0
- package/kb/references/thumbs/6facd57184.jpg +0 -0
- package/kb/references/thumbs/6fd57b785a.jpg +0 -0
- package/kb/references/thumbs/700b3cb185.jpg +0 -0
- package/kb/references/thumbs/71197443fa.jpg +0 -0
- package/kb/references/thumbs/72082bc9ee.jpg +0 -0
- package/kb/references/thumbs/72453db479.jpg +0 -0
- package/kb/references/thumbs/72cd64d500.jpg +0 -0
- package/kb/references/thumbs/72d1e75283.jpg +0 -0
- package/kb/references/thumbs/72e13f7f5b.jpg +0 -0
- package/kb/references/thumbs/7459f8e644.jpg +0 -0
- package/kb/references/thumbs/7470d55c79.jpg +0 -0
- package/kb/references/thumbs/74c468f02a.jpg +0 -0
- package/kb/references/thumbs/74fed6eb77.jpg +0 -0
- package/kb/references/thumbs/756e05080d.jpg +0 -0
- package/kb/references/thumbs/75df7e5f49.jpg +0 -0
- package/kb/references/thumbs/76226da6ef.jpg +0 -0
- package/kb/references/thumbs/76a34aa056.jpg +0 -0
- package/kb/references/thumbs/76c7076589.jpg +0 -0
- package/kb/references/thumbs/76cccc396c.jpg +0 -0
- package/kb/references/thumbs/774654789f.jpg +0 -0
- package/kb/references/thumbs/7746cc494d.jpg +0 -0
- package/kb/references/thumbs/7766e36aa3.jpg +0 -0
- package/kb/references/thumbs/78049331ef.jpg +0 -0
- package/kb/references/thumbs/78808a0ca5.jpg +0 -0
- package/kb/references/thumbs/7890b0a310.jpg +0 -0
- package/kb/references/thumbs/78911975e6.jpg +0 -0
- package/kb/references/thumbs/78d289d5a0.jpg +0 -0
- package/kb/references/thumbs/794126267e.jpg +0 -0
- package/kb/references/thumbs/7976eb9025.jpg +0 -0
- package/kb/references/thumbs/798519ec7c.jpg +0 -0
- package/kb/references/thumbs/7a6cc5eecc.jpg +0 -0
- package/kb/references/thumbs/7ac8a7cd4a.jpg +0 -0
- package/kb/references/thumbs/7b1341d61d.jpg +0 -0
- package/kb/references/thumbs/7b9c4031e3.jpg +0 -0
- package/kb/references/thumbs/7ba5ad3779.jpg +0 -0
- package/kb/references/thumbs/7be6eb2bd0.jpg +0 -0
- package/kb/references/thumbs/7c30864f5d.jpg +0 -0
- package/kb/references/thumbs/7c379b5e17.jpg +0 -0
- package/kb/references/thumbs/7c4050eb02.jpg +0 -0
- package/kb/references/thumbs/7ca47b3221.jpg +0 -0
- package/kb/references/thumbs/7d43516bd7.jpg +0 -0
- package/kb/references/thumbs/7da9dbb98a.jpg +0 -0
- package/kb/references/thumbs/7ddda8f57c.jpg +0 -0
- package/kb/references/thumbs/7ece6d215c.jpg +0 -0
- package/kb/references/thumbs/7eebf029de.jpg +0 -0
- package/kb/references/thumbs/7f45483c15.jpg +0 -0
- package/kb/references/thumbs/7fde06eaa5.jpg +0 -0
- package/kb/references/thumbs/80407b97e9.jpg +0 -0
- package/kb/references/thumbs/80f0a6cf4b.jpg +0 -0
- package/kb/references/thumbs/8118b451b8.jpg +0 -0
- package/kb/references/thumbs/816baed4a8.jpg +0 -0
- package/kb/references/thumbs/817d2d15d9.jpg +0 -0
- package/kb/references/thumbs/8260cb430d.jpg +0 -0
- package/kb/references/thumbs/827b562899.jpg +0 -0
- package/kb/references/thumbs/8293cf1e92.jpg +0 -0
- package/kb/references/thumbs/8294653169.jpg +0 -0
- package/kb/references/thumbs/83061f871f.jpg +0 -0
- package/kb/references/thumbs/833df778ca.jpg +0 -0
- package/kb/references/thumbs/83d3acaafc.jpg +0 -0
- package/kb/references/thumbs/844c6efeff.jpg +0 -0
- package/kb/references/thumbs/84563d482a.jpg +0 -0
- package/kb/references/thumbs/848082dd94.jpg +0 -0
- package/kb/references/thumbs/8494b1da94.jpg +0 -0
- package/kb/references/thumbs/84b71014be.jpg +0 -0
- package/kb/references/thumbs/84be4a5f3c.jpg +0 -0
- package/kb/references/thumbs/84fd0fd25a.jpg +0 -0
- package/kb/references/thumbs/853e488e22.jpg +0 -0
- package/kb/references/thumbs/858c91585d.jpg +0 -0
- package/kb/references/thumbs/85903e8fe9.jpg +0 -0
- package/kb/references/thumbs/86597d43fd.jpg +0 -0
- package/kb/references/thumbs/866eb99500.jpg +0 -0
- package/kb/references/thumbs/86ac050340.jpg +0 -0
- package/kb/references/thumbs/86afec7b64.jpg +0 -0
- package/kb/references/thumbs/87238127f5.jpg +0 -0
- package/kb/references/thumbs/87321df792.jpg +0 -0
- package/kb/references/thumbs/87460f70cd.jpg +0 -0
- package/kb/references/thumbs/8770dfeaec.jpg +0 -0
- package/kb/references/thumbs/8798451a8c.jpg +0 -0
- package/kb/references/thumbs/87da1f34a3.jpg +0 -0
- package/kb/references/thumbs/882cdf8c05.jpg +0 -0
- package/kb/references/thumbs/8839f4106f.jpg +0 -0
- package/kb/references/thumbs/8844455212.jpg +0 -0
- package/kb/references/thumbs/88abba0497.jpg +0 -0
- package/kb/references/thumbs/88b372435d.jpg +0 -0
- package/kb/references/thumbs/88bd4f35fa.jpg +0 -0
- package/kb/references/thumbs/88c71a075e.jpg +0 -0
- package/kb/references/thumbs/892e5f048e.jpg +0 -0
- package/kb/references/thumbs/893cc8e920.jpg +0 -0
- package/kb/references/thumbs/896c198814.jpg +0 -0
- package/kb/references/thumbs/8a8e22f756.jpg +0 -0
- package/kb/references/thumbs/8a9d8a35cb.jpg +0 -0
- package/kb/references/thumbs/8ab1d67fec.jpg +0 -0
- package/kb/references/thumbs/8ab201fe12.jpg +0 -0
- package/kb/references/thumbs/8ac372c102.jpg +0 -0
- package/kb/references/thumbs/8b15736d62.jpg +0 -0
- package/kb/references/thumbs/8b1d8d6a05.jpg +0 -0
- package/kb/references/thumbs/8bb6050e20.jpg +0 -0
- package/kb/references/thumbs/8c6c9d1577.jpg +0 -0
- package/kb/references/thumbs/8d337851e0.jpg +0 -0
- package/kb/references/thumbs/8d44b33cc5.jpg +0 -0
- package/kb/references/thumbs/8d4536ff3b.jpg +0 -0
- package/kb/references/thumbs/8d9b99454a.jpg +0 -0
- package/kb/references/thumbs/8dda2303ff.jpg +0 -0
- package/kb/references/thumbs/8dec722d62.jpg +0 -0
- package/kb/references/thumbs/8e0ea4ca74.jpg +0 -0
- package/kb/references/thumbs/8ebba84d69.jpg +0 -0
- package/kb/references/thumbs/8ef09140c0.jpg +0 -0
- package/kb/references/thumbs/8f2928a1b0.jpg +0 -0
- package/kb/references/thumbs/8f88f9ddba.jpg +0 -0
- package/kb/references/thumbs/8fa4451009.jpg +0 -0
- package/kb/references/thumbs/90109b0e02.jpg +0 -0
- package/kb/references/thumbs/90e854e5c9.jpg +0 -0
- package/kb/references/thumbs/914e79f893.jpg +0 -0
- package/kb/references/thumbs/9161369197.jpg +0 -0
- package/kb/references/thumbs/9165c87d6f.jpg +0 -0
- package/kb/references/thumbs/9193f6558a.jpg +0 -0
- package/kb/references/thumbs/91ac7df877.jpg +0 -0
- package/kb/references/thumbs/9216bd4931.jpg +0 -0
- package/kb/references/thumbs/922ae8a26a.jpg +0 -0
- package/kb/references/thumbs/92a70e6867.jpg +0 -0
- package/kb/references/thumbs/92c77ece22.jpg +0 -0
- package/kb/references/thumbs/92e5914fbf.jpg +0 -0
- package/kb/references/thumbs/92ee36419a.jpg +0 -0
- package/kb/references/thumbs/94153a60b0.jpg +0 -0
- package/kb/references/thumbs/9449666640.jpg +0 -0
- package/kb/references/thumbs/944be6a646.jpg +0 -0
- package/kb/references/thumbs/945831476e.jpg +0 -0
- package/kb/references/thumbs/94c1af82f4.jpg +0 -0
- package/kb/references/thumbs/9599d6d589.jpg +0 -0
- package/kb/references/thumbs/960710f4cf.jpg +0 -0
- package/kb/references/thumbs/9608f12d64.jpg +0 -0
- package/kb/references/thumbs/962dabfaa0.jpg +0 -0
- package/kb/references/thumbs/965a3a95c6.jpg +0 -0
- package/kb/references/thumbs/9672ed5ae4.jpg +0 -0
- package/kb/references/thumbs/96891ae9c1.jpg +0 -0
- package/kb/references/thumbs/96e1907c99.jpg +0 -0
- package/kb/references/thumbs/96f25b6578.jpg +0 -0
- package/kb/references/thumbs/97211df9ae.jpg +0 -0
- package/kb/references/thumbs/9769d763a5.jpg +0 -0
- package/kb/references/thumbs/9792bd6d05.jpg +0 -0
- package/kb/references/thumbs/97d2837e3e.jpg +0 -0
- package/kb/references/thumbs/97d90d1d85.jpg +0 -0
- package/kb/references/thumbs/97fcd5774a.jpg +0 -0
- package/kb/references/thumbs/980f68564e.jpg +0 -0
- package/kb/references/thumbs/98511fb393.jpg +0 -0
- package/kb/references/thumbs/98f8fa694d.jpg +0 -0
- package/kb/references/thumbs/9a42c6bb97.jpg +0 -0
- package/kb/references/thumbs/9ab3600a06.jpg +0 -0
- package/kb/references/thumbs/9ab48d9130.jpg +0 -0
- package/kb/references/thumbs/9ad519197d.jpg +0 -0
- package/kb/references/thumbs/9b1382c657.jpg +0 -0
- package/kb/references/thumbs/9b6cc1e077.jpg +0 -0
- package/kb/references/thumbs/9beede8480.jpg +0 -0
- package/kb/references/thumbs/9bf8976952.jpg +0 -0
- package/kb/references/thumbs/9cace7b75a.jpg +0 -0
- package/kb/references/thumbs/9cdcc5745e.jpg +0 -0
- package/kb/references/thumbs/9d0b269074.jpg +0 -0
- package/kb/references/thumbs/9d41788b48.jpg +0 -0
- package/kb/references/thumbs/9d475bd6af.jpg +0 -0
- package/kb/references/thumbs/9e6bc543d0.jpg +0 -0
- package/kb/references/thumbs/9ed0e0a206.jpg +0 -0
- package/kb/references/thumbs/9ef538de13.jpg +0 -0
- package/kb/references/thumbs/9efc373ab4.jpg +0 -0
- package/kb/references/thumbs/9f4a939fa5.jpg +0 -0
- package/kb/references/thumbs/9f8d12d7b9.jpg +0 -0
- package/kb/references/thumbs/9fd5e3efa7.jpg +0 -0
- package/kb/references/thumbs/a0a9b9c572.jpg +0 -0
- package/kb/references/thumbs/a29ca9b185.jpg +0 -0
- package/kb/references/thumbs/a2a42884af.jpg +0 -0
- package/kb/references/thumbs/a2f5064e34.jpg +0 -0
- package/kb/references/thumbs/a3112ce672.jpg +0 -0
- package/kb/references/thumbs/a3437736d1.jpg +0 -0
- package/kb/references/thumbs/a372667e76.jpg +0 -0
- package/kb/references/thumbs/a39bae94e9.jpg +0 -0
- package/kb/references/thumbs/a3fc75d94c.jpg +0 -0
- package/kb/references/thumbs/a440487631.jpg +0 -0
- package/kb/references/thumbs/a4993d5fb5.jpg +0 -0
- package/kb/references/thumbs/a500476a86.jpg +0 -0
- package/kb/references/thumbs/a55506bf46.jpg +0 -0
- package/kb/references/thumbs/a59a5f9843.jpg +0 -0
- package/kb/references/thumbs/a5bce0eede.jpg +0 -0
- package/kb/references/thumbs/a5d921e1f0.jpg +0 -0
- package/kb/references/thumbs/a5e19d4637.jpg +0 -0
- package/kb/references/thumbs/a5f92b97d5.jpg +0 -0
- package/kb/references/thumbs/a6562c210a.jpg +0 -0
- package/kb/references/thumbs/a6f61a8d09.jpg +0 -0
- package/kb/references/thumbs/a719fdf663.jpg +0 -0
- package/kb/references/thumbs/a724e5442f.jpg +0 -0
- package/kb/references/thumbs/a852b4319f.jpg +0 -0
- package/kb/references/thumbs/a896c08448.jpg +0 -0
- package/kb/references/thumbs/a8d190a4b8.jpg +0 -0
- package/kb/references/thumbs/a8dcdd57d7.jpg +0 -0
- package/kb/references/thumbs/a951347e18.jpg +0 -0
- package/kb/references/thumbs/a9a1a0bf7d.jpg +0 -0
- package/kb/references/thumbs/a9b72986a8.jpg +0 -0
- package/kb/references/thumbs/aa11555ba8.jpg +0 -0
- package/kb/references/thumbs/aa4aab9093.jpg +0 -0
- package/kb/references/thumbs/aa89b96658.jpg +0 -0
- package/kb/references/thumbs/aaeb3739b6.jpg +0 -0
- package/kb/references/thumbs/ab25a608ec.jpg +0 -0
- package/kb/references/thumbs/ab34b62268.jpg +0 -0
- package/kb/references/thumbs/ab3b0217bb.jpg +0 -0
- package/kb/references/thumbs/ac70c04afb.jpg +0 -0
- package/kb/references/thumbs/ace0879117.jpg +0 -0
- package/kb/references/thumbs/ad0515ae55.jpg +0 -0
- package/kb/references/thumbs/ad66b25b47.jpg +0 -0
- package/kb/references/thumbs/ad68229d2f.jpg +0 -0
- package/kb/references/thumbs/add6480693.jpg +0 -0
- package/kb/references/thumbs/ae5b8c3b8c.jpg +0 -0
- package/kb/references/thumbs/ae81247b47.jpg +0 -0
- package/kb/references/thumbs/af8aa54379.jpg +0 -0
- package/kb/references/thumbs/afa80dedd4.jpg +0 -0
- package/kb/references/thumbs/afe04d730f.jpg +0 -0
- package/kb/references/thumbs/b09a7dc315.jpg +0 -0
- package/kb/references/thumbs/b0c02629f6.jpg +0 -0
- package/kb/references/thumbs/b1cb4f91de.jpg +0 -0
- package/kb/references/thumbs/b1d4c13c92.jpg +0 -0
- package/kb/references/thumbs/b20eef86db.jpg +0 -0
- package/kb/references/thumbs/b3136ccdde.jpg +0 -0
- package/kb/references/thumbs/b3f5e8d7dd.jpg +0 -0
- package/kb/references/thumbs/b44adb81c9.jpg +0 -0
- package/kb/references/thumbs/b457a5894b.jpg +0 -0
- package/kb/references/thumbs/b461281e0f.jpg +0 -0
- package/kb/references/thumbs/b4942644f0.jpg +0 -0
- package/kb/references/thumbs/b49f8eccad.jpg +0 -0
- package/kb/references/thumbs/b56c69be23.jpg +0 -0
- package/kb/references/thumbs/b59786b33c.jpg +0 -0
- package/kb/references/thumbs/b5d368ce5a.jpg +0 -0
- package/kb/references/thumbs/b5eb442406.jpg +0 -0
- package/kb/references/thumbs/b7fdabf4ab.jpg +0 -0
- package/kb/references/thumbs/b88ee8d235.jpg +0 -0
- package/kb/references/thumbs/b8a4e5be8a.jpg +0 -0
- package/kb/references/thumbs/b8c85b661c.jpg +0 -0
- package/kb/references/thumbs/ba1b8e7435.jpg +0 -0
- package/kb/references/thumbs/ba9a593eed.jpg +0 -0
- package/kb/references/thumbs/baa7afc201.jpg +0 -0
- package/kb/references/thumbs/baf74398f7.jpg +0 -0
- package/kb/references/thumbs/bb3e947c10.jpg +0 -0
- package/kb/references/thumbs/bb4c1bb7c1.jpg +0 -0
- package/kb/references/thumbs/bbaa25cc8a.jpg +0 -0
- package/kb/references/thumbs/bc7e7f88cc.jpg +0 -0
- package/kb/references/thumbs/bc9d5b58f5.jpg +0 -0
- package/kb/references/thumbs/bcc99a51f7.jpg +0 -0
- package/kb/references/thumbs/bce13dd1c1.jpg +0 -0
- package/kb/references/thumbs/bd079a6130.jpg +0 -0
- package/kb/references/thumbs/bd2d70dda7.jpg +0 -0
- package/kb/references/thumbs/bd5895c5f2.jpg +0 -0
- package/kb/references/thumbs/bde8e31d62.jpg +0 -0
- package/kb/references/thumbs/be084e78f3.jpg +0 -0
- package/kb/references/thumbs/be94f170c8.jpg +0 -0
- package/kb/references/thumbs/bed33654f7.jpg +0 -0
- package/kb/references/thumbs/beeb9a0c18.jpg +0 -0
- package/kb/references/thumbs/bef42094dc.jpg +0 -0
- package/kb/references/thumbs/bf625496fa.jpg +0 -0
- package/kb/references/thumbs/bf771f1398.jpg +0 -0
- package/kb/references/thumbs/c0ddefa3d9.jpg +0 -0
- package/kb/references/thumbs/c0f01e536e.jpg +0 -0
- package/kb/references/thumbs/c1d592b678.jpg +0 -0
- package/kb/references/thumbs/c1e83e1b3e.jpg +0 -0
- package/kb/references/thumbs/c2168f8096.jpg +0 -0
- package/kb/references/thumbs/c249cd6b17.jpg +0 -0
- package/kb/references/thumbs/c2e3d4feed.jpg +0 -0
- package/kb/references/thumbs/c3cec01df1.jpg +0 -0
- package/kb/references/thumbs/c47bedb42d.jpg +0 -0
- package/kb/references/thumbs/c4b03b4680.jpg +0 -0
- package/kb/references/thumbs/c4e6d18ec3.jpg +0 -0
- package/kb/references/thumbs/c5477e2877.jpg +0 -0
- package/kb/references/thumbs/c566794674.jpg +0 -0
- package/kb/references/thumbs/c5b945afbb.jpg +0 -0
- package/kb/references/thumbs/c5e4659497.jpg +0 -0
- package/kb/references/thumbs/c622786702.jpg +0 -0
- package/kb/references/thumbs/c6250649ca.jpg +0 -0
- package/kb/references/thumbs/c6261a9526.jpg +0 -0
- package/kb/references/thumbs/c62e609076.jpg +0 -0
- package/kb/references/thumbs/c6602d3e85.jpg +0 -0
- package/kb/references/thumbs/c6c1a16e40.jpg +0 -0
- package/kb/references/thumbs/c77f932157.jpg +0 -0
- package/kb/references/thumbs/c79788f01e.jpg +0 -0
- package/kb/references/thumbs/c7a511ad1e.jpg +0 -0
- package/kb/references/thumbs/c7acfbc3c8.jpg +0 -0
- package/kb/references/thumbs/c7bb6d1bb8.jpg +0 -0
- package/kb/references/thumbs/c829eadcb9.jpg +0 -0
- package/kb/references/thumbs/c891fd9d85.jpg +0 -0
- package/kb/references/thumbs/c89f812ee3.jpg +0 -0
- package/kb/references/thumbs/c8a85b9f61.jpg +0 -0
- package/kb/references/thumbs/c8fdf85c9a.jpg +0 -0
- package/kb/references/thumbs/c961ac1031.jpg +0 -0
- package/kb/references/thumbs/c9fd3f88d8.jpg +0 -0
- package/kb/references/thumbs/ca0d6399c3.jpg +0 -0
- package/kb/references/thumbs/ca316c83e4.jpg +0 -0
- package/kb/references/thumbs/ca3b93aa0d.jpg +0 -0
- package/kb/references/thumbs/cb0596a85b.jpg +0 -0
- package/kb/references/thumbs/cb95a5c3ef.jpg +0 -0
- package/kb/references/thumbs/cbe238b656.jpg +0 -0
- package/kb/references/thumbs/cbf530e608.jpg +0 -0
- package/kb/references/thumbs/cc173494ec.jpg +0 -0
- package/kb/references/thumbs/ccb664bddf.jpg +0 -0
- package/kb/references/thumbs/ccf69d36cd.jpg +0 -0
- package/kb/references/thumbs/ccf759db42.jpg +0 -0
- package/kb/references/thumbs/cd2a285807.jpg +0 -0
- package/kb/references/thumbs/cd4a24a8ca.jpg +0 -0
- package/kb/references/thumbs/cdb3fe8938.jpg +0 -0
- package/kb/references/thumbs/cdce1b9bc6.jpg +0 -0
- package/kb/references/thumbs/cde3aa761a.jpg +0 -0
- package/kb/references/thumbs/ce9d5cd9c2.jpg +0 -0
- package/kb/references/thumbs/ceb01f8a34.jpg +0 -0
- package/kb/references/thumbs/cee15c98d0.jpg +0 -0
- package/kb/references/thumbs/cf6944ddae.jpg +0 -0
- package/kb/references/thumbs/d15dd21cd8.jpg +0 -0
- package/kb/references/thumbs/d1633bf2ed.jpg +0 -0
- package/kb/references/thumbs/d16a838000.jpg +0 -0
- package/kb/references/thumbs/d1cf87e9f0.jpg +0 -0
- package/kb/references/thumbs/d32511d913.jpg +0 -0
- package/kb/references/thumbs/d327e9dedd.jpg +0 -0
- package/kb/references/thumbs/d35bf6c85e.jpg +0 -0
- package/kb/references/thumbs/d37afc9d61.jpg +0 -0
- package/kb/references/thumbs/d3b66655c7.jpg +0 -0
- package/kb/references/thumbs/d40b4172b6.jpg +0 -0
- package/kb/references/thumbs/d4c40d1824.jpg +0 -0
- package/kb/references/thumbs/d4cb55a4b6.jpg +0 -0
- package/kb/references/thumbs/d4f0c30f7e.jpg +0 -0
- package/kb/references/thumbs/d51cce3ae5.jpg +0 -0
- package/kb/references/thumbs/d52948f9ba.jpg +0 -0
- package/kb/references/thumbs/d62bd3cba4.jpg +0 -0
- package/kb/references/thumbs/d668a21c92.jpg +0 -0
- package/kb/references/thumbs/d685072c52.jpg +0 -0
- package/kb/references/thumbs/d6d7b96093.jpg +0 -0
- package/kb/references/thumbs/d7cd874b21.jpg +0 -0
- package/kb/references/thumbs/d7e111736a.jpg +0 -0
- package/kb/references/thumbs/d88325f832.jpg +0 -0
- package/kb/references/thumbs/d9272ded76.jpg +0 -0
- package/kb/references/thumbs/d962e7c654.jpg +0 -0
- package/kb/references/thumbs/d97f000ee2.jpg +0 -0
- package/kb/references/thumbs/d9c1ae2543.jpg +0 -0
- package/kb/references/thumbs/d9ccb3cac8.jpg +0 -0
- package/kb/references/thumbs/da99019680.jpg +0 -0
- package/kb/references/thumbs/da9b8bc615.jpg +0 -0
- package/kb/references/thumbs/daafbee2c1.jpg +0 -0
- package/kb/references/thumbs/db0f11f143.jpg +0 -0
- package/kb/references/thumbs/db5dd367f5.jpg +0 -0
- package/kb/references/thumbs/db69677866.jpg +0 -0
- package/kb/references/thumbs/db87c1956e.jpg +0 -0
- package/kb/references/thumbs/dbb86d8bda.jpg +0 -0
- package/kb/references/thumbs/dbd3a8ff2a.jpg +0 -0
- package/kb/references/thumbs/dbdf4b2794.jpg +0 -0
- package/kb/references/thumbs/dd4c19b4b1.jpg +0 -0
- package/kb/references/thumbs/dd98d9f6fa.jpg +0 -0
- package/kb/references/thumbs/ddb00e3b6a.jpg +0 -0
- package/kb/references/thumbs/dde3541a5c.jpg +0 -0
- package/kb/references/thumbs/de2a4da502.jpg +0 -0
- package/kb/references/thumbs/de4c387a66.jpg +0 -0
- package/kb/references/thumbs/de5618fa82.jpg +0 -0
- package/kb/references/thumbs/de6bec2538.jpg +0 -0
- package/kb/references/thumbs/dea13cbb1f.jpg +0 -0
- package/kb/references/thumbs/deff9202aa.jpg +0 -0
- package/kb/references/thumbs/df12835f8d.jpg +0 -0
- package/kb/references/thumbs/df57acbb3d.jpg +0 -0
- package/kb/references/thumbs/df8265009e.jpg +0 -0
- package/kb/references/thumbs/dfc99a1e8e.jpg +0 -0
- package/kb/references/thumbs/dfc9fde460.jpg +0 -0
- package/kb/references/thumbs/e038348eee.jpg +0 -0
- package/kb/references/thumbs/e04c2ae1d5.jpg +0 -0
- package/kb/references/thumbs/e070345c43.jpg +0 -0
- package/kb/references/thumbs/e0a0c84d47.jpg +0 -0
- package/kb/references/thumbs/e0af1e6b9e.jpg +0 -0
- package/kb/references/thumbs/e1025942c4.jpg +0 -0
- package/kb/references/thumbs/e11b6f5b82.jpg +0 -0
- package/kb/references/thumbs/e1553de3fc.jpg +0 -0
- package/kb/references/thumbs/e162ebe7cd.jpg +0 -0
- package/kb/references/thumbs/e1f1e531d8.jpg +0 -0
- package/kb/references/thumbs/e20842e5c9.jpg +0 -0
- package/kb/references/thumbs/e24e7d949b.jpg +0 -0
- package/kb/references/thumbs/e2a3e5d10a.jpg +0 -0
- package/kb/references/thumbs/e2de02615a.jpg +0 -0
- package/kb/references/thumbs/e305dad7dd.jpg +0 -0
- package/kb/references/thumbs/e52e3ef97f.jpg +0 -0
- package/kb/references/thumbs/e570e92d06.jpg +0 -0
- package/kb/references/thumbs/e583932fb9.jpg +0 -0
- package/kb/references/thumbs/e5da3c038f.jpg +0 -0
- package/kb/references/thumbs/e657634af3.jpg +0 -0
- package/kb/references/thumbs/e67946e3e1.jpg +0 -0
- package/kb/references/thumbs/e69e0f3639.jpg +0 -0
- package/kb/references/thumbs/e6ebe66031.jpg +0 -0
- package/kb/references/thumbs/e7db9563c9.jpg +0 -0
- package/kb/references/thumbs/e84a4c3b7b.jpg +0 -0
- package/kb/references/thumbs/e84cf52c27.jpg +0 -0
- package/kb/references/thumbs/e8707cf6e8.jpg +0 -0
- package/kb/references/thumbs/e888890b40.jpg +0 -0
- package/kb/references/thumbs/e8a502b418.jpg +0 -0
- package/kb/references/thumbs/e8ba68371d.jpg +0 -0
- package/kb/references/thumbs/e9098f54cc.jpg +0 -0
- package/kb/references/thumbs/e9144deae9.jpg +0 -0
- package/kb/references/thumbs/e93e98d757.jpg +0 -0
- package/kb/references/thumbs/e9762dd435.jpg +0 -0
- package/kb/references/thumbs/e9db4544c8.jpg +0 -0
- package/kb/references/thumbs/e9ddffeacd.jpg +0 -0
- package/kb/references/thumbs/e9e2cf1d7e.jpg +0 -0
- package/kb/references/thumbs/ea1e23e623.jpg +0 -0
- package/kb/references/thumbs/ea41200f5e.jpg +0 -0
- package/kb/references/thumbs/eaf4916e1a.jpg +0 -0
- package/kb/references/thumbs/eb2c505fc8.jpg +0 -0
- package/kb/references/thumbs/eb47943693.jpg +0 -0
- package/kb/references/thumbs/eb4ffd6625.jpg +0 -0
- package/kb/references/thumbs/eb82ac0a4d.jpg +0 -0
- package/kb/references/thumbs/ebeb345ade.jpg +0 -0
- package/kb/references/thumbs/ec4e2aba0a.jpg +0 -0
- package/kb/references/thumbs/ed683bc9f7.jpg +0 -0
- package/kb/references/thumbs/ed9e236a84.jpg +0 -0
- package/kb/references/thumbs/ee45e1caea.jpg +0 -0
- package/kb/references/thumbs/ee50bbf2e7.jpg +0 -0
- package/kb/references/thumbs/eed6ad3b7b.jpg +0 -0
- package/kb/references/thumbs/eee247fd70.jpg +0 -0
- package/kb/references/thumbs/ef87b6cb99.jpg +0 -0
- package/kb/references/thumbs/ef87dccf04.jpg +0 -0
- package/kb/references/thumbs/ef941bba1e.jpg +0 -0
- package/kb/references/thumbs/effc14fb2c.jpg +0 -0
- package/kb/references/thumbs/f04aa5a191.jpg +0 -0
- package/kb/references/thumbs/f13f12485f.jpg +0 -0
- package/kb/references/thumbs/f16a5c0fd4.jpg +0 -0
- package/kb/references/thumbs/f1ba7a7a8f.jpg +0 -0
- package/kb/references/thumbs/f1bc4c9c19.jpg +0 -0
- package/kb/references/thumbs/f1ee827878.jpg +0 -0
- package/kb/references/thumbs/f21736aeff.jpg +0 -0
- package/kb/references/thumbs/f22bc41213.jpg +0 -0
- package/kb/references/thumbs/f266aaffcc.jpg +0 -0
- package/kb/references/thumbs/f2c0ed0d65.jpg +0 -0
- package/kb/references/thumbs/f32ac710fd.jpg +0 -0
- package/kb/references/thumbs/f32b697ff6.jpg +0 -0
- package/kb/references/thumbs/f39c883904.jpg +0 -0
- package/kb/references/thumbs/f3b9d55e6e.jpg +0 -0
- package/kb/references/thumbs/f3c1763e14.jpg +0 -0
- package/kb/references/thumbs/f40853fd43.jpg +0 -0
- package/kb/references/thumbs/f4fd07dc4d.jpg +0 -0
- package/kb/references/thumbs/f50b756ee5.jpg +0 -0
- package/kb/references/thumbs/f51272e9b3.jpg +0 -0
- package/kb/references/thumbs/f538895eee.jpg +0 -0
- package/kb/references/thumbs/f5d28081b5.jpg +0 -0
- package/kb/references/thumbs/f6046c9501.jpg +0 -0
- package/kb/references/thumbs/f62e4af316.jpg +0 -0
- package/kb/references/thumbs/f6f6bffeb8.jpg +0 -0
- package/kb/references/thumbs/f736e00af6.jpg +0 -0
- package/kb/references/thumbs/f7932da47d.jpg +0 -0
- package/kb/references/thumbs/f879e118ca.jpg +0 -0
- package/kb/references/thumbs/f88257215d.jpg +0 -0
- package/kb/references/thumbs/f88c45a6d7.jpg +0 -0
- package/kb/references/thumbs/f89a7b646e.jpg +0 -0
- package/kb/references/thumbs/f8a1e7a274.jpg +0 -0
- package/kb/references/thumbs/f9183cf2b6.jpg +0 -0
- package/kb/references/thumbs/f995de5ce9.jpg +0 -0
- package/kb/references/thumbs/f9ada2c3e1.jpg +0 -0
- package/kb/references/thumbs/f9d4616f89.jpg +0 -0
- package/kb/references/thumbs/f9f4307bb0.jpg +0 -0
- package/kb/references/thumbs/fa070122c7.jpg +0 -0
- package/kb/references/thumbs/fa29cc1369.jpg +0 -0
- package/kb/references/thumbs/fa791a4dab.jpg +0 -0
- package/kb/references/thumbs/fa8060509e.jpg +0 -0
- package/kb/references/thumbs/fafeed4003.jpg +0 -0
- package/kb/references/thumbs/fb1c024f38.jpg +0 -0
- package/kb/references/thumbs/fb77aa28b3.jpg +0 -0
- package/kb/references/thumbs/fb9f7f1966.jpg +0 -0
- package/kb/references/thumbs/fba8a8c2da.jpg +0 -0
- package/kb/references/thumbs/fce2754c36.jpg +0 -0
- package/kb/references/thumbs/fce2fb83df.jpg +0 -0
- package/kb/references/thumbs/fd4c51bb47.jpg +0 -0
- package/kb/references/thumbs/fd8c269817.jpg +0 -0
- package/kb/references/thumbs/fdb7b250ca.jpg +0 -0
- package/kb/references/thumbs/fe18088de8.jpg +0 -0
- package/kb/references/thumbs/fe4f742ba7.jpg +0 -0
- package/kb/references/thumbs/fe64742ce7.jpg +0 -0
- package/kb/references/thumbs/feb5d62161.jpg +0 -0
- package/kb/references/thumbs/fed21b3e98.jpg +0 -0
- package/kb/references/thumbs/fed2205951.jpg +0 -0
- package/kb/references/thumbs/ffdacf1715.jpg +0 -0
- package/kb/sections/_buttons.md +93 -0
- package/kb/sections/_finish.md +325 -0
- package/kb/sections/about-founder-note.md +85 -0
- package/kb/sections/about-team-roster.md +86 -0
- package/kb/sections/alternating-rows-live-tiles.md +110 -0
- package/kb/sections/annotated-product-shot.md +105 -0
- package/kb/sections/asymmetric-bento-dominant.md +114 -0
- package/kb/sections/before-after-features.md +104 -0
- package/kb/sections/before-after-repair.md +107 -0
- package/kb/sections/bento-lead-tile.md +112 -0
- package/kb/sections/book-a-slot-honest.md +116 -0
- package/kb/sections/capability-prompt-ledger.md +68 -0
- package/kb/sections/case-study-band.md +113 -0
- package/kb/sections/centred-stack-hero.md +107 -0
- package/kb/sections/closing-demo-final-state.md +81 -0
- package/kb/sections/closing-full-bleed-line-and-form.md +86 -0
- package/kb/sections/closing-result-previewed.md +88 -0
- package/kb/sections/closing-three-real-steps.md +87 -0
- package/kb/sections/command-reference-table.md +70 -0
- package/kb/sections/comparison-old-way-bars.md +88 -0
- package/kb/sections/comparison-same-task-two-ways.md +88 -0
- package/kb/sections/day-of-the-place.md +102 -0
- package/kb/sections/docs-reading-rail.md +88 -0
- package/kb/sections/editorial-columns-hero.md +107 -0
- package/kb/sections/editorial-essay-pull-quote.md +112 -0
- package/kb/sections/events-calendar-list.md +107 -0
- package/kb/sections/explorable-control-demo.md +102 -0
- package/kb/sections/faq-open-answers-editorial.md +85 -0
- package/kb/sections/faq-ruled-accordion-aside.md +87 -0
- package/kb/sections/footer-closing-scene.md +84 -0
- package/kb/sections/footer-editorial-sitemap.md +85 -0
- package/kb/sections/footer-minimal-credits.md +80 -0
- package/kb/sections/full-bleed-image-band.md +103 -0
- package/kb/sections/full-bleed-image-hero.md +105 -0
- package/kb/sections/gallery-first-hero.md +109 -0
- package/kb/sections/horizontal-scroll-strip.md +101 -0
- package/kb/sections/how-i-work-own-voice.md +111 -0
- package/kb/sections/how-it-works-in-place.md +109 -0
- package/kb/sections/impact-numbers-sourced.md +109 -0
- package/kb/sections/install-steps-per-agent.md +77 -0
- package/kb/sections/masonry-real-work.md +109 -0
- package/kb/sections/numbered-editorial-columns.md +105 -0
- package/kb/sections/object-first-hero.md +106 -0
- package/kb/sections/object-timeline.md +105 -0
- package/kb/sections/one-huge-number.md +100 -0
- package/kb/sections/one-person-story.md +103 -0
- package/kb/sections/order-ahead-ticket.md +119 -0
- package/kb/sections/press-strip-quoted.md +106 -0
- package/kb/sections/pricing-comparison-table-sticky.md +94 -0
- package/kb/sections/pricing-free-pro-upgrade-moment.md +85 -0
- package/kb/sections/pricing-plan-beside-product.md +88 -0
- package/kb/sections/pricing-plans-ledger.md +94 -0
- package/kb/sections/pricing-usage-calculator.md +93 -0
- package/kb/sections/printed-menu-card.md +110 -0
- package/kb/sections/process-happening.md +102 -0
- package/kb/sections/project-index-ruled.md +106 -0
- package/kb/sections/proof-logo-cloud-with-reasons.md +82 -0
- package/kb/sections/proof-measured-numbers.md +88 -0
- package/kb/sections/proof-output-wall.md +84 -0
- package/kb/sections/proof-single-honest-quote.md +81 -0
- package/kb/sections/resources-searchable-list.md +110 -0
- package/kb/sections/rooms-and-rates.md +107 -0
- package/kb/sections/ruled-facts-table.md +108 -0
- package/kb/sections/ruled-list-pinned-visual.md +107 -0
- package/kb/sections/scroll-scrubbed-product-demo.md +103 -0
- package/kb/sections/self-playing-run-demo.md +104 -0
- package/kb/sections/services-price-ledger.md +106 -0
- package/kb/sections/signup-form-with-next-steps.md +86 -0
- package/kb/sections/signup-waitlist-place-in-line.md +90 -0
- package/kb/sections/spec-sheet-features.md +108 -0
- package/kb/sections/split-hero-live-object.md +108 -0
- package/kb/sections/sticky-feature-narrative.md +104 -0
- package/kb/sections/todays-board-hero.md +112 -0
- package/kb/sections/touchable-tool-hero.md +111 -0
- package/kb/sections/typographic-statement-hero.md +99 -0
- package/kb/sections/visit-hours-map.md +110 -0
- package/kb/sections/ways-to-help-honest.md +115 -0
- package/kb/sources/design-reference.md +991 -0
- package/kb/sources/product-and-docs.md +37 -0
- package/kb/systems/1win/DESIGN.md +463 -0
- package/kb/systems/LICENSE-awesome-design-md +21 -0
- package/kb/systems/README.md +7 -0
- package/kb/systems/airbnb/DESIGN.md +545 -0
- package/kb/systems/airtable/DESIGN.md +554 -0
- package/kb/systems/aljazeera/DESIGN.md +594 -0
- package/kb/systems/apple/DESIGN.md +562 -0
- package/kb/systems/binance/DESIGN.md +634 -0
- package/kb/systems/bmw/DESIGN.md +544 -0
- package/kb/systems/bmw-m/DESIGN.md +503 -0
- package/kb/systems/bugatti/DESIGN.md +454 -0
- package/kb/systems/cal/DESIGN.md +542 -0
- package/kb/systems/categories.json +87 -0
- package/kb/systems/claude/DESIGN.md +589 -0
- package/kb/systems/clay/DESIGN.md +541 -0
- package/kb/systems/clickhouse/DESIGN.md +544 -0
- package/kb/systems/cohere/DESIGN.md +451 -0
- package/kb/systems/coinbase/DESIGN.md +570 -0
- package/kb/systems/composio/DESIGN.md +506 -0
- package/kb/systems/cursor/DESIGN.md +537 -0
- package/kb/systems/dell-1996/DESIGN.md +632 -0
- package/kb/systems/dji/DESIGN.md +882 -0
- package/kb/systems/elevenlabs/DESIGN.md +504 -0
- package/kb/systems/expo/DESIGN.md +526 -0
- package/kb/systems/ferrari/DESIGN.md +531 -0
- package/kb/systems/figma/DESIGN.md +578 -0
- package/kb/systems/framer/DESIGN.md +544 -0
- package/kb/systems/hashicorp/DESIGN.md +575 -0
- package/kb/systems/hp/DESIGN.md +670 -0
- package/kb/systems/ibm/DESIGN.md +550 -0
- package/kb/systems/intercom/DESIGN.md +546 -0
- package/kb/systems/jobright/DESIGN.md +525 -0
- package/kb/systems/kraken/DESIGN.md +125 -0
- package/kb/systems/lamborghini/DESIGN.md +288 -0
- package/kb/systems/linear.app/DESIGN.md +548 -0
- package/kb/systems/lovable/DESIGN.md +298 -0
- package/kb/systems/mastercard/DESIGN.md +365 -0
- package/kb/systems/mercury/DESIGN.md +568 -0
- package/kb/systems/meta/DESIGN.md +683 -0
- package/kb/systems/minimax/DESIGN.md +746 -0
- package/kb/systems/mintlify/DESIGN.md +852 -0
- package/kb/systems/miro/DESIGN.md +825 -0
- package/kb/systems/mistral.ai/DESIGN.md +773 -0
- package/kb/systems/mongodb/DESIGN.md +767 -0
- package/kb/systems/mydealz/DESIGN.md +551 -0
- package/kb/systems/nerdwallet/DESIGN.md +722 -0
- package/kb/systems/nike/DESIGN.md +575 -0
- package/kb/systems/nintendo-2001/DESIGN.md +649 -0
- package/kb/systems/notion/DESIGN.md +821 -0
- package/kb/systems/nvidia/DESIGN.md +640 -0
- package/kb/systems/ollama/DESIGN.md +539 -0
- package/kb/systems/opencode.ai/DESIGN.md +521 -0
- package/kb/systems/oracle/DESIGN.md +778 -0
- package/kb/systems/oura/DESIGN.md +616 -0
- package/kb/systems/pinterest/DESIGN.md +597 -0
- package/kb/systems/playstation/DESIGN.md +661 -0
- package/kb/systems/posthog/DESIGN.md +690 -0
- package/kb/systems/raycast/DESIGN.md +669 -0
- package/kb/systems/renault/DESIGN.md +589 -0
- package/kb/systems/replicate/DESIGN.md +616 -0
- package/kb/systems/resend/DESIGN.md +585 -0
- package/kb/systems/revolut/DESIGN.md +636 -0
- package/kb/systems/runwayml/DESIGN.md +244 -0
- package/kb/systems/sanity/DESIGN.md +357 -0
- package/kb/systems/sap/DESIGN.md +639 -0
- package/kb/systems/sentry/DESIGN.md +551 -0
- package/kb/systems/shopify/DESIGN.md +516 -0
- package/kb/systems/slack/DESIGN.md +482 -0
- package/kb/systems/spacex/DESIGN.md +363 -0
- package/kb/systems/spotify/DESIGN.md +246 -0
- package/kb/systems/starbucks/DESIGN.md +580 -0
- package/kb/systems/stripe/DESIGN.md +487 -0
- package/kb/systems/supabase/DESIGN.md +462 -0
- package/kb/systems/superhuman/DESIGN.md +448 -0
- package/kb/systems/tesla/DESIGN.md +286 -0
- package/kb/systems/theverge/DESIGN.md +339 -0
- package/kb/systems/together.ai/DESIGN.md +633 -0
- package/kb/systems/uber/DESIGN.md +636 -0
- package/kb/systems/vercel/DESIGN.md +736 -0
- package/kb/systems/vodafone/DESIGN.md +538 -0
- package/kb/systems/voltagent/DESIGN.md +521 -0
- package/kb/systems/warp/DESIGN.md +526 -0
- package/kb/systems/webflow/DESIGN.md +588 -0
- package/kb/systems/wired/DESIGN.md +497 -0
- package/kb/systems/wise/DESIGN.md +544 -0
- package/kb/systems/x.ai/DESIGN.md +465 -0
- package/kb/systems/zapier/DESIGN.md +537 -0
- package/kb/taste/garvit-by-job.md +46 -0
- package/kb/taste/garvit-portfolio.md +94 -0
- package/kb/universal/color-roles.md +26 -0
- package/kb/universal/copy.md +16 -0
- package/kb/universal/details.md +31 -0
- package/kb/universal/first-screen.md +30 -0
- package/kb/universal/fit-the-codebase.md +29 -0
- package/kb/universal/layout-width.md +28 -0
- package/kb/universal/motion-feedback.md +23 -0
- package/kb/universal/signature.md +29 -0
- package/kb/universal/states.md +17 -0
- package/kb/universal/type-app.md +33 -0
- package/kb/universal/type-marketing.md +28 -0
- package/package.json +36 -4
- package/scripts/pack-assets.mjs +48 -0
- package/skill/palate/SKILL.md +261 -0
- package/src/auth-recheck.mjs +4 -0
- package/src/auth.mjs +416 -0
- package/src/capture.mjs +182 -0
- package/src/catalog/classify.mjs +96 -0
- package/src/catalog/curated.mjs +128 -0
- package/src/catalog/index-build.mjs +67 -0
- package/src/catalog/literal.mjs +146 -0
- package/src/catalog/store.mjs +40 -0
- package/src/catalog/vibrant.mjs +126 -0
- package/src/check.mjs +93 -0
- package/src/concept.mjs +157 -0
- package/src/context.mjs +226 -0
- package/src/copy.mjs +188 -0
- package/src/devserver.mjs +135 -0
- package/src/fontgenre.mjs +44 -0
- package/src/guard-agents.mjs +213 -0
- package/src/guard.mjs +377 -0
- package/src/kb.mjs +91 -0
- package/src/look.mjs +312 -0
- package/src/loop/ambition.mjs +620 -0
- package/src/loop/animate.mjs +70 -0
- package/src/loop/artdirection.mjs +264 -0
- package/src/loop/bench.mjs +184 -0
- package/src/loop/benchpick.mjs +155 -0
- package/src/loop/blueprint.mjs +620 -0
- package/src/loop/board.html +180 -0
- package/src/loop/build.mjs +393 -0
- package/src/loop/buttons.mjs +413 -0
- package/src/loop/common.mjs +206 -0
- package/src/loop/cost.mjs +63 -0
- package/src/loop/craft.mjs +152 -0
- package/src/loop/craftchecks.mjs +148 -0
- package/src/loop/critique.mjs +393 -0
- package/src/loop/details.mjs +225 -0
- package/src/loop/direction.html +168 -0
- package/src/loop/direction.mjs +256 -0
- package/src/loop/directions.json +8 -0
- package/src/loop/explore.mjs +219 -0
- package/src/loop/fail.mjs +110 -0
- package/src/loop/fix.mjs +194 -0
- package/src/loop/floor.mjs +677 -0
- package/src/loop/forget.mjs +52 -0
- package/src/loop/gate.mjs +1053 -0
- package/src/loop/grid.html +123 -0
- package/src/loop/growth.mjs +118 -0
- package/src/loop/icons.mjs +109 -0
- package/src/loop/imagery.mjs +1280 -0
- package/src/loop/judge-api.mjs +245 -0
- package/src/loop/judge.mjs +167 -0
- package/src/loop/layouts.mjs +492 -0
- package/src/loop/library.mjs +82 -0
- package/src/loop/lookplan.mjs +182 -0
- package/src/loop/lookvec.mjs +645 -0
- package/src/loop/match.mjs +923 -0
- package/src/loop/matched.mjs +26 -0
- package/src/loop/myrefs.mjs +151 -0
- package/src/loop/pick.mjs +213 -0
- package/src/loop/picker.html +118 -0
- package/src/loop/plan.mjs +289 -0
- package/src/loop/polish.mjs +39 -0
- package/src/loop/research-learn.mjs +41 -0
- package/src/loop/research.mjs +1130 -0
- package/src/loop/rulereview.mjs +146 -0
- package/src/loop/rules-board.html +199 -0
- package/src/loop/rules.mjs +939 -0
- package/src/loop/similar.mjs +276 -0
- package/src/loop/states-source.mjs +258 -0
- package/src/loop/states.mjs +1547 -0
- package/src/loop/stats.mjs +78 -0
- package/src/loop/taste.mjs +81 -0
- package/src/loop/timeline.mjs +149 -0
- package/src/loop/variants.mjs +228 -0
- package/src/loop/vary.mjs +249 -0
- package/src/mcp/server.mjs +1246 -0
- package/src/motion.mjs +207 -0
- package/src/moves.mjs +242 -0
- package/src/novelty.mjs +116 -0
- package/src/page-ambition.js +181 -0
- package/src/page-craft.js +724 -0
- package/src/page-details.js +415 -0
- package/src/page-devices.js +365 -0
- package/src/page-fingerprint.js +281 -0
- package/src/page-gate.js +1307 -0
- package/src/page-look.js +698 -0
- package/src/page-metrics.js +78 -0
- package/src/page-principles.js +1167 -0
- package/src/page-rules.js +308 -0
- package/src/page-sections.js +211 -0
- package/src/page-states.js +703 -0
- package/src/paths.mjs +13 -0
- package/src/png.mjs +107 -0
- package/src/point/auto.mjs +224 -0
- package/src/point/locate.mjs +114 -0
- package/src/point/overlay.js +1516 -0
- package/src/point/server.mjs +1122 -0
- package/src/point/trail.mjs +219 -0
- package/src/pool.mjs +80 -0
- package/src/principles.mjs +279 -0
- package/src/refs.mjs +299 -0
- package/src/robots.mjs +145 -0
- package/src/sections.mjs +210 -0
- package/src/shoot.mjs +235 -0
- package/src/systems/apply.mjs +355 -0
- package/src/systems/load.mjs +251 -0
- package/src/systems/pick.mjs +213 -0
- package/templates/vite-react-tw/index.html +12 -0
- package/templates/vite-react-tw/package.json +25 -0
- package/templates/vite-react-tw/src/App.tsx +3 -0
- package/templates/vite-react-tw/src/index.css +1 -0
- package/templates/vite-react-tw/src/main.tsx +10 -0
- package/templates/vite-react-tw/tsconfig.app.json +26 -0
- package/templates/vite-react-tw/tsconfig.json +7 -0
- package/templates/vite-react-tw/tsconfig.node.json +23 -0
- package/templates/vite-react-tw/vite.config.ts +8 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// How a loop stays varied: the structures (archetypes) a loop can assign, directions generated from the
|
|
2
|
+
// user's references and from the library's style clusters for this job, the choice of directions (what won
|
|
3
|
+
// first, one slot that explores something this user has never seen for this kind of screen), and references
|
|
4
|
+
// split so no two directions share one.
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { TASTE_DIR, readJson } from "./common.mjs";
|
|
9
|
+
import { pastGenerated, seenDirections } from "./layouts.mjs";
|
|
10
|
+
import { listRefs } from "./myrefs.mjs";
|
|
11
|
+
|
|
12
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
|
|
14
|
+
// Structures. Each has two forms so the two variants of one direction differ structurally too.
|
|
15
|
+
export const ARCHETYPES = {
|
|
16
|
+
page: [
|
|
17
|
+
{ id: "split", name: "Split hero", brief: "The first screen splits in two: headline, one line and the action on one side; the real product on the other, at a size you can read.", forms: ["text left, the product right and allowed to bleed off the right edge", "the product left and larger (about 7/12), text right, a thin proof strip spanning both underneath"] },
|
|
18
|
+
{ id: "centred", name: "Centred stack", brief: "A centred headline, the action directly under it, then the product full width below, all on one axis.", forms: ["the product in one framed window under the action", "the product as a row of real outputs side by side, no window frame"] },
|
|
19
|
+
{ id: "fullbleed", name: "Full-bleed product", brief: "The main content (the product, its real output, the plans) fills the first screen edge to edge; the headline is a compact block on or beside it.", forms: ["the headline in a compact panel over one corner of the content", "the headline in a slim band above an edge-to-edge strip of the content"] },
|
|
20
|
+
{ id: "editorial", name: "Editorial grid", brief: "A type-led, multi-column grid like a well-made publication: a large headline spanning most columns, facts and captions in narrow columns, ruled or numbered sections.", forms: ["a 12-column grid: headline across 8, a narrow column of facts on the right", "three ruled columns of numbered entries under a full-width headline"] },
|
|
21
|
+
{ id: "asymmetric", name: "Asymmetric", brief: "An off-centre composition: oversized type anchored to one side, content offset to a strong vertical line, a sticky index or side column while sections scroll.", forms: ["a sticky left index of section names, content scrolling on the right", "an oversized headline on the left, everything else starting at a 5/12 offset"] },
|
|
22
|
+
{ id: "bento", name: "Bento overview", brief: "Right after a short headline, a grid of unequal tiles, each holding one real part of the content shown for real; tile size follows importance.", forms: ["one large tile and four small ones", "a 2-row mosaic with one tall tile at the side"] },
|
|
23
|
+
],
|
|
24
|
+
app: [
|
|
25
|
+
{ id: "full-width", name: "Main object full width", brief: "The main object (table, list, board, plans) takes the full width; filters and summaries sit in one slim bar above it.", forms: ["a single full-width table or list with a summary strip that doubles as a filter", "the main object grouped into labelled sections, each with its own totals"] },
|
|
26
|
+
{ id: "master-detail", name: "List + detail", brief: "A scannable list on one side, the selected item's detail on the other, both visible at once.", forms: ["list left (about 5/12), detail right", "a compact list across the top, the selected item's detail filling the space below"] },
|
|
27
|
+
{ id: "rail", name: "Main + summary rail", brief: "The main object with a narrow rail of summaries, quick filters or next actions beside it.", forms: ["rail on the right with live summaries", "rail on the left with quick filters and counts"] },
|
|
28
|
+
{ id: "columns", name: "Columns / board", brief: "Items laid out in side-by-side columns (by stage, step or group), so the whole state reads at a glance.", forms: ["equal columns, one per stage or step", "columns of different widths, the active one widest"] },
|
|
29
|
+
{ id: "document", name: "Document flow", brief: "One readable column, sections stacked like a document, controls inline where they apply.", forms: ["a single centred column with inline controls", "a column with a sticky outline beside it"] },
|
|
30
|
+
{ id: "cards", name: "Card overview", brief: "A grid of equal cards, each a complete record or step with its own action.", forms: ["a 3-across grid of working cards", "a 2-across grid of larger cards with a progress or status strip on top"] },
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
export const archetypesFor = (kind) => ARCHETYPES[kind === "app" ? "app" : "page"];
|
|
34
|
+
|
|
35
|
+
// Phrases for the library's style tags; pairs of tags that co-occur in this job's references make a direction.
|
|
36
|
+
const STYLE = {
|
|
37
|
+
"editorial serif typography": "a serif display face set large, with an editorial rhythm",
|
|
38
|
+
"bold large typography": "very large, heavy headline type as the main graphic element",
|
|
39
|
+
photography: "real photography from the project as a major surface",
|
|
40
|
+
"dark theme": "a dark canvas with light type",
|
|
41
|
+
"dense information": "dense, information-rich panels where density is the content",
|
|
42
|
+
monochrome: "a monochrome palette, contrast from value alone",
|
|
43
|
+
"soft shadows": "soft, layered shadows for depth",
|
|
44
|
+
"warm tones": "warm off-whites and earthy tones",
|
|
45
|
+
playful: "playful shapes and small moments of delight",
|
|
46
|
+
"rounded corners": "generous rounded corners",
|
|
47
|
+
"sharp corners": "square corners and hairline rules",
|
|
48
|
+
monospace: "monospace type for data, labels and numbers",
|
|
49
|
+
minimal: "radical reduction: few elements, each exact",
|
|
50
|
+
outlined: "outlined, line-drawn components instead of filled ones",
|
|
51
|
+
spacious: "generous spacing",
|
|
52
|
+
illustration: "one custom illustration drawn from the product's domain",
|
|
53
|
+
colorful: "a confident multi-colour palette used with discipline",
|
|
54
|
+
friendly: "friendly, approachable forms and copy",
|
|
55
|
+
enterprise: "sober, enterprise-grade structure",
|
|
56
|
+
};
|
|
57
|
+
const CLASH = [["dark theme", "light theme"], ["rounded corners", "sharp corners"], ["monochrome", "colorful"], ["dense information", "spacious"], ["dense information", "minimal"], ["playful", "enterprise"]];
|
|
58
|
+
const clash = (a, b) => CLASH.some(([x, y]) => (a === x && b === y) || (a === y && b === x));
|
|
59
|
+
const slug = (s) => s.replace(/[^a-z]+/gi, "-").toLowerCase();
|
|
60
|
+
const cap = (s) => s[0].toUpperCase() + s.slice(1);
|
|
61
|
+
|
|
62
|
+
export function baseDirections() {
|
|
63
|
+
return readJson(path.join(here, "directions.json"), []);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Directions from the style tags that cluster in this job's library results. Skips pairs a base direction
|
|
67
|
+
// already stands for.
|
|
68
|
+
export function libraryDirections(pool) {
|
|
69
|
+
const base = baseDirections();
|
|
70
|
+
const pairs = new Map();
|
|
71
|
+
for (const r of pool) {
|
|
72
|
+
const tags = r.tags.filter((t) => STYLE[t]);
|
|
73
|
+
for (let i = 0; i < tags.length; i++)
|
|
74
|
+
for (let j = i + 1; j < tags.length; j++) {
|
|
75
|
+
if (clash(tags[i], tags[j])) continue;
|
|
76
|
+
const key = [tags[i], tags[j]].sort().join("|");
|
|
77
|
+
pairs.set(key, (pairs.get(key) ?? 0) + 1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return [...pairs.entries()]
|
|
81
|
+
.filter(([k, n]) => n >= 2 && !base.some((d) => k.split("|").every((t) => (d.style ?? "").includes(t))))
|
|
82
|
+
.sort((a, b) => b[1] - a[1])
|
|
83
|
+
.slice(0, 4)
|
|
84
|
+
.map(([k, n]) => {
|
|
85
|
+
const [a, b] = k.split("|");
|
|
86
|
+
return { id: `gen-${slug(a)}+${slug(b)}`, name: `${cap(a)} + ${b}`, brief: `${cap(STYLE[a])}, and ${STYLE[b]}. Drawn from ${n} library references for this job that share it; everything else stays clear.`, style: `${a} ${b}`, generated: "library" };
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Directions from the user's own saved references: their measured type and colour, their notes.
|
|
91
|
+
export function refDirections(exclude = []) {
|
|
92
|
+
return listRefs()
|
|
93
|
+
.filter((r) => !exclude.includes(r.id) && (r.measures || r.note))
|
|
94
|
+
.slice(-4)
|
|
95
|
+
.map((r) => {
|
|
96
|
+
const m = r.measures ?? {};
|
|
97
|
+
const host = r.kind === "url" ? r.source.replace(/^https?:\/\/(www\.)?/, "").split("/")[0] : path.basename(r.source);
|
|
98
|
+
const facts = [m.headline && `headline ${m.headline}`, m.fonts?.length && `fonts ${m.fonts.join(", ")}`, m.radii?.length && `radii ${m.radii.join(", ")}`, m.backgrounds?.length && `backgrounds ${m.backgrounds.slice(0, 3).join(", ")}`].filter(Boolean).join("; ");
|
|
99
|
+
return { id: `ref-${r.id}`, name: `The type and colour of ${host}`, brief: `From a reference the user saved (${r.source}${r.note ? `; their note: "${r.note}"` : ""}). ${facts ? `Measured: ${facts}. ` : ""}Take its type character, scale contrast and palette mood (never its text, logos or brand colours); the structure comes from your assigned archetype.`, style: "", generated: "user-ref" };
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const picksLog = () => (fs.existsSync(path.join(TASTE_DIR, "picks.jsonl")) ? fs.readFileSync(path.join(TASTE_DIR, "picks.jsonl"), "utf8").split("\n").filter(Boolean).map((l) => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean) : []);
|
|
104
|
+
|
|
105
|
+
// Wins per direction id (2 for this kind of screen, 1 elsewhere) and per archetype for this kind.
|
|
106
|
+
function wins(kind) {
|
|
107
|
+
const byDir = {};
|
|
108
|
+
const byArch = {};
|
|
109
|
+
for (const p of picksLog()) {
|
|
110
|
+
if (!p.winner || !p.directions) continue;
|
|
111
|
+
const letter = p.winner.match(/-([a-z])\d+$/)?.[1];
|
|
112
|
+
const d = p.directions.find((x) => x.letter === letter);
|
|
113
|
+
if (!d) continue;
|
|
114
|
+
const id = d.id.replace(/^blend-/, "");
|
|
115
|
+
byDir[id] = (byDir[id] ?? 0) + (p.kind === kind ? 2 : 1);
|
|
116
|
+
if (d.archetype && p.kind === kind) byArch[d.archetype] = (byArch[d.archetype] ?? 0) + 1;
|
|
117
|
+
}
|
|
118
|
+
return { byDir, byArch };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Chooses `count` directions, each with its own structure:
|
|
122
|
+
// - the directions that have won most for this user come first (base, generated or from their references);
|
|
123
|
+
// - one slot explores: a direction this user has never seen for this kind of screen, or failing that a
|
|
124
|
+
// direction × structure pair never seen; generated directions count, so exploring never runs dry;
|
|
125
|
+
// - structures never repeat inside a loop and prefer ones least made for this kind of screen.
|
|
126
|
+
export function chooseDirections(count, { kind, screen, pool = [], exclude = [], keepSlots } = {}) {
|
|
127
|
+
const generated = [...libraryDirections(pool), ...refDirections(exclude)];
|
|
128
|
+
const revived = pastGenerated().filter((g) => !generated.some((x) => x.id === g.id));
|
|
129
|
+
const all = [...baseDirections(), ...generated, ...revived];
|
|
130
|
+
const { byDir, byArch } = wins(kind);
|
|
131
|
+
const seen = seenDirections(kind, screen, picksLog());
|
|
132
|
+
const jitter = () => Math.random() * 0.01;
|
|
133
|
+
const exploit = Math.max(1, keepSlots ?? count - 1);
|
|
134
|
+
// Revived generated directions only return when they have won.
|
|
135
|
+
const ranked = all.filter((d) => !d.generated || byDir[d.id] > 0).sort((a, b) => (byDir[b.id] ?? 0) - (byDir[a.id] ?? 0) || Math.random() - 0.5);
|
|
136
|
+
const keep = ranked.slice(0, exploit);
|
|
137
|
+
const archs = archetypesFor(kind);
|
|
138
|
+
const used = new Set();
|
|
139
|
+
const archOrder = (preferWinner) =>
|
|
140
|
+
[...archs].filter((a) => !used.has(a.id)).sort((a, b) => (preferWinner ? (byArch[b.id] ?? 0) - (byArch[a.id] ?? 0) : 0) || (seen.shapes[a.id] ?? 0) - (seen.shapes[b.id] ?? 0) || Math.random() - 0.5);
|
|
141
|
+
const out = keep.map((d, i) => {
|
|
142
|
+
// The first slot may keep the structure that has won for this kind of screen; the rest take the least made.
|
|
143
|
+
const a = archOrder(i === 0 && Object.keys(byArch).length > 0)[0];
|
|
144
|
+
used.add(a.id);
|
|
145
|
+
return { ...d, archetype: a.id, archetypeWon: i === 0 && byArch[a.id] > 0 };
|
|
146
|
+
});
|
|
147
|
+
// The explore slot.
|
|
148
|
+
while (out.length < count) {
|
|
149
|
+
const options = [];
|
|
150
|
+
for (const d of all.filter((x) => !out.some((o) => o.id === x.id) && !revived.includes(x)))
|
|
151
|
+
for (const a of archs.filter((x) => !used.has(x.id))) {
|
|
152
|
+
const newDir = !seen.dirs.has(d.id);
|
|
153
|
+
const newPair = !seen.combos.has(`${d.id}|${a.id}`);
|
|
154
|
+
options.push({ d, a, score: (newDir ? 4 : 0) + (newPair ? 2 : 0) + (d.generated ? 0.5 : 0) + 1 / (1 + (seen.shapes[a.id] ?? 0)) + jitter() + Math.random() });
|
|
155
|
+
}
|
|
156
|
+
if (!options.length) break;
|
|
157
|
+
const best = options.sort((x, y) => y.score - x.score)[0];
|
|
158
|
+
used.add(best.a.id);
|
|
159
|
+
out.push({ ...best.d, archetype: best.a.id, explore: true, neverSeen: !seen.dirs.has(best.d.id) ? "direction" : !seen.combos.has(`${best.d.id}|${best.a.id}`) ? "pair" : null });
|
|
160
|
+
}
|
|
161
|
+
return { directions: out, generated, used };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function nextArchetype(kind, used, screenShapes = {}) {
|
|
165
|
+
return archetypesFor(kind).filter((a) => !used.has(a.id)).sort((a, b) => (screenShapes[a.id] ?? 0) - (screenShapes[b.id] ?? 0) || Math.random() - 0.5)[0];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// The reference pool for a job: several searches (the job's first sentence, the whole job, the kind of
|
|
169
|
+
// screen), merged by rank, so three directions can each get their own references.
|
|
170
|
+
const EXPAND = {
|
|
171
|
+
landing: ["landing page hero section", "call to action newsletter signup", "features section"],
|
|
172
|
+
hero: ["hero section landing page", "call to action"],
|
|
173
|
+
pricing: ["pricing section comparison table", "billing page"],
|
|
174
|
+
features: ["features section card grid", "landing page"],
|
|
175
|
+
onboarding: ["onboarding steps stepper", "empty state"],
|
|
176
|
+
team: ["team section user list", "settings page"],
|
|
177
|
+
settings: ["settings page form", "sidebar navigation"],
|
|
178
|
+
table: ["data table search and filters", "dashboard"],
|
|
179
|
+
dashboard: ["dashboard analytics chart", "stats section"],
|
|
180
|
+
auth: ["login form signup form"],
|
|
181
|
+
docs: ["documentation page", "blog list"],
|
|
182
|
+
};
|
|
183
|
+
export function referencePool(searchLibrary, job, { kind, screen } = {}) {
|
|
184
|
+
const first = job.split(/[.:]/)[0].slice(0, 160);
|
|
185
|
+
const queries = [[first, 3], [job.slice(0, 300), 2], ...(EXPAND[screen] ?? [kind === "app" ? "app section dashboard" : "marketing section landing page"]).map((q) => [q, 1])];
|
|
186
|
+
const score = new Map();
|
|
187
|
+
const rec = new Map();
|
|
188
|
+
for (const [q, w] of queries)
|
|
189
|
+
searchLibrary(q, { n: 40, preferWhole: true }).forEach((r, i) => {
|
|
190
|
+
rec.set(r.id, r);
|
|
191
|
+
score.set(r.id, (score.get(r.id) ?? 0) + w / (i + 3));
|
|
192
|
+
});
|
|
193
|
+
return [...rec.values()].sort((a, b) => score.get(b.id) - score.get(a.id)).map((r, i) => ({ ...r, rank: i }));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Splits the pool so no two directions share a reference: each direction in turn takes its best remaining
|
|
197
|
+
// match (relevance first, its style words second), until each has `per` or the pool runs out.
|
|
198
|
+
export function splitReferences(pool, directions, styleOf, per = 6) {
|
|
199
|
+
const words = (s) => new Set(String(s ?? "").toLowerCase().split(/\s+/).filter(Boolean));
|
|
200
|
+
const taken = new Set();
|
|
201
|
+
const out = directions.map(() => []);
|
|
202
|
+
for (let round = 0; round < per; round++)
|
|
203
|
+
directions.forEach((d, i) => {
|
|
204
|
+
const sw = words(styleOf(d));
|
|
205
|
+
let best = null;
|
|
206
|
+
let bestScore = -Infinity;
|
|
207
|
+
for (const r of pool) {
|
|
208
|
+
if (taken.has(r.id)) continue;
|
|
209
|
+
const style = r.tags.filter((t) => t.split(" ").every((w) => sw.has(w))).length;
|
|
210
|
+
const s = style * 6 - r.rank;
|
|
211
|
+
if (s > bestScore) [best, bestScore] = [r, s];
|
|
212
|
+
}
|
|
213
|
+
if (best) {
|
|
214
|
+
taken.add(best.id);
|
|
215
|
+
out[i].push(best);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// `palate fail <route> "<why>"`: the user says a screen is bad. palate shoots it (or takes the screenshots
|
|
2
|
+
// given with --shot), keeps them in ~/.palate/failures with the why, and proposes rules from it: the general
|
|
3
|
+
// form of what it matches ("logos too small" → logo marks at least 24px, measured), else the user's words as a
|
|
4
|
+
// rule the judge asks. A proposal applies nowhere until the user keeps it with a scope (palate rule review | ok).
|
|
5
|
+
// Briefs for this kind of screen show the failure itself under "Don't do this".
|
|
6
|
+
// palate rule add "<rule>" [--kind landing | --only <Component> | --route /x] [--project <name>] a rule in the user's words (active at once)
|
|
7
|
+
// palate rule list | edit <id> ["<words>"] [--kind k] [--project <name> | --project all] | rm <id> | learn [--all]
|
|
8
|
+
// palate rule review the proposals on a board in the browser: scope, wording, keep or discard
|
|
9
|
+
// palate rule ok <id> [--scope …|--kind …|--only <Component>|--route /x] [--project <name>] [--text "…"] keep a proposal
|
|
10
|
+
// palate rule no <id> discard a proposal (remembered, so the same evidence won't bring it back)
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import { normalizeRoute, shoot } from "../shoot.mjs";
|
|
13
|
+
import { approveRule, checkWords, classifyScope, dedupe, editRule, isProposed, learnedLines, learnRules, loadRules, projectOf, proposalLine, recordFailure, rejectRule, removeRule, reviewHint, routeTags, ruleFrom, RULES_FILE, scopeLabel } from "./rules.mjs";
|
|
14
|
+
|
|
15
|
+
const slash = (p) => String(p).replace(/\\/g, "/");
|
|
16
|
+
const kindsOf = (kind) => (kind ? String(kind).split(",").map((k) => k.trim().toLowerCase()).filter(Boolean) : null);
|
|
17
|
+
const said = (list) =>
|
|
18
|
+
list.map(({ rule: r, added, discarded, needs }) =>
|
|
19
|
+
!r ? `- Not proposed: you discarded "${discarded.rule}" before (it comes back only after ${needs} more new ask${needs > 1 ? "s" : ""}).` : isProposed(r) ? `- Proposed, waiting for your OK: ${r.id} ${r.rule} (${checkWords(r)})` : `- ${added ? "New" : "Already a rule, strengthened"}: ${r.id} [${scopeLabel(r)}] ${r.rule} (${checkWords(r)})`,
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export async function fail(dir, rawRoute, why, { kind, shots, url, project } = {}) {
|
|
23
|
+
if (!rawRoute || !why) throw new Error('Usage: palate fail <route> "<why it is bad, in the user\'s words>" [--kind landing] [--shot file.png]');
|
|
24
|
+
const route = normalizeRoute(rawRoute);
|
|
25
|
+
// --shot "" records a failure with no screenshot.
|
|
26
|
+
let files = shots ?? [];
|
|
27
|
+
if (shots == null) {
|
|
28
|
+
// The whole page at 1440, the way the user saw it.
|
|
29
|
+
const shot = await shoot(dir, route, { url, widths: [1440], principles: false });
|
|
30
|
+
files = shot.files.filter((f) => f.endsWith("-full.png")).slice(0, 1);
|
|
31
|
+
}
|
|
32
|
+
const kinds = kindsOf(kind) ?? routeTags(dir, route);
|
|
33
|
+
const { failure, learned } = recordFailure({ project: project ?? path.basename(path.resolve(dir)), route, why, kinds, shots: files });
|
|
34
|
+
const proposals = learned.filter((l) => l.rule && isProposed(l.rule)).map((l) => l.rule.id);
|
|
35
|
+
return [
|
|
36
|
+
`Saved the failure: ${failure.id}${failure.shots.length ? ` (${failure.shots.join(", ")})` : ""}.`,
|
|
37
|
+
`Kinds: ${kinds.join(", ")}. Briefs for these screens now show it under "Don't do this".`,
|
|
38
|
+
"",
|
|
39
|
+
"What palate learned from it:",
|
|
40
|
+
...said(learned),
|
|
41
|
+
...(proposals.length ? ["", `This fix is for ${route}; whether it holds anywhere else is the user's call. ${reviewHint(proposals)}`] : []),
|
|
42
|
+
"",
|
|
43
|
+
`Rules file: ${slash(RULES_FILE)}.`,
|
|
44
|
+
].join("\n");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const checkOf = (r) => (r.check?.type === "metric" ? `${r.check.metric} ${r.check.op} ${r.check.value}` : r.check?.type === "dom" ? `${r.check.selector}${r.check.min != null ? ` ≥ ${r.check.min}` : ""}${r.check.max != null ? ` ≤ ${r.check.max}` : ""}` : "judge");
|
|
48
|
+
// The scope the user chose, from flags: --only <Component>, --route /x, --kind a,b, --scope <option>; --project
|
|
49
|
+
// <name> keeps any of them to one project.
|
|
50
|
+
const scopeFrom = ({ only, route, kind, scope, project }) => {
|
|
51
|
+
const s = only ? { component: only } : route ? { route } : kindsOf(kind) ? { kinds: kindsOf(kind) } : scope;
|
|
52
|
+
if (!project) return s;
|
|
53
|
+
return typeof s === "object" && s ? { ...s, project } : s ? { scope: s, project } : { project };
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// dir: the project the user is in. With no scope given, palate picks one: a rule tied to this product's identity
|
|
57
|
+
// (a colour, a font, its name, its agents and demos) stays in this project; a judgement about design holds everywhere.
|
|
58
|
+
export function rule(sub, args, { kind, source, only, route, scope, text, project, dir } = {}) {
|
|
59
|
+
const kinds = kindsOf(kind);
|
|
60
|
+
if (sub === "add") {
|
|
61
|
+
// --project all means general taste, the same as on edit.
|
|
62
|
+
if (project?.trim().toLowerCase() === "all") project = undefined;
|
|
63
|
+
const words = args.join(" ").trim();
|
|
64
|
+
const narrow = only ? { component: String(only).replace(/^<|\/?>$/g, "") } : route ? { route: normalizeRoute(route) } : {};
|
|
65
|
+
const picked = !kinds && !only && !route && !project?.trim() && dir && words ? classifyScope(words, { project: projectOf(dir), dir }) : null;
|
|
66
|
+
if (picked?.project) project = picked.project;
|
|
67
|
+
const where = project?.trim() ? { ...narrow, project: project.trim() } : Object.keys(narrow).length ? narrow : undefined;
|
|
68
|
+
const learned = dedupe(ruleFrom(words, { kinds: kinds ?? undefined, source: source ?? `user:"${words.slice(0, 120)}"`, where }));
|
|
69
|
+
const ids = [...new Set(learned.filter((l) => l.rule).map((l) => l.rule.id))].join(" ");
|
|
70
|
+
// Words that match a known rule get its general form and its check; others stay a rule in the user's words.
|
|
71
|
+
return [
|
|
72
|
+
"From your words:",
|
|
73
|
+
...said(learned),
|
|
74
|
+
...(picked
|
|
75
|
+
? [picked.project ? `Scope: only in ${picked.project}, because it's tied to this product: ${picked.why}. If it should hold in every project: palate rule edit ${ids || "<id>"} --project all` : `Scope: general taste (${picked.why}), so it holds in every project. If it's only for this one: palate rule edit ${ids || "<id>"} --project ${projectOf(dir)}`]
|
|
76
|
+
: []),
|
|
77
|
+
].join("\n");
|
|
78
|
+
}
|
|
79
|
+
if (sub === "edit") {
|
|
80
|
+
const [id, ...rest] = args;
|
|
81
|
+
const r = editRule(id, { rule: rest.join(" ") || undefined, kinds: kinds ?? undefined, project });
|
|
82
|
+
return `${r.id} [${scopeLabel(r)}] ${r.rule}`;
|
|
83
|
+
}
|
|
84
|
+
if (sub === "rm" || sub === "remove") {
|
|
85
|
+
const r = removeRule(args[0]);
|
|
86
|
+
return `Removed ${r.id}: ${r.rule}`;
|
|
87
|
+
}
|
|
88
|
+
if (sub === "ok" || sub === "approve" || sub === "keep") {
|
|
89
|
+
if (!args[0]) throw new Error('Usage: palate rule ok <id> [--scope <option>|--kind team|--only <Component>|--route /x] [--project <name>] [--text "<new words>"]');
|
|
90
|
+
const { rule: r, scope: s, mergedFrom } = approveRule(args[0], { scope: scopeFrom({ only, route, kind, scope, project }), text });
|
|
91
|
+
return [`Kept ${mergedFrom ? `${mergedFrom} (merged into ${r.id}, which now applies to ${s.label.toLowerCase()})` : r.id}: ${r.rule}`, `Applies to: ${scopeLabel(r)} · ${checkWords(r)}. It's in every brief, shoot and judge for that scope from now on.`].join("\n");
|
|
92
|
+
}
|
|
93
|
+
if (sub === "no" || sub === "reject" || sub === "discard") {
|
|
94
|
+
if (!args[0]) throw new Error("Usage: palate rule no <id>");
|
|
95
|
+
const r = rejectRule(args[0]);
|
|
96
|
+
return `Discarded ${r.id}: ${r.rule}\nIt stays a one-off fix. palate remembers this, so the same evidence won't propose it again.`;
|
|
97
|
+
}
|
|
98
|
+
if (sub === "learn") return learnedLines(learnRules({ all: args.includes("--all") })).join("\n");
|
|
99
|
+
const all = loadRules();
|
|
100
|
+
const shown = kinds ? all.filter((r) => r.kinds.includes("all") || r.kinds.some((k) => kinds.includes(k))) : all;
|
|
101
|
+
const active = shown.filter((r) => !isProposed(r));
|
|
102
|
+
const proposed = shown.filter(isProposed);
|
|
103
|
+
if (sub === "proposed") return proposed.length ? [`# Waiting for your OK (${proposed.length}): not applied anywhere yet`, ...proposed.map(proposalLine), "", reviewHint(proposed.map((r) => r.id))].join("\n") : "Nothing waiting for your OK.";
|
|
104
|
+
if (!all.length) return 'No rules yet. Add one: palate rule add "<rule>" [--kind landing]';
|
|
105
|
+
return [
|
|
106
|
+
`# Your rules (${active.length}${kinds ? ` for ${kinds.join(", ")}` : ""}): ${slash(RULES_FILE)}`,
|
|
107
|
+
...active.map((r) => `- ${r.id} [${scopeLabel(r)}] ${r.rule}\n check: ${r.where?.component ? `the judge asks, for <${r.where.component}> only` : checkOf(r)} · from ${[r.source, ...(r.also ?? [])].join(", ")}`),
|
|
108
|
+
...(proposed.length ? ["", `## Waiting for your OK (${proposed.length}): not applied anywhere yet`, ...proposed.map(proposalLine), "", reviewHint(proposed.map((r) => r.id))] : []),
|
|
109
|
+
].join("\n");
|
|
110
|
+
}
|
package/src/loop/fix.mjs
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// `palate fix <route>`: turns the findings the user agreed with in the latest critique into a brief, most
|
|
2
|
+
// severe first, with each section's crops, and tells the agent to re-shoot and verify each one. With no
|
|
3
|
+
// critique it fixes what is measurably wrong (palate shoot's problems).
|
|
4
|
+
// `palate fix <route> --verify` re-renders the sections and puts each finding's section before | after.
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { contactSheet, cropSections, findSections, openPage, shootFull, slugOf, stamp, withBrowser } from "../look.mjs";
|
|
8
|
+
import { normalizeRoute, shoot } from "../shoot.mjs";
|
|
9
|
+
import { readJson } from "./common.mjs";
|
|
10
|
+
import { latestCritique, SEVERITIES } from "./critique.mjs";
|
|
11
|
+
import { slash } from "./craft.mjs";
|
|
12
|
+
import { projectOf, routeTags, rulesBlock } from "./rules.mjs";
|
|
13
|
+
import { latestStates, STATES } from "./states.mjs";
|
|
14
|
+
|
|
15
|
+
// shoot's ⚠ lines, each tagged with the width it was measured at.
|
|
16
|
+
function problemsOf(report) {
|
|
17
|
+
let at = "";
|
|
18
|
+
const out = [];
|
|
19
|
+
for (const l of report.split("\n")) {
|
|
20
|
+
if (l.startsWith("## ")) at = l.slice(3);
|
|
21
|
+
else if (l.startsWith("- ⚠")) out.push(`- ⚠ (${at}) ${l.slice(4)}`);
|
|
22
|
+
}
|
|
23
|
+
return out.join("\n");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// The missing states from the latest `palate states` run for the route (or a pointer to run it).
|
|
27
|
+
function statesLines(dir, route) {
|
|
28
|
+
const s = latestStates(dir, route);
|
|
29
|
+
if (!s) return ["", "## States", `Not checked yet. \`palate states ${route}\` renders empty, loading, error, long text, many items, failing images, 320 wide and forms pressed twice, and lists the missing ones.`];
|
|
30
|
+
const rec = readJson(path.join(s, "findings.json"), { findings: [] });
|
|
31
|
+
const stamp = path.basename(s);
|
|
32
|
+
if (!rec.findings.length) return ["", `## States (palate states ${stamp})`, "Every state palate could render held up."];
|
|
33
|
+
return [
|
|
34
|
+
"",
|
|
35
|
+
`## Missing states (palate states ${stamp}${rec.sheet ? `; contact sheet ${slash(rec.sheet)}` : ""})`,
|
|
36
|
+
...rec.findings.map((f) => `- ${f.id} [${f.severity}] ${f.componentLabel} · ${f.states.map((s) => STATES[s] ?? s).join(", ")}: ${f.what} Build: ${f.fix}${f.where ? ` Where: ${f.where}.` : ""}${f.crop ? ` Crop: ${slash(f.crop)}` : ""}`),
|
|
37
|
+
`The full states brief, with copy guidance: ${slash(path.join(s, "states.md"))}. Verify these with \`palate states ${route} --verify\`.`,
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Agreed findings (all of them when the user hasn't reviewed), most severe first, with their sections.
|
|
42
|
+
function plan(session) {
|
|
43
|
+
const { findings = [] } = readJson(path.join(session, "findings.json"), {});
|
|
44
|
+
const meta = readJson(path.join(session, "sections.json"), {});
|
|
45
|
+
const review = readJson(path.join(session, "review.json"), null);
|
|
46
|
+
const verdicts = review?.verdicts ?? {};
|
|
47
|
+
const reviewed = Object.values(verdicts).some((v) => v.verdict);
|
|
48
|
+
const sectionOf = (f) => {
|
|
49
|
+
const n = Number(String(f.section).match(/^\s*#?(\d+)/)?.[1]);
|
|
50
|
+
return n ? meta.sections?.find((s) => s.index === n) ?? null : meta.sections?.find((s) => s.name.toLowerCase() === String(f.section).toLowerCase()) ?? null;
|
|
51
|
+
};
|
|
52
|
+
const rank = (f) => SEVERITIES.indexOf(String(f.severity).toLowerCase()) + 1 || 2;
|
|
53
|
+
const all = findings.map((f, i) => ({ ...f, id: f.id ?? `F${i + 1}`, verdict: verdicts[f.id]?.verdict ?? null, note: verdicts[f.id]?.note ?? "", sec: sectionOf(f) })).sort((a, b) => rank(a) - rank(b));
|
|
54
|
+
return {
|
|
55
|
+
meta,
|
|
56
|
+
reviewed,
|
|
57
|
+
todo: reviewed ? all.filter((f) => f.verdict === "agree") : all,
|
|
58
|
+
skip: all.filter((f) => f.verdict === "disagree"),
|
|
59
|
+
unmarked: reviewed ? all.filter((f) => !f.verdict) : [],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function fix(dir, rawRoute, { url, verify = false } = {}) {
|
|
64
|
+
const route = normalizeRoute(rawRoute);
|
|
65
|
+
const session = latestCritique(dir, route, { withFindings: true });
|
|
66
|
+
if (verify) return verifyFixes(dir, route, session, { url });
|
|
67
|
+
|
|
68
|
+
const shot = await shoot(dir, route, { url });
|
|
69
|
+
const problems = problemsOf(shot.report);
|
|
70
|
+
const measured = /⚠/.test(problems);
|
|
71
|
+
// The user's rules for this page, marked where the shoot just measured them failing.
|
|
72
|
+
const mine = rulesBlock(shot.rules?.tags ?? routeTags(dir, route), { results: shot.rules?.results, route, project: projectOf(dir) });
|
|
73
|
+
if (!session || !fs.existsSync(path.join(session, "findings.json"))) {
|
|
74
|
+
const out = path.join(dir, ".palate", "fix", slugOf(route), stamp());
|
|
75
|
+
fs.mkdirSync(out, { recursive: true });
|
|
76
|
+
const brief = [
|
|
77
|
+
mine.line,
|
|
78
|
+
"",
|
|
79
|
+
`# Fix: ${route} (what is measurably wrong)`,
|
|
80
|
+
"",
|
|
81
|
+
...mine.lines,
|
|
82
|
+
`No critique with findings for ${route} yet, so this fixes what palate can measure. For a designer's review first: palate critique ${route}.`,
|
|
83
|
+
"",
|
|
84
|
+
`Screenshots: ${shot.files.map(slash).join(", ")}`,
|
|
85
|
+
"",
|
|
86
|
+
measured ? problems : "palate shoot measured no problems. Open the screenshots and fix the three biggest problems you see, or run palate critique for a full review.",
|
|
87
|
+
...statesLines(dir, route),
|
|
88
|
+
"",
|
|
89
|
+
"Fix each ⚠ at its cause (the element, not a global override), smallest change first. Keep the design's idea and layout.",
|
|
90
|
+
`Then run \`palate shoot ${route}\` again: every ⚠ above should be gone. Run the project's typecheck. Don't commit.`,
|
|
91
|
+
].join("\n");
|
|
92
|
+
fs.writeFileSync(path.join(out, "fix.md"), brief);
|
|
93
|
+
return `${brief}\n\n(Brief saved to ${slash(path.join(out, "fix.md"))})`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const { meta, reviewed, todo, skip, unmarked } = plan(session);
|
|
97
|
+
const full = path.join(session, "full-1440.png");
|
|
98
|
+
const crops = (f) => (f.sec ? Object.entries(f.sec.crops ?? {}).filter(([, c]) => c).sort((a, b) => b[0] - a[0]).map(([w, c]) => `${w}px ${slash(c)}`).join(" · ") : fs.existsSync(full) ? `full page ${slash(full)}` : "the full page");
|
|
99
|
+
const brief = [
|
|
100
|
+
mine.line,
|
|
101
|
+
"",
|
|
102
|
+
`# Fix: ${route}, from the critique of ${path.basename(session)}`,
|
|
103
|
+
"",
|
|
104
|
+
...mine.lines,
|
|
105
|
+
reviewed ? `The user agreed with ${todo.length} finding(s)${skip.length ? ` and disagreed with ${skip.length}` : ""}. Fix the agreed ones, most severe first.` : `The user hasn't reviewed these findings yet (palate critique --findings ${slash(path.join(session, "findings.json"))} opens the board). Fixing all ${todo.length}, most severe first; ask the user before the ideas.`,
|
|
106
|
+
"",
|
|
107
|
+
"## Findings to fix",
|
|
108
|
+
...todo.map((f, i) => [
|
|
109
|
+
`### ${i + 1}. ${f.id} [${f.severity}] ${f.sec ? `section ${f.sec.index}, ${f.sec.name}` : "the whole page"}`,
|
|
110
|
+
`- What: ${f.what}`,
|
|
111
|
+
f.why ? `- Why: ${f.why}` : "",
|
|
112
|
+
`- Fix: ${f.fix}`,
|
|
113
|
+
f.note ? `- The user's note: ${f.note} (this overrides the fix where they differ)` : "",
|
|
114
|
+
`- Before: ${crops(f)}`,
|
|
115
|
+
].filter(Boolean).join("\n")),
|
|
116
|
+
skip.length ? `\n## Leave these alone (the user disagreed)\n${skip.map((f) => `- ${f.id}: ${f.what}${f.note ? ` (their note: ${f.note})` : ""}`).join("\n")}` : "",
|
|
117
|
+
unmarked.length ? `\n## Not marked by the user (skip unless trivial and clearly right)\n${unmarked.map((f) => `- ${f.id} [${f.severity}]: ${f.what}`).join("\n")}` : "",
|
|
118
|
+
measured ? `\n## Also measurably wrong now (palate shoot)\n${problems}` : "",
|
|
119
|
+
...statesLines(dir, route),
|
|
120
|
+
"",
|
|
121
|
+
"## How",
|
|
122
|
+
"- One finding at a time, in this order. Change what the finding names; keep the rest of the design, its idea and its content.",
|
|
123
|
+
"- No fix may break one of your rules above; a rule marked FAILS NOW is a finding too.",
|
|
124
|
+
"- Ideas (severity idea) are bigger changes: build them only if the user agreed with them, and keep them to the section named.",
|
|
125
|
+
"- Use the project's tokens and components. Real content only. Don't install packages without asking.",
|
|
126
|
+
`- After each section you change, run \`palate shoot ${route}\` and look at that section at both widths.`,
|
|
127
|
+
"",
|
|
128
|
+
"## Verify",
|
|
129
|
+
`When all are done: \`palate fix ${route} --verify\`. It re-renders every section with a finding and puts it before | after. Open each pair and report, per finding: fixed, partly, or not, in one line. Fix what isn't, then run the project's typecheck. Don't commit.`,
|
|
130
|
+
]
|
|
131
|
+
.filter((l) => l !== "")
|
|
132
|
+
.join("\n")
|
|
133
|
+
.replace(/\n(#{2,3} )/g, "\n\n$1");
|
|
134
|
+
fs.writeFileSync(path.join(session, "fix.md"), brief);
|
|
135
|
+
return `${brief}\n\n(Brief saved to ${slash(path.join(session, "fix.md"))})`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function verifyFixes(dir, route, session, { url }) {
|
|
139
|
+
if (!session || !fs.existsSync(path.join(session, "findings.json"))) {
|
|
140
|
+
const shot = await shoot(dir, route, { url });
|
|
141
|
+
return `# Verify: ${route}\n\n${problemsOf(shot.report) || "No measurable problems left."}\n\nScreenshots: ${shot.files.map(slash).join(", ")}`;
|
|
142
|
+
}
|
|
143
|
+
const { meta, todo } = plan(session);
|
|
144
|
+
const out = path.join(session, `after-${stamp()}`);
|
|
145
|
+
const { pairs, pagePairs, shotReport } = await withBrowser(dir, { url }, async ({ base, browser }) => {
|
|
146
|
+
const shotReport = (await shoot(dir, route, { url: base })).report;
|
|
147
|
+
const now = {};
|
|
148
|
+
for (const w of [1440, 390]) {
|
|
149
|
+
const { page, ctx } = await openPage(browser, base, route, { width: w });
|
|
150
|
+
now[w] = await cropSections(page, await findSections(page), out, `w${w}`);
|
|
151
|
+
if (w === 1440) await shootFull(page, path.join(out, "full-1440.png"));
|
|
152
|
+
await ctx.close();
|
|
153
|
+
}
|
|
154
|
+
// The same section after the changes: by id, then heading, then position.
|
|
155
|
+
const match = (w, s) => now[w].find((x) => s.id && x.id === s.id) ?? now[w].find((x) => x.name === s.name) ?? now[w].find((x) => x.index === s.index);
|
|
156
|
+
const bySection = new Map();
|
|
157
|
+
for (const f of todo) {
|
|
158
|
+
const key = f.sec?.index ?? 0;
|
|
159
|
+
if (!bySection.has(key)) bySection.set(key, { sec: f.sec, ids: [] });
|
|
160
|
+
bySection.get(key).ids.push(f.id);
|
|
161
|
+
}
|
|
162
|
+
const rows = [];
|
|
163
|
+
for (const [, g] of bySection) {
|
|
164
|
+
if (!g.sec) continue;
|
|
165
|
+
for (const w of [1440, 390]) {
|
|
166
|
+
const before = g.sec.crops?.[w];
|
|
167
|
+
const after = match(w, g.sec)?.file;
|
|
168
|
+
rows.push({ label: `Section ${g.sec.index} · ${g.sec.name.slice(0, 50)} · ${w}px · ${g.ids.join(", ")}`, cells: [{ caption: "before", file: before && fs.existsSync(before) ? before : null, note: "no before crop" }, { caption: "after", file: after ?? null, note: "section not found now" }] });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const pairs = rows.length ? await contactSheet(browser, rows, path.join(out, "before-after.png"), { cell: 620, maxCell: 520 }) : null;
|
|
172
|
+
// Whole-page findings: the full page, before | after.
|
|
173
|
+
const fullBefore = path.join(session, "full-1440.png");
|
|
174
|
+
const pagePairs = todo.some((f) => !f.sec) && fs.existsSync(fullBefore) ? await contactSheet(browser, [{ label: `The whole page · ${todo.filter((f) => !f.sec).map((f) => f.id).join(", ")}`, cells: [{ caption: "before", file: fullBefore }, { caption: "after", file: path.join(out, "full-1440.png") }] }], path.join(out, "page-before-after.png"), { cell: 560, maxCell: 6000 }) : null;
|
|
175
|
+
return { pairs, pagePairs, shotReport };
|
|
176
|
+
});
|
|
177
|
+
const text = [
|
|
178
|
+
`# Verify the fixes: ${route}`,
|
|
179
|
+
"",
|
|
180
|
+
pairs ? `Before | after for every section with a finding: ${slash(pairs)} (crops in ${slash(out)}).` : "",
|
|
181
|
+
pagePairs ? `The whole page, before | after: ${slash(pagePairs)}.` : "",
|
|
182
|
+
"",
|
|
183
|
+
"For each finding, open the pair and answer fixed, partly or not:",
|
|
184
|
+
...todo.map((f) => `- ${f.id} [${f.severity}] ${f.sec ? `section ${f.sec.index}` : "page"}: ${f.what}`),
|
|
185
|
+
"",
|
|
186
|
+
"## Measured now (palate shoot)",
|
|
187
|
+
problemsOf(shotReport) || "No measurable problems.",
|
|
188
|
+
"",
|
|
189
|
+
`Fix anything not fixed, then run this again. When all are fixed: palate taste learn (the user's verdicts on this critique are in their taste log).`,
|
|
190
|
+
latestStates(dir, route) ? `The missing states are verified separately: palate states ${route} --verify (before | after per state, measured).` : "",
|
|
191
|
+
].join("\n");
|
|
192
|
+
fs.writeFileSync(path.join(out, "verify.md"), text);
|
|
193
|
+
return text;
|
|
194
|
+
}
|