@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,70 @@
|
|
|
1
|
+
// `palate animate <route>`: a motion pass that serves the content. Runs the motion check (frame strips,
|
|
2
|
+
// invisible content, layout shift, reduced motion, no-JS), finds the motion skills installed here (Emil
|
|
3
|
+
// Kowalski's emil-design-eng, Jakub Krehel's better-ui / better-motion), and writes a brief: where motion
|
|
4
|
+
// would explain something, how to build it so content never hides, and how to verify it.
|
|
5
|
+
// `palate animate <route> --check` runs only the check, to verify the pass.
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { slugOf, stamp } from "../look.mjs";
|
|
9
|
+
import { motionCheck } from "../motion.mjs";
|
|
10
|
+
import { normalizeRoute } from "../shoot.mjs";
|
|
11
|
+
import { craftRubric, skillFiles, slash } from "./craft.mjs";
|
|
12
|
+
|
|
13
|
+
const SKILLS = [
|
|
14
|
+
{ id: "emil-design-eng", who: "Emil Kowalski", use: "what animates and why, duration and easing, enter/exit, press feedback, interruptibility, reduced motion" },
|
|
15
|
+
{ id: "better-motion", who: "Jakub Krehel", use: "motion values and patterns" },
|
|
16
|
+
{ id: "better-ui", who: "Jakub Krehel", use: "exact values for motion, icon states, shadows and radii" },
|
|
17
|
+
{ id: "review-animations", who: "Emil Kowalski's bar", use: "a strict review of the motion code once it's written" },
|
|
18
|
+
];
|
|
19
|
+
const LIBS = [["motion", "Motion (motion/react)"], ["framer-motion", "Framer Motion"], ["gsap", "GSAP"], ["@react-spring/web", "React Spring"], ["@formkit/auto-animate", "auto-animate"], ["tailwindcss-animate", "tailwindcss-animate"], ["tw-animate-css", "tw-animate-css"]];
|
|
20
|
+
|
|
21
|
+
export async function animate(dir, rawRoute, { url, checkOnly = false } = {}) {
|
|
22
|
+
const route = normalizeRoute(rawRoute);
|
|
23
|
+
const session = path.join(dir, ".palate", "motion", slugOf(route), stamp());
|
|
24
|
+
const check = await motionCheck(dir, route, { url, out: session });
|
|
25
|
+
if (checkOnly) return `${check.report}\n\nOpen the strips and confirm: each motion explains something, content is readable in every frame after 400ms, nothing jumps.`;
|
|
26
|
+
|
|
27
|
+
let deps = {};
|
|
28
|
+
try {
|
|
29
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf8"));
|
|
30
|
+
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
31
|
+
} catch {}
|
|
32
|
+
const libs = LIBS.filter(([p]) => p in deps).map(([, n]) => n);
|
|
33
|
+
const skills = skillFiles(dir, SKILLS.map((s) => s.id)).map((s, i) => ({ ...SKILLS[i], file: s.file }));
|
|
34
|
+
const rubric = craftRubric(/motion|anim|demo/i);
|
|
35
|
+
const still = check.data.sections.filter((s) => !s.moved);
|
|
36
|
+
const brief = [
|
|
37
|
+
`# Animate: ${route}`,
|
|
38
|
+
"",
|
|
39
|
+
"A motion pass that serves the content: motion that explains hierarchy, state and cause, never decoration. Keep the layout and the content; add or fix motion only.",
|
|
40
|
+
"",
|
|
41
|
+
check.report,
|
|
42
|
+
"",
|
|
43
|
+
"## Where motion should go",
|
|
44
|
+
check.data.static ? "The page is static: nothing moves on load or on scroll. Add motion in this order, and stop when the page feels alive (three or four well-placed motions beat motion everywhere):" : "Add or fix motion in this order:",
|
|
45
|
+
"1. **The product doing its job.** If a section shows the product as a static picture, make one of them live: rebuild the key moment in real UI and animate the state change (e.g. variants appear, one is chosen, the result lands). This is the most persuasive motion on a page.",
|
|
46
|
+
"2. **The first screen.** One short entrance that sets the reading order (headline, then sub-copy, then the action), 300–500ms in total, 8–12px of travel, staggered 40–60ms. Content is visible in the HTML before any script runs.",
|
|
47
|
+
`3. **Sections as they arrive.** Scroll-linked reveals for sections whose content has an order to it${still.length ? ` (still now: ${still.map((s) => `${s.index} ${s.name.slice(0, 30)}`).join(", ")})` : ""}. Reveal once, small travel, never a whole section fading from nothing.`,
|
|
48
|
+
"4. **State transitions.** Toggles, tabs, form submit, copy-to-clipboard, expanding rows: animate between states so the change is understood (cross-fade, height with FLIP or Motion layout, icon swaps with a short blur).",
|
|
49
|
+
"5. **Hover and press feedback.** Buttons press to `scale(0.97)` over 100ms; links and cards shift colour or lift 1–2px over 150ms, hover inside `@media (hover: hover)`.",
|
|
50
|
+
"",
|
|
51
|
+
"## How to build it so content never hides",
|
|
52
|
+
"- Start from visible. Never render `opacity: 0` (or `initial={{ opacity: 0 }}` in Motion) into server HTML for content: with JS slow, failed or off, it stays hidden. Either animate with CSS (`@keyframes` with `animation-fill-mode: both`, which runs without JS), or hide only under a class a script sets (`html.motion-ok .reveal { … }`) and inside `@media (prefers-reduced-motion: no-preference)`.",
|
|
53
|
+
"- Scroll reveals: CSS scroll-driven animations (`animation-timeline: view()`) inside `@supports` and the no-preference media query, or an IntersectionObserver that adds a class (threshold ~0.15, once). Content must be fully visible within 400ms of entering the viewport, and visible at the end of the page without scrolling back.",
|
|
54
|
+
"- Animate only `transform` and `opacity` (and `filter: blur()` sparingly). No `transition: all`. No layout properties without FLIP.",
|
|
55
|
+
"- Durations: 100–200ms for feedback, 200–300ms for state changes, at most 500ms for entrances. Ease-out for things arriving (e.g. `cubic-bezier(0.23, 1, 0.32, 1)`), ease-in-out for things moving on screen, never linear except spinners.",
|
|
56
|
+
"- `prefers-reduced-motion: reduce`: no travel, no scale, no parallax; keep instant changes or short opacity cross-fades.",
|
|
57
|
+
"- No layout shift: reserve space for anything that animates in (fixed heights, aspect-ratio, absolutely positioned overlays).",
|
|
58
|
+
libs.length ? `- This project already has ${libs.join(", ")}: use it, don't add another library.` : "- No motion library installed: use CSS (transitions, @keyframes, scroll-driven animations). Ask the user before installing one.",
|
|
59
|
+
"",
|
|
60
|
+
"## Skills to apply",
|
|
61
|
+
...skills.map((s) => `- ${s.who}'s ${s.id}: ${s.use}. ${s.file ? `Read ${slash(s.file)} and apply it.` : "Not installed; apply the same principles from your own knowledge."}`),
|
|
62
|
+
rubric.text ? `\n## Motion checklist (kb/craft)\n${rubric.text}` : "",
|
|
63
|
+
"",
|
|
64
|
+
"## Verify",
|
|
65
|
+
`Run \`palate animate ${route} --check\` after the pass. Open both strips: the motion you added must show between frames, every frame from 400ms on must be readable, and the check must report no hidden content (normal, reduced motion and JavaScript off) and CLS under 0.05. Run the project's typecheck. Keep a motion only if it makes the page clearer.`,
|
|
66
|
+
].join("\n");
|
|
67
|
+
fs.writeFileSync(path.join(session, "brief.md"), brief);
|
|
68
|
+
return `${brief}\n\n(Brief saved to ${slash(path.join(session, "brief.md"))})`;
|
|
69
|
+
}
|
|
70
|
+
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// `palate direction "<job>" --from-research <name>`: ideation after research. The brief asks for 3 art directions,
|
|
2
|
+
// each with a name, a metaphor, ONE signature moment (a signature move from the moves library, adapted to this
|
|
3
|
+
// product), type and colour drawn from the metaphor (or, in a project with a brand, the brand kept and the metaphor
|
|
4
|
+
// living inside it), a section plan, a provenance line ("rhythm from R2, texture idea from R4, nothing copied") and a
|
|
5
|
+
// rough wireframe. A project with no brand gets a complete starter system per direction (AA-checked colours,
|
|
6
|
+
// licence-safe type with its scale, radii, spacing, motion character, licence-safe imagery).
|
|
7
|
+
// The agent drives: palate picks the direction itself when the user's taste for this kind of screen is strong and
|
|
8
|
+
// one direction clearly leads, or when the user said "just build it"; the picker opens only for a real judgement
|
|
9
|
+
// call (no or weak history, directions scoring close, or the user asked to choose), with the reason in one line.
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import { brandOf } from "../context.mjs";
|
|
13
|
+
import { normalizeRoute } from "../shoot.mjs";
|
|
14
|
+
import { TASTE_DIR } from "./common.mjs";
|
|
15
|
+
import { costLine, estimate, logCost } from "./cost.mjs";
|
|
16
|
+
import { tasteFor } from "./craft.mjs";
|
|
17
|
+
import { alreadyMade, projectId } from "./layouts.mjs";
|
|
18
|
+
import { describePlanned, ideaLook, recentLooks, sharedAxes } from "./lookplan.mjs";
|
|
19
|
+
import { plan } from "./plan.mjs";
|
|
20
|
+
import { kindTags, projectOf, rulesFor } from "./rules.mjs";
|
|
21
|
+
import { LICENCE_RULE, loadResearch, matchMovesSafe, moveExists, researchNotes, tasteHistory, understandingLines, validateStarter } from "./research.mjs";
|
|
22
|
+
|
|
23
|
+
const slash = (p) => String(p).replace(/\\/g, "/");
|
|
24
|
+
const uniq = (a) => [...new Set(a.filter(Boolean))];
|
|
25
|
+
const words = (s) => (String(s ?? "").toLowerCase().match(/[a-z]{4,}/g) ?? []);
|
|
26
|
+
const STOP = new Set(["with", "that", "this", "from", "they", "their", "them", "than", "into", "what", "when", "only", "each", "every", "over", "under", "also", "more", "less", "most", "page", "pages", "screen", "screens", "section", "sections", "wins", "loses", "winner", "lost", "variants", "variant", "loop", "plans", "all", "the", "where", "there", "which", "would", "could", "about", "other", "every", "everything", "first", "three", "above", "below", "product", "products", "shows", "these", "those", "while", "after", "before", "being", "still", "really", "whole", "people", "things"]);
|
|
27
|
+
|
|
28
|
+
// The signature moves that fit this job (signature: true), the user's past choices first.
|
|
29
|
+
export function signatureMoves(u, { history = tasteHistory(u.screen), limit = 6 } = {}) {
|
|
30
|
+
let rows = matchMovesSafe({ tags: u.tags, signature: true, limit: 12 });
|
|
31
|
+
if (rows.length < 3) rows = [...rows, ...matchMovesSafe({ signature: true, limit: 12 }).filter((m) => !rows.some((r) => r.id === m.id))];
|
|
32
|
+
const past = history.moves ?? {};
|
|
33
|
+
return rows
|
|
34
|
+
.map((m) => ({ ...m, chosenBefore: past[m.id] ?? 0 }))
|
|
35
|
+
.sort((a, b) => b.chosenBefore - a.chosenBefore || b.score - a.score)
|
|
36
|
+
.slice(0, limit);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// The 3 art directions brief. Writes <project>/.palate/direction/<name>/{brief.md,direction.json}.
|
|
40
|
+
export function artDirectionBrief(dir, job, { route, name, fromResearch } = {}) {
|
|
41
|
+
const d = loadResearch(dir, fromResearch);
|
|
42
|
+
if (!d) throw new Error(`No research ${fromResearch && fromResearch !== "latest" ? `"${fromResearch}" ` : ""}in this project. Run palate research "<job>" first (MCP: palate_research).`);
|
|
43
|
+
if (d.stage !== "done") throw new Error(`Research "${d.name}" has only its first step: call palate_research again with the URLs from the searches (or urls: []).`);
|
|
44
|
+
const u = d.understanding;
|
|
45
|
+
// A route stored by older research may be a Git Bash path ("C:/Program Files/Git/"): refused here, never copied on.
|
|
46
|
+
route = route ? normalizeRoute(route) : u.route ? normalizeRoute(u.route) : undefined;
|
|
47
|
+
name ??= `${d.name}-directions`;
|
|
48
|
+
const session = path.join(dir, ".palate", "direction", name);
|
|
49
|
+
fs.mkdirSync(session, { recursive: true });
|
|
50
|
+
fs.writeFileSync(path.join(dir, ".palate", ".gitignore"), "*\n");
|
|
51
|
+
const brand = brandOf(dir, `${job} ${u.job}`);
|
|
52
|
+
const history = tasteHistory(u.screen);
|
|
53
|
+
const sigs = signatureMoves(u, { history });
|
|
54
|
+
const tags = kindTags({ screen: u.screen, kind: "marketing", route: route ?? u.route, words: job.slice(0, 160) });
|
|
55
|
+
const rules = rulesFor(tags, { route: route ?? u.route, project: projectOf(dir) });
|
|
56
|
+
// Only the rules that hold everywhere: type and colour come from the metaphor, not from past projects.
|
|
57
|
+
const general = tasteFor("", { sections: 0, lean: true });
|
|
58
|
+
const past = alreadyMade({ dir, kind: "marketing", screen: u.screen, limit: 4 }).filter((r) => r.moves);
|
|
59
|
+
const chosenBefore = sigs.filter((m) => m.chosenBefore > 0);
|
|
60
|
+
const ideasFile = path.join(session, "ideas.json");
|
|
61
|
+
const scratch = brand.mode === "scratch";
|
|
62
|
+
const recentLooksLines = recentLooks({ excludePid: projectId(dir), limit: 6 }).map((x) => `- ${x.project}: ${describePlanned(x.look)}`);
|
|
63
|
+
const brief = [
|
|
64
|
+
`# Art directions: ${job}`,
|
|
65
|
+
"",
|
|
66
|
+
`From research "${d.name}": ${d.kept.length} references kept of ${d.looked} looked at (${slash(path.join(d.dir, "research.md"))}${d.contact ? `; contact sheet ${slash(d.contact)}` : ""}).`,
|
|
67
|
+
...understandingLines(u),
|
|
68
|
+
"",
|
|
69
|
+
"## Your answer: 3 art directions",
|
|
70
|
+
"Three different answers, not three skins of one: each has its own metaphor, its own signature moment and its own first screen. Order them from the safest to the boldest. They must span different visual worlds: no two share both the ground (white, light, dark, a colour, a photograph) and the headline's type genre (serif, sans, slab, mono, display, script), and at least one leads with imagery or type instead of a product frame where the category allows it. None may be palate's house look (a warm off-white page with grain, a serif headline, a split hero with a framed card, a pill button top right): palate refuses it at the blueprint.",
|
|
71
|
+
...(recentLooksLines.length ? ["palate's recent pages, for reference (directions unlike these rank higher):", ...recentLooksLines] : []),
|
|
72
|
+
"Each has:",
|
|
73
|
+
"- **name** (2–4 words) and **metaphor**: one sentence, an image the whole page hangs on (the working metaphor above can be one of them).",
|
|
74
|
+
"- **signature**: `{ \"move\": \"<a move id from the list below>\", \"moment\": \"…\" }`. ONE signature moment, adapted to this product: what the visitor sees and does, where on the page, and why it says what the product does. It will be checked on the built page.",
|
|
75
|
+
scratch
|
|
76
|
+
? "- **starter**: a complete starter system drawn from the metaphor (this project has no brand yet, see below): colours, type, radius, spacing, motion, imagery."
|
|
77
|
+
: "- **brand**: one sentence on how the direction lives inside the project's brand (which of its tokens carry the metaphor). No new font, no new brand colour.",
|
|
78
|
+
"- **sections**: the section plan, 5–8 short names in order.",
|
|
79
|
+
"- **provenance**: one line naming what each idea is learned from, by reference id, e.g. \"rhythm from R2, texture idea from R4, nothing copied\".",
|
|
80
|
+
"- **summary**: 2 sentences: what the visitor sees first and why it fits the product.",
|
|
81
|
+
"- **wireframe**: a rough ASCII sketch of the first screen and the signature moment (at most 16 lines × 64 columns).",
|
|
82
|
+
`- ${LICENCE_RULE}`,
|
|
83
|
+
"- Avoid what the competitors all do (below) unless a direction turns it into something they don't do.",
|
|
84
|
+
"",
|
|
85
|
+
"## Signature moves that fit (moves library, signature: true)",
|
|
86
|
+
...sigs.map((m) => `- \`${m.id}\` ${m.name}: ${m.reason}${m.chosenBefore ? ` · the user chose it before (${m.chosenBefore}×)` : ""}`),
|
|
87
|
+
"Read a move in full with palate moves show <id> before you adapt it.",
|
|
88
|
+
"",
|
|
89
|
+
...(chosenBefore.length || history.chosen
|
|
90
|
+
? [
|
|
91
|
+
"## What this user keeps choosing for this kind of screen",
|
|
92
|
+
`${history.chosen} direction(s) chosen before${chosenBefore.length ? `; signature moves: ${chosenBefore.map((m) => `${m.id} (${m.chosenBefore}×)`).join(", ")}` : ""}. Lead with what they keep choosing in one direction, made new for this product: never a copy of a past project.`,
|
|
93
|
+
"",
|
|
94
|
+
]
|
|
95
|
+
: []),
|
|
96
|
+
scratch
|
|
97
|
+
? [
|
|
98
|
+
"## No brand yet: each direction defines a starter system",
|
|
99
|
+
brand.line,
|
|
100
|
+
"Each `starter` is complete and drawn from its metaphor, not from the user's past projects:",
|
|
101
|
+
'- `colours`: hex values for at least `bg`, `surface`, `text`, `muted`, `accent`, `on-accent`, `line`. palate checks AA: text and muted on bg ≥ 4.5:1, accent on bg ≥ 3:1, on-accent on accent ≥ 4.5:1.',
|
|
102
|
+
'- `type`: `{ "display": "…", "body": "…", "mono": "…", "source": "google-fonts" | "ofl" | "system", "scale": [12, 14, 16, 20, 28, 40, 64] }`: licence-safe families only (Google Fonts / OFL or system). No paid fonts, and none of the fonts measured on the references.',
|
|
103
|
+
'- `radius` (e.g. `[4, 8, 16]`), `spacing` (`{ "unit": 8, "scale": [4, 8, 12, 16, 24, 32, 48, 64, 96] }`), `motion` (its character: "calm: 280ms ease-out, one thing moves at a time"), `imagery` (licence-safe: built in code (SVG, CSS, canvas), CC0 / public-domain art, or generated patterns).',
|
|
104
|
+
].join("\n")
|
|
105
|
+
: ["## The project's brand: work inside it", brand.line, `Tokens in ${brand.tokenFiles.join(", ") || "the project's CSS"}: ${brand.colours.slice(0, 12).map((c) => `${c.name} ${c.value}`).join(", ")}${brand.colours.length > 12 ? " …" : ""}.`, "Keep the palette tokens, the fonts and the components; the metaphor and the signature moment are adapted to them. Propose a new colour or type only if the user asks for a rebrand."].join("\n"),
|
|
106
|
+
"",
|
|
107
|
+
...(past.length ? ["## Already made for this kind of screen (don't take type or colour from these)", ...past.map((r) => `- ${r.project} ${r.route}: type ${r.moves.type}; palette ${r.moves.palette}`), ""] : []),
|
|
108
|
+
"## What the research found (abstract notes)",
|
|
109
|
+
...researchNotes(d),
|
|
110
|
+
"",
|
|
111
|
+
...(rules.length ? ["## The user's rules (every direction keeps them)", ...rules.map((x) => `- ${x.id} ${x.rule}`), ""] : []),
|
|
112
|
+
...(general ? ["## Whose taste (the rules that hold everywhere)", general.trim(), ""] : []),
|
|
113
|
+
`Write them to ${slash(ideasFile)}:`,
|
|
114
|
+
"```json",
|
|
115
|
+
scratch
|
|
116
|
+
? '[{ "name": "…", "metaphor": "…", "signature": { "move": "<id>", "moment": "…" }, "starter": { "colours": { "bg": "#…", "surface": "#…", "text": "#…", "muted": "#…", "accent": "#…", "on-accent": "#…", "line": "#…" }, "type": { "display": "…", "body": "…", "source": "google-fonts", "scale": [13, 16, 20, 28, 40, 64] }, "radius": [4, 8, 16], "spacing": { "unit": 8, "scale": [8, 16, 24, 40, 64, 96] }, "motion": "…", "imagery": "…" }, "sections": ["…"], "provenance": "… nothing copied", "summary": "…", "wireframe": "…", "format": "ascii" }, …]'
|
|
117
|
+
: '[{ "name": "…", "metaphor": "…", "signature": { "move": "<id>", "moment": "…" }, "brand": "…", "sections": ["…"], "provenance": "… nothing copied", "summary": "…", "wireframe": "…", "format": "ascii" }, …]',
|
|
118
|
+
"```",
|
|
119
|
+
`Then palate_direction with the ideas (CLI: palate direction --ideas ${slash(ideasFile)}). palate picks one itself when the user's taste is strong and one direction clearly leads, or when they said "just build it" (choose: "auto"); otherwise it opens the picker in their browser and says why. Don't ask the user which one in chat.`,
|
|
120
|
+
].join("\n");
|
|
121
|
+
fs.writeFileSync(path.join(session, "brief.md"), brief);
|
|
122
|
+
const cost = estimate({ mode: "direction", briefs: [brief] });
|
|
123
|
+
fs.writeFileSync(path.join(session, "direction.json"), JSON.stringify({ name, problem: job.trim(), route: route ?? u.route ?? null, exists: false, tags, screen: u.screen, research: d.name, brand: brand.mode, brandLine: brand.line, rebrand: brand.rebrand, moveTags: u.tags, signatures: sigs.map((m) => m.id), created: new Date().toISOString(), cost, ideas: null, chosen: null }, null, 2));
|
|
124
|
+
logCost(dir, name, "direction", cost, { research: d.name });
|
|
125
|
+
return [brief, "", "---", `Brief: ${slash(path.join(session, "brief.md"))}`, costLine(cost)].join("\n");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Ideas from research: every field there and sound. Throws with every problem at once, so one retry fixes them.
|
|
129
|
+
export function normalizeArtIdeas(raw, meta) {
|
|
130
|
+
const list = Array.isArray(raw) ? raw : raw?.ideas;
|
|
131
|
+
if (!Array.isArray(list) || list.length < 2 || list.length > 4) throw new Error("Give 3 art directions (2–4 at most).");
|
|
132
|
+
const problems = [];
|
|
133
|
+
const warnings = [];
|
|
134
|
+
const scratch = meta.brand === "scratch";
|
|
135
|
+
const out = list.map((x, i) => {
|
|
136
|
+
const n = `Direction ${i + 1}${x?.name ? ` (${x.name})` : ""}`;
|
|
137
|
+
for (const k of ["name", "metaphor", "provenance", "wireframe"]) if (!x?.[k]) problems.push(`${n}: needs ${k}`);
|
|
138
|
+
if (!x?.signature?.move || !x?.signature?.moment) problems.push(`${n}: needs signature { move, moment }`);
|
|
139
|
+
else if (!moveExists(x.signature.move)) warnings.push(`${n}: "${x.signature.move}" isn't in the moves library; palate will check the moment by its description`);
|
|
140
|
+
if (!Array.isArray(x?.sections) || x.sections.length < 3) problems.push(`${n}: needs a section plan (sections, 3+ names in order)`);
|
|
141
|
+
let starter = null;
|
|
142
|
+
if (scratch) {
|
|
143
|
+
const v = validateStarter(x?.starter);
|
|
144
|
+
if (!v.ok) problems.push(...v.problems.map((p) => `${n}: starter: ${p}`));
|
|
145
|
+
warnings.push(...v.warnings.map((w) => `${n}: ${w}`));
|
|
146
|
+
starter = x?.starter ? { ...x.starter, checks: v.checks } : null;
|
|
147
|
+
} else {
|
|
148
|
+
if (x?.starter && !meta.rebrand) problems.push(`${n}: this project has a brand (${meta.brandLine}); keep its tokens and say how the direction lives inside them (brand), or ask the user whether they want a rebrand`);
|
|
149
|
+
if (!x?.brand) problems.push(`${n}: needs brand: how it lives inside the project's tokens`);
|
|
150
|
+
}
|
|
151
|
+
const provenance = x?.provenance ? (/nothing copied/i.test(x.provenance) ? String(x.provenance).trim() : `${String(x.provenance).trim().replace(/[.;,]$/, "")}, nothing copied`) : "";
|
|
152
|
+
const format = x?.format === "html" || (!x?.format && /^\s*<[a-z]/i.test(x?.wireframe ?? "")) ? "html" : "ascii";
|
|
153
|
+
return {
|
|
154
|
+
id: `d${i + 1}`,
|
|
155
|
+
name: String(x?.name ?? "").trim(),
|
|
156
|
+
summary: String(x?.summary ?? `${x?.metaphor ?? ""} Signature: ${x?.signature?.moment ?? ""}`).trim(),
|
|
157
|
+
metaphor: String(x?.metaphor ?? "").trim(),
|
|
158
|
+
signature: x?.signature ? { move: String(x.signature.move).trim(), moment: String(x.signature.moment).trim() } : null,
|
|
159
|
+
brand: scratch ? null : String(x?.brand ?? "").trim(),
|
|
160
|
+
starter,
|
|
161
|
+
sections: (x?.sections ?? []).map(String),
|
|
162
|
+
provenance,
|
|
163
|
+
wireframe: String(x?.wireframe ?? "").replace(/\s+$/, ""),
|
|
164
|
+
format,
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
// Different visual worlds: two directions may not share both the ground and the headline's type genre.
|
|
168
|
+
if (scratch) {
|
|
169
|
+
const looks = out.map((x) => ideaLook(x));
|
|
170
|
+
for (let i = 0; i < looks.length; i++)
|
|
171
|
+
for (let j = i + 1; j < looks.length; j++) {
|
|
172
|
+
const [a, b] = [looks[i], looks[j]];
|
|
173
|
+
const sameGround = a.ground && b.ground && (a.ground === b.ground || (a.ground.startsWith("light") && b.ground.startsWith("light")) || [a.ground, b.ground].every((g) => ["white", "light-neutral", "light-warm", "light-cool"].includes(g)));
|
|
174
|
+
const sameType = a.display.genre !== "unknown" && a.display.genre === b.display.genre;
|
|
175
|
+
if (sameGround && sameType) problems.push(`${out[i].name} and ${out[j].name} share both the ground (${a.ground}/${b.ground}) and the headline's type genre (${a.display.genre}): make them different visual worlds`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (problems.length) throw new Error(`The art directions need fixing before the user sees them:\n- ${problems.join("\n- ")}`);
|
|
179
|
+
return Object.assign(out, { warnings });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// How well each direction fits the user's taste: signature fit for the job, the moves they chose before, their
|
|
183
|
+
// profile's wins and losses, and their rules (an idea that names what a rule forbids loses a lot).
|
|
184
|
+
export function scoreIdeas(ideas, meta, { recent = [], history = tasteHistory(meta.screen), profile = fs.existsSync(path.join(TASTE_DIR, "profile.md")) ? fs.readFileSync(path.join(TASTE_DIR, "profile.md"), "utf8") : "", rules = rulesFor(meta.tags ?? ["all"], { route: meta.route, project: meta.project }) } = {}) {
|
|
185
|
+
const fit = Object.fromEntries(matchMovesSafe({ tags: meta.moveTags ?? [], signature: true, limit: 200 }).map((m) => [m.id, m.score]));
|
|
186
|
+
const top = Math.max(1, ...Object.values(fit));
|
|
187
|
+
const pick = (re) => uniq((profile.match(re) ?? []).join(" ").toLowerCase().match(/[a-z]{5,}/g) ?? []).filter((w) => !STOP.has(w));
|
|
188
|
+
const wins = new Set(pick(/\*\*Wins:?\*\*[^\n]*/gi));
|
|
189
|
+
const loses = new Set(pick(/\*\*Loses:?\*\*[^\n]*/gi));
|
|
190
|
+
const forbidden = rules.flatMap((r) => [...String(r.rule).matchAll(/\b(?:no|never|avoid|without)\s+([a-z][a-z -]{3,30}?)(?=[,.;:)]|\s+(?:on|in|before|after|unless|or)\b|$)/gi)].map((m) => ({ id: r.id, what: m[1].trim().toLowerCase() })));
|
|
191
|
+
return ideas
|
|
192
|
+
.map((x, i) => {
|
|
193
|
+
const text = `${x.name} ${x.metaphor} ${x.summary} ${x.signature?.moment ?? ""} ${(x.sections ?? []).join(" ")} ${x.brand ?? ""}`.toLowerCase();
|
|
194
|
+
const ws = new Set(words(text));
|
|
195
|
+
const why = [];
|
|
196
|
+
let s = 0.5 - i * 0.01;
|
|
197
|
+
if (x.signature?.move && fit[x.signature.move] != null) {
|
|
198
|
+
s += 0.2 * (fit[x.signature.move] / top);
|
|
199
|
+
why.push(`signature fits the job (${fit[x.signature.move]})`);
|
|
200
|
+
}
|
|
201
|
+
const before = history.moves?.[x.signature?.move] ?? 0;
|
|
202
|
+
if (before) {
|
|
203
|
+
// A small nod to what they chose; more than that turns every product into the last one.
|
|
204
|
+
s += Math.min(0.06, 0.03 * before);
|
|
205
|
+
why.push(`you chose ${x.signature.move} before (${before}×)`);
|
|
206
|
+
}
|
|
207
|
+
// Novelty: a direction whose look repeats palate's recent pages ranks down; a fresh one up.
|
|
208
|
+
if (recent.length && x.starter) {
|
|
209
|
+
const mine = ideaLook(x);
|
|
210
|
+
const worst = Math.max(0, ...recent.map((r) => sharedAxes(mine, r.look, ["ground", "display", "imagery"]).length));
|
|
211
|
+
if (worst >= 2) (s -= 0.12 * (worst - 1)), why.push(`its look repeats a recent palate page (${worst} of 3)`);
|
|
212
|
+
else (s += 0.05), why.push("its look is unlike palate's recent pages");
|
|
213
|
+
}
|
|
214
|
+
const w = [...ws].filter((t) => wins.has(t));
|
|
215
|
+
const l = [...ws].filter((t) => loses.has(t));
|
|
216
|
+
if (w.length) (s += Math.min(0.15, 0.03 * w.length)), why.push(`profile wins: ${w.slice(0, 4).join(", ")}`);
|
|
217
|
+
if (l.length) (s -= Math.min(0.25, 0.05 * l.length)), why.push(`profile losses: ${l.slice(0, 4).join(", ")}`);
|
|
218
|
+
for (const f of forbidden)
|
|
219
|
+
if (text.includes(f.what)) {
|
|
220
|
+
s -= 0.2;
|
|
221
|
+
why.push(`names what ${f.id} forbids (${f.what})`);
|
|
222
|
+
}
|
|
223
|
+
return { id: x.id, name: x.name, score: +s.toFixed(3), why };
|
|
224
|
+
})
|
|
225
|
+
.sort((a, b) => b.score - a.score);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export const CLOSE_GAP = 0.08;
|
|
229
|
+
// Auto-pick or picker. choose: "auto" (the user said just build it), "user" (they asked to choose), or undefined.
|
|
230
|
+
// strength: the triage's reading of the user's taste for this kind of screen (none | some | strong).
|
|
231
|
+
export function decidePick({ scored, strength = "none", choose, history = { chosen: 0 }, screen = "this kind of screen" }) {
|
|
232
|
+
const [a, b] = scored;
|
|
233
|
+
const label = screen === "other" ? "this kind of screen" : `${screen} pages`;
|
|
234
|
+
if (choose === "user") return { auto: false, why: "Opening the picker: the user asked to choose." };
|
|
235
|
+
if (choose === "auto") return { auto: true, pick: a, why: `Picked "${a.name}" from your taste: you said to just build it.` };
|
|
236
|
+
const strong = strength === "strong" || (history.chosen ?? 0) >= 2;
|
|
237
|
+
if (!strong) return { auto: false, why: `Opening the picker: ${strength === "some" || history.chosen ? "only a little" : "no"} history for ${label} yet.` };
|
|
238
|
+
if (b && a.score - b.score < CLOSE_GAP) return { auto: false, why: `Opening the picker: "${a.name}" and "${b.name}" score close (${a.score} vs ${b.score}): a real judgement call.` };
|
|
239
|
+
return { auto: true, pick: a, why: `Picked "${a.name}" from your taste: your history for ${label} is strong and it leads${b ? ` by ${(a.score - b.score).toFixed(2)}` : ""}${a.why.length ? ` (${a.why.slice(0, 2).join("; ")})` : ""}.` };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// The whole decision for a direction session (research or not).
|
|
243
|
+
export function decide(dir, meta, list, { choose } = {}) {
|
|
244
|
+
const history = tasteHistory(meta.screen);
|
|
245
|
+
const scored = scoreIdeas(list, { ...meta, project: projectOf(dir) }, { history, recent: recentLooks({ excludePid: projectId(dir) }) });
|
|
246
|
+
let strength = "none";
|
|
247
|
+
try {
|
|
248
|
+
strength = plan(dir, meta.problem, { route: meta.route ?? undefined, mode: "research", log: false }).strength;
|
|
249
|
+
} catch {}
|
|
250
|
+
return { ...decidePick({ scored, strength, choose, history, screen: meta.screen ?? "other" }), scored, strength };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// What the picker shows besides the ideas: the brand case and the references (which the user may like or dislike).
|
|
254
|
+
export function pickerState(dir, meta) {
|
|
255
|
+
const d = loadResearch(dir, meta.research);
|
|
256
|
+
return { research: d ? { name: d.name, product: d.understanding.product, brand: meta.brand, brandLine: meta.brandLine, refs: d.kept.map((r) => ({ id: r.id, name: r.name, url: r.url, role: r.role, learn: r.learn.line })), cliches: d.cliches.map((c) => c.label) } : null };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// The extra fields a choice logs to ~/.palate/taste/directions.jsonl (palate learns from them).
|
|
260
|
+
export function choiceFields(meta, idea) {
|
|
261
|
+
if (!idea) return {};
|
|
262
|
+
return { screen: meta.screen ?? null, research: meta.research ?? null, brand: meta.brand ?? null, metaphor: idea.metaphor ?? null, signature: idea.signature ?? null, starter: idea.starter ? { colours: idea.starter.colours ?? idea.starter.colors, type: idea.starter.type, radius: idea.starter.radius, motion: idea.starter.motion, imagery: idea.starter.imagery } : null, provenance: idea.provenance ?? null };
|
|
263
|
+
}
|
|
264
|
+
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// The benchmark: 30 fictional landing-page briefs (kb/bench/briefs.json) that palate builds end to end with no
|
|
2
|
+
// human input on each release, so quality is measured on pages nobody tuned for, not taken from self-scores.
|
|
3
|
+
// A brief is scaffolded into an empty Vite + React + Tailwind project; whoever runs the build (an agent, a
|
|
4
|
+
// script) records one result per brief, and the report sums them per release: floor pass rate, reference
|
|
5
|
+
// tie-or-win rate (from a judge that saw both orders), build minutes and cost. The references are real sites
|
|
6
|
+
// used only as judging exemplars: never shipped, never copied, never handed to the builder as material.
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
import { PALATE_HOME } from "../catalog/store.mjs";
|
|
12
|
+
import { KB_ROOT } from "../paths.mjs";
|
|
13
|
+
|
|
14
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const PKG_DIR = path.resolve(here, "..", "..");
|
|
16
|
+
const KB_DIR = process.env.PALATE_KB ?? KB_ROOT;
|
|
17
|
+
|
|
18
|
+
export const BENCH_DIR = path.join(PALATE_HOME, "bench");
|
|
19
|
+
export const RESULTS_FILE = path.join(BENCH_DIR, "results.jsonl");
|
|
20
|
+
export const BRIEFS_FILE = path.join(KB_DIR, "bench", "briefs.json");
|
|
21
|
+
export const TEMPLATE_DIR = path.join(PKG_DIR, "templates", "vite-react-tw");
|
|
22
|
+
|
|
23
|
+
let cached = null;
|
|
24
|
+
function loadBriefs() {
|
|
25
|
+
if (!cached) cached = JSON.parse(fs.readFileSync(BRIEFS_FILE, "utf8"));
|
|
26
|
+
return cached;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const categories = () => loadBriefs().categories ?? [...new Set(loadBriefs().briefs.map((b) => b.category))];
|
|
30
|
+
|
|
31
|
+
// Every brief, or only one category's.
|
|
32
|
+
export function listBriefs({ category } = {}) {
|
|
33
|
+
const { briefs } = loadBriefs();
|
|
34
|
+
if (!category) return briefs;
|
|
35
|
+
if (!categories().includes(category)) throw new Error(`No bench category "${category}". Categories: ${categories().join(", ")}.`);
|
|
36
|
+
return briefs.filter((b) => b.category === category);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getBrief(id) {
|
|
40
|
+
const b = loadBriefs().briefs.find((x) => x.id === id);
|
|
41
|
+
if (!b) throw new Error(`No bench brief "${id}". The ${loadBriefs().briefs.length} briefs are in ${BRIEFS_FILE}.`);
|
|
42
|
+
return b;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function copyDir(from, to) {
|
|
46
|
+
fs.mkdirSync(to, { recursive: true });
|
|
47
|
+
for (const e of fs.readdirSync(from, { withFileTypes: true })) {
|
|
48
|
+
// npm drops .gitignore from published packages, so a template may carry it as "gitignore" or "_gitignore".
|
|
49
|
+
const name = e.isFile() && /^_?gitignore$/.test(e.name) ? ".gitignore" : e.name;
|
|
50
|
+
if (e.isDirectory()) copyDir(path.join(from, e.name), path.join(to, name));
|
|
51
|
+
else fs.copyFileSync(path.join(from, e.name), path.join(to, name));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const npmName = (id) => `bench-${id}`.toLowerCase().replace(/[^a-z0-9-._~]/g, "-");
|
|
56
|
+
|
|
57
|
+
// Copies the template into `into` (which must be empty or missing), names the project, writes the brief's README
|
|
58
|
+
// and .palate/bench.json, and says what to do next.
|
|
59
|
+
export function scaffold(id, into) {
|
|
60
|
+
const brief = getBrief(id);
|
|
61
|
+
if (!into) throw new Error("scaffold needs a folder to build into.");
|
|
62
|
+
const dir = path.resolve(into);
|
|
63
|
+
if (fs.existsSync(dir) && (!fs.statSync(dir).isDirectory() || fs.readdirSync(dir).length)) throw new Error(`${dir} is not empty; a bench brief starts from an empty folder.`);
|
|
64
|
+
copyDir(TEMPLATE_DIR, dir);
|
|
65
|
+
|
|
66
|
+
const pkgFile = path.join(dir, "package.json");
|
|
67
|
+
const pkg = JSON.parse(fs.readFileSync(pkgFile, "utf8"));
|
|
68
|
+
pkg.name = npmName(brief.id);
|
|
69
|
+
fs.writeFileSync(pkgFile, JSON.stringify(pkg, null, 2) + "\n");
|
|
70
|
+
const html = path.join(dir, "index.html");
|
|
71
|
+
if (fs.existsSync(html)) fs.writeFileSync(html, fs.readFileSync(html, "utf8").replaceAll("{{title}}", brief.product));
|
|
72
|
+
|
|
73
|
+
fs.writeFileSync(path.join(dir, "README.md"), brief.readme.endsWith("\n") ? brief.readme : brief.readme + "\n");
|
|
74
|
+
fs.mkdirSync(path.join(dir, ".palate"), { recursive: true });
|
|
75
|
+
const meta = { id: brief.id, job: brief.job, references: brief.references, created: new Date().toISOString() };
|
|
76
|
+
fs.writeFileSync(path.join(dir, ".palate", "bench.json"), JSON.stringify(meta, null, 2) + "\n");
|
|
77
|
+
|
|
78
|
+
return [
|
|
79
|
+
`Bench brief "${brief.id}" (${brief.category}) is ready in ${dir}.`,
|
|
80
|
+
`${brief.product}: README.md has the product facts; build from them with no human input.`,
|
|
81
|
+
"",
|
|
82
|
+
"Next:",
|
|
83
|
+
` cd ${JSON.stringify(dir)}`,
|
|
84
|
+
" pnpm install",
|
|
85
|
+
` The job: ${brief.job}`,
|
|
86
|
+
` palate plan ${JSON.stringify(brief.job)}`,
|
|
87
|
+
].join("\n");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// The release a result belongs to: palate's version plus the git commit when palate runs from a checkout.
|
|
91
|
+
export function releaseTag() {
|
|
92
|
+
const { version } = JSON.parse(fs.readFileSync(path.join(PKG_DIR, "package.json"), "utf8"));
|
|
93
|
+
let sha = "";
|
|
94
|
+
try {
|
|
95
|
+
const r = spawnSync("git", ["rev-parse", "--short", "HEAD"], { cwd: PKG_DIR, encoding: "utf8", windowsHide: true, timeout: 5000 });
|
|
96
|
+
if (r.status === 0) sha = r.stdout.trim();
|
|
97
|
+
} catch {}
|
|
98
|
+
return sha ? `${version}+${sha}` : version;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// One build's result: { floor: {pass, fails:[...]}, vsRefs: {wins, ties, losses, inconsistent}, minutes, tokens, cost?, notes }.
|
|
102
|
+
export function recordResult(id, result = {}) {
|
|
103
|
+
getBrief(id);
|
|
104
|
+
const row = { id, release: result.release ?? releaseTag(), at: new Date().toISOString(), ...result };
|
|
105
|
+
fs.mkdirSync(BENCH_DIR, { recursive: true });
|
|
106
|
+
fs.appendFileSync(RESULTS_FILE, JSON.stringify(row) + "\n");
|
|
107
|
+
return row;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function readResults() {
|
|
111
|
+
if (!fs.existsSync(RESULTS_FILE)) return [];
|
|
112
|
+
return fs
|
|
113
|
+
.readFileSync(RESULTS_FILE, "utf8")
|
|
114
|
+
.split(/\r?\n/)
|
|
115
|
+
.filter(Boolean)
|
|
116
|
+
.flatMap((l) => {
|
|
117
|
+
try {
|
|
118
|
+
return [JSON.parse(l)];
|
|
119
|
+
} catch {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const pct = (n, d) => (d ? `${Math.round((n / d) * 100)}%` : "–");
|
|
126
|
+
const num = (v) => (typeof v === "number" && Number.isFinite(v) ? v : null);
|
|
127
|
+
const cell = (s) => String(s ?? "").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
128
|
+
|
|
129
|
+
// A Markdown summary of one release (the newest one recorded when none is named): the latest result per brief,
|
|
130
|
+
// then the totals the benchmark is judged on.
|
|
131
|
+
export function benchReport({ release } = {}) {
|
|
132
|
+
const all = readResults();
|
|
133
|
+
if (!all.length) return `No bench results yet in ${RESULTS_FILE}.`;
|
|
134
|
+
const rel = release ?? all[all.length - 1].release;
|
|
135
|
+
const rows = all.filter((r) => r.release === rel);
|
|
136
|
+
if (!rows.length) return `No bench results for release ${rel}. Recorded releases: ${[...new Set(all.map((r) => r.release))].join(", ")}.`;
|
|
137
|
+
|
|
138
|
+
const latest = new Map();
|
|
139
|
+
for (const r of rows) latest.set(r.id, r); // file order is time order; the last one wins
|
|
140
|
+
const briefs = loadBriefs().briefs;
|
|
141
|
+
const order = new Map(briefs.map((b, i) => [b.id, i]));
|
|
142
|
+
const done = [...latest.values()].sort((a, b) => (order.get(a.id) ?? 1e9) - (order.get(b.id) ?? 1e9));
|
|
143
|
+
|
|
144
|
+
const t = { floorRun: 0, floorPass: 0, wins: 0, ties: 0, losses: 0, inconsistent: 0, minutes: [], tokens: 0, tokensSeen: false, cost: 0, costSeen: false };
|
|
145
|
+
const lines = [
|
|
146
|
+
`# palate bench · ${rel}`,
|
|
147
|
+
"",
|
|
148
|
+
`${done.length} of ${briefs.length} briefs built (${rows.length} result${rows.length === 1 ? "" : "s"} recorded, latest per brief counted).`,
|
|
149
|
+
"",
|
|
150
|
+
"| Brief | Category | Floor | Fails | vs refs W/T/L/inc | Minutes | Tokens | Cost | Notes |",
|
|
151
|
+
"|---|---|---|---|---|---|---|---|---|",
|
|
152
|
+
];
|
|
153
|
+
for (const r of done) {
|
|
154
|
+
const cat = briefs.find((b) => b.id === r.id)?.category ?? "?";
|
|
155
|
+
const floor = r.floor && typeof r.floor.pass === "boolean" ? r.floor : null;
|
|
156
|
+
if (floor) {
|
|
157
|
+
t.floorRun++;
|
|
158
|
+
if (floor.pass) t.floorPass++;
|
|
159
|
+
}
|
|
160
|
+
const v = r.vsRefs ?? null;
|
|
161
|
+
if (v) for (const k of ["wins", "ties", "losses", "inconsistent"]) t[k] += num(v[k]) ?? 0;
|
|
162
|
+
if (num(r.minutes) != null) t.minutes.push(r.minutes);
|
|
163
|
+
if (num(r.tokens) != null) (t.tokens += r.tokens), (t.tokensSeen = true);
|
|
164
|
+
if (num(r.cost) != null) (t.cost += r.cost), (t.costSeen = true);
|
|
165
|
+
lines.push(
|
|
166
|
+
`| ${cell(r.id)} | ${cell(cat)} | ${floor ? (floor.pass ? "pass" : "FAIL") : "–"} | ${cell((floor?.fails ?? []).join("; ")) || "–"} | ${v ? `${num(v.wins) ?? 0}/${num(v.ties) ?? 0}/${num(v.losses) ?? 0}/${num(v.inconsistent) ?? 0}` : "–"} | ${num(r.minutes) != null ? r.minutes.toFixed(1) : "–"} | ${num(r.tokens) != null ? r.tokens.toLocaleString("en-US") : "–"} | ${num(r.cost) != null ? `$${r.cost.toFixed(2)}` : "–"} | ${cell(r.notes) || ""} |`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
const judged = t.wins + t.ties + t.losses + t.inconsistent;
|
|
170
|
+
const meanMin = t.minutes.length ? t.minutes.reduce((a, b) => a + b, 0) / t.minutes.length : null;
|
|
171
|
+
lines.push(
|
|
172
|
+
"",
|
|
173
|
+
"## Totals",
|
|
174
|
+
"",
|
|
175
|
+
`- Floor pass rate: ${pct(t.floorPass, t.floorRun)} (${t.floorPass}/${t.floorRun}; target 100%)`,
|
|
176
|
+
`- Reference tie-or-win rate: ${pct(t.wins + t.ties, judged)} (${t.wins} wins, ${t.ties} ties, ${t.losses} losses, ${t.inconsistent} inconsistent across orders, of ${judged} pairs; tie share ${pct(t.ties, judged)}; inconsistent pairs count as not won)`,
|
|
177
|
+
`- Mean build: ${meanMin != null ? `${meanMin.toFixed(1)} min` : "–"} over ${t.minutes.length} build${t.minutes.length === 1 ? "" : "s"}`,
|
|
178
|
+
`- Tokens: ${t.tokensSeen ? t.tokens.toLocaleString("en-US") : "–"}`,
|
|
179
|
+
`- Cost: ${t.costSeen ? `$${t.cost.toFixed(2)}` : "–"}`,
|
|
180
|
+
);
|
|
181
|
+
const missing = briefs.filter((b) => !latest.has(b.id)).map((b) => b.id);
|
|
182
|
+
if (missing.length) lines.push("", `Not built in this release: ${missing.join(", ")}.`);
|
|
183
|
+
return lines.join("\n") + "\n";
|
|
184
|
+
}
|