@palate/cli 0.0.0-stage → 0.0.2
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 +153 -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 +37 -4
- package/scripts/pack-assets.mjs +58 -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,620 @@
|
|
|
1
|
+
// `palate ambition <route>`: the pass after the finishing pass that asks "is this remarkable?", not "is it correct?".
|
|
2
|
+
// palate renders the page at 1440, crops each section, and puts the first screen and every section beside the
|
|
3
|
+
// strongest references it has (the research step's captures, else the user's own references, else palate's
|
|
4
|
+
// library of the same kind of section), with the chosen signature move. It measures what it can (type scale
|
|
5
|
+
// and character, contrast, whitespace, centring, stock grids, colour against common SaaS palettes, the
|
|
6
|
+
// signature in the DOM, how close each section is to a stock component-library section) and asks the calling
|
|
7
|
+
// agent, who can see, to score each section on a strict rubric. Then it picks the weakest section and writes
|
|
8
|
+
// one upgrade brief: what's generic, moves that fit this product (with recipes), what to keep. The agent
|
|
9
|
+
// upgrades that section once; `--verify` re-renders it, before | after, with new scores. Each upgrade and its
|
|
10
|
+
// later fate (kept, reverted, pointed at again) is logged in ~/.palate so the next choice of moves follows
|
|
11
|
+
// what this user keeps. Runs without asking the user anything.
|
|
12
|
+
import fs from "node:fs";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { contactSheet, cropSections, findSections, openPage, shootFull, slugOf, stamp, withBrowser } from "../look.mjs";
|
|
16
|
+
import { normalizeRoute } from "../shoot.mjs";
|
|
17
|
+
import { readJson, TASTE_DIR } from "./common.mjs";
|
|
18
|
+
import { LIB_DIR, sectionKind, slash } from "./craft.mjs";
|
|
19
|
+
import { logGrowth, preferMoves, setOutcome, upgrades } from "./growth.mjs";
|
|
20
|
+
import { layoutRecord, projectId, readLayouts, visualSimilarity } from "./layouts.mjs";
|
|
21
|
+
import { rememberedRefs } from "./myrefs.mjs";
|
|
22
|
+
import { kindTags } from "./rules.mjs";
|
|
23
|
+
import { gateLines, normSignature, readResearch, saveGate, similarityGate } from "./similar.mjs";
|
|
24
|
+
|
|
25
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const ambitionScript = fs.readFileSync(path.join(here, "..", "page-ambition.js"), "utf8").trim().replace(/;\s*$/, "");
|
|
27
|
+
const fingerprintScript = fs.readFileSync(path.join(here, "..", "page-fingerprint.js"), "utf8").trim().replace(/;\s*$/, "");
|
|
28
|
+
|
|
29
|
+
// The rubric the agent scores every section on, 0–10 each (10 is remarkable).
|
|
30
|
+
export const RUBRIC = [
|
|
31
|
+
{ id: "screenshot", label: "Screenshot-worthy", q: "Would a designer screenshot this section to save or share it?" },
|
|
32
|
+
{ id: "moment", label: "Memorable moment", q: "Is there one moment here someone would describe tomorrow?" },
|
|
33
|
+
{ id: "signature", label: "Signature delivered", q: "Is the chosen signature move delivered (score the section that should carry it; leave null elsewhere)?" },
|
|
34
|
+
{ id: "type", label: "Type with character", q: "A deliberate face, scale, weight and tracking, not defaults?" },
|
|
35
|
+
{ id: "copy", label: "Point of view", q: "Copy that only this product could say, not a sentence any SaaS could use?" },
|
|
36
|
+
{ id: "hierarchy", label: "Hierarchy and rhythm", q: "Hierarchy and rhythm at the level of the references beside it?" },
|
|
37
|
+
{ id: "generic", label: "Nothing generic", q: "No template look, stock patterns or centred-everything? (10 = nothing generic)" },
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const clamp = (v, lo = 0, hi = 10) => Math.max(lo, Math.min(hi, v));
|
|
41
|
+
const r1 = (v) => (v == null ? null : Math.round(v * 10) / 10);
|
|
42
|
+
const pct = (v) => `${Math.round((v ?? 0) * 100)}%`;
|
|
43
|
+
const mean = (xs) => {
|
|
44
|
+
const v = xs.filter((x) => typeof x === "number" && !Number.isNaN(x));
|
|
45
|
+
return v.length ? v.reduce((a, b) => a + b, 0) / v.length : null;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Faces that read as "nobody chose this".
|
|
49
|
+
const GENERIC_FONT = /^(ui-sans-serif|system-ui|-apple-system|blinkmacsystemfont|segoe ui|roboto|helvetica( neue)?|arial|inter|geist|sans-serif|open sans|lato|poppins|montserrat|ui-serif|times new roman|times)$/i;
|
|
50
|
+
// Sentences any product could print.
|
|
51
|
+
const GENERIC_COPY = [/everything (you|your [a-z]+|a [a-z]+(?: [a-z]+)?) needs?\b/i, /\ball[- ]in[- ]one\b/i, /\bpowerful\b/i, /\bseamless(ly)?\b/i, /\beffortless(ly)?\b/i, /\bsupercharge/i, /\bbuilt for (modern )?teams\b/i, /\bmade (simple|easy)\b/i, /\bwork smarter\b/i, /\bstreamline/i, /\bboost (your )?productivity\b/i, /\bunlock\b/i, /\btransform (the way|your)\b/i, /\bsimple,? (yet|but) powerful\b/i, /\bnext[- ]gen/i, /\bgame[- ]chang/i, /\bwhy choose\b/i, /\bfeatures that\b/i, /\bat your fingertips\b/i, /\btake (it|your [a-z]+) to the next level\b/i];
|
|
52
|
+
// Accents every SaaS template ships with (Tailwind defaults, the usual brand blues and violets, near-black).
|
|
53
|
+
const COMMON_ACCENTS = { "Tailwind blue": "#2563eb", "Tailwind indigo": "#4f46e5", "Tailwind violet": "#7c3aed", "Tailwind purple": "#9333ea", "Tailwind sky": "#0284c7", "Tailwind emerald": "#059669", "Tailwind green": "#16a34a", "Tailwind teal": "#0d9488", "Tailwind orange": "#ea580c", "Tailwind rose": "#e11d48", "Stripe violet": "#635bff", "Linear indigo": "#5e6ad2", "near-black": "#111111", "slate-900": "#0f172a" };
|
|
54
|
+
const hexRgb = (h) => (h && /^#[0-9a-f]{6}$/i.test(h) ? [1, 3, 5].map((i) => parseInt(h.slice(i, i + 2), 16)) : null);
|
|
55
|
+
const dist = (a, b) => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
|
|
56
|
+
|
|
57
|
+
// How distinct the page's accent is: from template palettes, and from the user's other projects.
|
|
58
|
+
export function colourCheck(accent, dir) {
|
|
59
|
+
const a = hexRgb(accent);
|
|
60
|
+
if (!a) return { accent, line: "No chromatic accent found (a page in neutrals only).", score: null };
|
|
61
|
+
const near = Object.entries(COMMON_ACCENTS).map(([name, h]) => ({ name, h, d: dist(a, hexRgb(h)) })).sort((x, y) => x.d - y.d)[0];
|
|
62
|
+
const pid = dir ? projectId(dir) : null;
|
|
63
|
+
const mine = readLayouts().filter((r) => r.pid !== pid && hexRgb(r.style?.accent) && dist(a, hexRgb(r.style.accent)) < 28);
|
|
64
|
+
const projects = [...new Set(mine.map((r) => r.project))];
|
|
65
|
+
const score = r1(clamp((near.d / 120) * 10 - (projects.length ? 4 : 0)));
|
|
66
|
+
return { accent, near, projects, score, line: `Accent ${accent}: ${Math.round(near.d)} from ${near.name} (${near.h})${near.d < 40 ? ", a template colour" : ""}${projects.length ? `; the same colour as your other project${projects.length > 1 ? "s" : ""} ${projects.join(", ")}` : ""}. Distinctiveness ${score}/10.` };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// palate's own scores for a section (0–10; null where it can't measure), with what it found generic.
|
|
70
|
+
export function measuredScores(m, { libSim = null, signature = null } = {}) {
|
|
71
|
+
if (!m || m.empty) return { scores: {}, flags: [], templateness: null, mean: null };
|
|
72
|
+
const flags = [];
|
|
73
|
+
// A product window is judged as product UI on the sheet; its small app type isn't page typography.
|
|
74
|
+
if (m.productUI) {
|
|
75
|
+
const lib = libSim == null ? 0 : clamp((libSim - 0.35) / 0.4, 0, 1);
|
|
76
|
+
if (lib >= 0.5) flags.push(`close to a stock component-library section (${pct(libSim)})`);
|
|
77
|
+
if (!m.animated) flags.push("the product window doesn't move: a still picture of the product");
|
|
78
|
+
const scores = { screenshot: null, moment: r1(clamp(5 + (m.animated ? 2 : 0) + (m.mediaShare >= 0.35 ? 0.5 : 0) - 2 * lib)), signature: signature && m.signature ? 9 : null, type: null, copy: null, hierarchy: null, generic: r1(clamp(10 * (1 - 0.6 * lib))) };
|
|
79
|
+
return { scores, flags, templateness: +(0.6 * lib).toFixed(2), mean: r1(mean(Object.values(scores))) };
|
|
80
|
+
}
|
|
81
|
+
const h = m.headline;
|
|
82
|
+
const defaultFace = GENERIC_FONT.test(h.family ?? "");
|
|
83
|
+
let type = 5;
|
|
84
|
+
if (defaultFace) flags.push(`headline in a default face (${h.family})`);
|
|
85
|
+
else type += 2 + (h.family !== m.body.family ? 0.5 : 0);
|
|
86
|
+
if (Math.abs(h.track ?? 0) >= 0.01) type += 1;
|
|
87
|
+
if (m.scale >= 4.5) type += 1.5;
|
|
88
|
+
else if (m.scale >= 3) type += 0.5;
|
|
89
|
+
else if (m.scale < 1.8) {
|
|
90
|
+
type -= 2;
|
|
91
|
+
flags.push(`headline only ${m.scale}× the body size: no scale drama`);
|
|
92
|
+
}
|
|
93
|
+
if (h.weight - m.body.weight >= 250 || (h.weight <= 350 && h.size >= 56)) type += 0.5;
|
|
94
|
+
if (h.italic || h.upper) type += 0.5;
|
|
95
|
+
let hierarchy = 6;
|
|
96
|
+
if (m.scale < 1.8) hierarchy -= 2;
|
|
97
|
+
else if (m.scale >= 2.5) hierarchy += 1;
|
|
98
|
+
if (m.focal > 2) {
|
|
99
|
+
hierarchy -= 2;
|
|
100
|
+
flags.push(`${m.focal} elements share the biggest size: no single focal point`);
|
|
101
|
+
}
|
|
102
|
+
// Tight on both sides; one open edge is often a section running on into the next on purpose.
|
|
103
|
+
const edge = Math.max(m.padTop, m.padBottom);
|
|
104
|
+
if (edge < 40 && m.height > 300 && m.mediaShare < 0.3) {
|
|
105
|
+
hierarchy -= 1.5;
|
|
106
|
+
flags.push(`tight edges (${edge}px of air)`);
|
|
107
|
+
} else if (Math.min(m.padTop, m.padBottom) >= 96) hierarchy += 0.5;
|
|
108
|
+
if (h.contrast != null && h.contrast < 4.5) {
|
|
109
|
+
hierarchy -= 1;
|
|
110
|
+
flags.push(`headline contrast ${h.contrast}:1`);
|
|
111
|
+
}
|
|
112
|
+
if (m.body.contrast < 4.5) {
|
|
113
|
+
hierarchy -= 1;
|
|
114
|
+
flags.push(`body text contrast ${m.body.contrast}:1`);
|
|
115
|
+
}
|
|
116
|
+
const stock = GENERIC_COPY.map((re) => m.copy.match(re)?.[0]).filter(Boolean);
|
|
117
|
+
let copy = 6 - 2 * stock.length + (/\d/.test(h.text) ? 1 : 0) - (h.text.split(/\s+/).length <= 2 && !/\d/.test(h.text) ? 1 : 0);
|
|
118
|
+
if (stock.length) flags.push(`stock copy: "${stock.join('", "')}"`);
|
|
119
|
+
const grid = m.grid >= 3 && m.grid <= 6;
|
|
120
|
+
const centred = m.centred >= 0.7 && m.blocks >= 2;
|
|
121
|
+
const lib = libSim == null ? 0 : clamp((libSim - 0.35) / 0.4, 0, 1);
|
|
122
|
+
if (grid) flags.push(`a row of ${m.grid} equal cards`);
|
|
123
|
+
if (centred) flags.push("centred everything");
|
|
124
|
+
if (lib >= 0.5) flags.push(`close to a stock component-library section (${pct(libSim)})`);
|
|
125
|
+
const templateness = +(0.4 * lib + 0.25 * (grid ? 1 : 0) + 0.2 * (centred ? 1 : 0) + 0.15 * (defaultFace ? 1 : 0)).toFixed(2);
|
|
126
|
+
let moment = 4 + (m.scale >= 4 ? 2 : 0) + (m.mediaShare >= 0.35 || m.animated > 0 ? 1 : 0) + (m.ownBg ? 0.5 : 0) + (defaultFace ? 0 : 1) + 2 * (1 - templateness) - 1;
|
|
127
|
+
const scores = { screenshot: null, moment, signature: signature && m.signature ? 9 : null, type, copy, hierarchy, generic: 10 * (1 - templateness) };
|
|
128
|
+
for (const k of Object.keys(scores)) scores[k] = scores[k] == null ? null : r1(clamp(scores[k]));
|
|
129
|
+
return { scores, flags, templateness, mean: r1(mean(Object.values(scores))) };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// The agent's scores, in any of the shapes an agent might write them.
|
|
133
|
+
export function readAgentScores(input) {
|
|
134
|
+
const j = typeof input === "string" ? readJson(input, null) : input;
|
|
135
|
+
if (!j) throw new Error(`Could not read the scores${typeof input === "string" ? ` in ${input}` : ""}. Write JSON: {"sections": [{"index": 2, "scores": {"screenshot": 3, …}, "generic": "…", "keep": "…"}]}`);
|
|
136
|
+
const list = Array.isArray(j) ? j : Array.isArray(j.sections) ? j.sections : Object.entries(j).filter(([k]) => /^\d+$/.test(k)).map(([k, v]) => ({ index: Number(k), ...v }));
|
|
137
|
+
return Object.fromEntries(list.map((s) => [Number(s.index ?? s.section), { scores: s.scores ?? Object.fromEntries(RUBRIC.map((r) => [r.id, s[r.id]]).filter(([, v]) => v != null)), generic: s.generic ?? s.why ?? null, keep: s.keep ?? null }]));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// The agent's eyes count most; palate's measures keep it honest.
|
|
141
|
+
export function combine(measured, agent) {
|
|
142
|
+
const a = agent ? mean(RUBRIC.map((r) => agent[r.id])) : null;
|
|
143
|
+
return r1(a != null ? (measured != null ? 0.7 * a + 0.3 * measured : a) : measured);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// The weakest content section (not the header, navigation or footer); ties go to the one higher on the page.
|
|
147
|
+
export function pickWeakest(sections) {
|
|
148
|
+
const ok = sections.filter((s) => s.final != null && !["header", "nav", "footer"].includes(s.tag) && !/^(header|footer|navigation)$/i.test(s.name ?? "") && (s.height ?? 999) >= 160);
|
|
149
|
+
return [...ok].sort((a, b) => a.final - b.final || a.index - b.index)[0] ?? null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ---- moves: the moves library when it is there (src/moves.mjs), else kb/moves/moves.yaml.
|
|
153
|
+
const words = (s) => String(s ?? "").toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
154
|
+
async function yamlMoves() {
|
|
155
|
+
try {
|
|
156
|
+
const { loadMoves } = await import("../concept.mjs");
|
|
157
|
+
return loadMoves().moves ?? [];
|
|
158
|
+
} catch {
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const FAMILY_FOR = { type: ["type"], generic: ["composition", "data"], moment: ["composition", "interaction", "motion"], copy: ["content"], hierarchy: ["composition", "type"], screenshot: ["composition", "type"], signature: ["composition", "interaction"], colour: ["colour"] };
|
|
163
|
+
// The moves library's kinds of move that answer each weak rubric item, and that fit each kind of section.
|
|
164
|
+
const MOVE_KINDS_FOR = { type: ["type"], generic: ["layout", "imagery", "data"], moment: ["interaction", "motion", "hero"], hierarchy: ["layout", "type"], screenshot: ["layout", "imagery", "texture"], signature: ["hero", "interaction"], colour: ["texture", "imagery"] };
|
|
165
|
+
const sectionMoveKinds = (sk = "") => (/hero/.test(sk) ? ["hero", "type", "layout", "imagery", "motion", "interaction", "texture"] : /footer/.test(sk) ? ["footer", "easter-egg"] : ["layout", "type", "data", "imagery", "interaction", "motion", "texture"]);
|
|
166
|
+
export const recipeOf =(m) => `### ${m.id}${m.family ? ` (${m.family}${m.cost ? `, ${m.cost} effort` : ""})` : ""}\n${m.do ?? m.recipe ?? m.what ?? ""}${m.test ? `\nIt worked if: ${m.test}` : ""}`;
|
|
167
|
+
|
|
168
|
+
// Moves that could lift a section, best first, led by what this user keeps; reverted ones are skipped.
|
|
169
|
+
// weak: rubric ids that scored lowest. Returns { ids, text, skipped, why, source }.
|
|
170
|
+
export async function movesFor({ tags = [], kind = "marketing", signature = null, weak = [], sectionKind: sk = null, words: extra = "", limit = 3 } = {}) {
|
|
171
|
+
let lib = null;
|
|
172
|
+
try {
|
|
173
|
+
lib = await import("../moves.mjs");
|
|
174
|
+
} catch {}
|
|
175
|
+
let candidates = [];
|
|
176
|
+
if (lib?.matchMoves) {
|
|
177
|
+
try {
|
|
178
|
+
// The library's kinds are kinds of move (hero, layout, type…): the ones that can change this section,
|
|
179
|
+
// led by the ones that answer its weakest rubric items. The user's history goes in too.
|
|
180
|
+
const kinds = sectionMoveKinds(sk);
|
|
181
|
+
const history = upgrades().filter((u) => ["kept", "reverted"].includes(u.outcome)).flatMap((u) => (u.moves ?? []).slice(0, 1).map((id) => ({ id, outcome: u.outcome, kind: u.sectionKind })));
|
|
182
|
+
const r = await lib.matchMoves({ tags: [...tags, ...words(extra)], kind: kinds, limit: limit + 8, history, screen: sk ?? undefined });
|
|
183
|
+
const lead = new Set(weak.flatMap((w) => MOVE_KINDS_FOR[w] ?? []));
|
|
184
|
+
candidates = (Array.isArray(r) ? r : r?.moves ?? [])
|
|
185
|
+
.map((m) => (typeof m === "string" ? { id: m } : m))
|
|
186
|
+
.filter((m) => m?.id && m.id !== signature?.move)
|
|
187
|
+
.map((m, i) => ({ ...m, rank: (m.score ?? 0) + (lead.has(m.kind) ? 1 : 0) - i * 0.01 }))
|
|
188
|
+
.sort((a, b) => b.rank - a.rank);
|
|
189
|
+
} catch {}
|
|
190
|
+
}
|
|
191
|
+
const source = candidates.length ? "moves library" : "kb/moves/moves.yaml";
|
|
192
|
+
const all = await yamlMoves();
|
|
193
|
+
if (!candidates.length) {
|
|
194
|
+
const kinds = kind === "app" ? ["tool"] : ["marketing"];
|
|
195
|
+
const q = new Set(words(`${tags.join(" ")} ${extra} ${sk ?? ""}`).flatMap((w) => [w, w.replace(/s$/, "")]));
|
|
196
|
+
const fams = new Set(weak.flatMap((w) => FAMILY_FOR[w] ?? []));
|
|
197
|
+
candidates = all
|
|
198
|
+
.filter((m) => (m.kinds ?? []).some((k) => kinds.includes(k)) && m.do)
|
|
199
|
+
.map((m) => ({ m, s: (m.signals ?? []).filter((s) => words(s).every((w) => q.has(w))).length + (fams.has(m.family) ? 2 : 0) + (m.cost && m.cost !== "low" ? 0.3 : 0) }))
|
|
200
|
+
.sort((a, b) => b.s - a.s)
|
|
201
|
+
.slice(0, limit + 5)
|
|
202
|
+
.map((x) => x.m);
|
|
203
|
+
}
|
|
204
|
+
const { order, skipped, why } = preferMoves(candidates.map((m) => m.id), { sectionKind: sk });
|
|
205
|
+
const ids = order.slice(0, limit);
|
|
206
|
+
let text = null;
|
|
207
|
+
if (lib?.moveBrief && source === "moves library") {
|
|
208
|
+
try {
|
|
209
|
+
const t = await lib.moveBrief(ids);
|
|
210
|
+
text = typeof t === "string" ? t : Array.isArray(t) ? t.join("\n\n") : t?.text ?? null;
|
|
211
|
+
} catch {}
|
|
212
|
+
}
|
|
213
|
+
text ??= ids.map((id) => recipeOf(candidates.find((c) => c.id === id && c.do) ?? all.find((c) => c.id === id) ?? { id })).join("\n\n");
|
|
214
|
+
return { ids, text, skipped, why, source };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// The upgrade brief for one section. Plain data in, markdown out (tests call it directly).
|
|
218
|
+
export function upgradeBrief({ route, section, measured, agent, moves, signature, sourceFiles = [], crop, scoreLine, verifyCmd }) {
|
|
219
|
+
const low = RUBRIC.filter((r) => (agent?.scores?.[r.id] ?? measured.scores?.[r.id]) != null).sort((a, b) => (agent?.scores?.[a.id] ?? measured.scores[a.id]) - (agent?.scores?.[b.id] ?? measured.scores[b.id]));
|
|
220
|
+
const high = low.slice().reverse().filter((r) => (agent?.scores?.[r.id] ?? measured.scores[r.id]) >= 7);
|
|
221
|
+
return [
|
|
222
|
+
`# Upgrade one section: ${section.name} (section ${section.index} of ${route})`,
|
|
223
|
+
"",
|
|
224
|
+
scoreLine,
|
|
225
|
+
crop ? `Crop: ${slash(crop)}` : null,
|
|
226
|
+
sourceFiles.length ? `Source: ${sourceFiles.map(slash).join(", ")}` : `Source: find the component that renders "${section.heading ?? section.name}" (\`${section.selector}\`).`,
|
|
227
|
+
"",
|
|
228
|
+
"## What's generic",
|
|
229
|
+
...(agent?.generic ? [`- You saw: ${agent.generic}`] : []),
|
|
230
|
+
...(measured.flags.length ? measured.flags.map((f) => `- Measured: ${f}`) : ["- Nothing measurable stands out; the rubric scores say where it falls short."]),
|
|
231
|
+
`- Lowest on the rubric: ${low.slice(0, 3).map((r) => `${r.label} ${agent?.scores?.[r.id] ?? measured.scores[r.id]}/10`).join(", ")}.`,
|
|
232
|
+
signature ? `- The signature move "${signature.name}"${signature.what ? ` (${signature.what})` : ""}: ${section.signature ? "is here; make it the moment of this section" : "isn't in this section; bring it here if this is where it belongs"}.` : null,
|
|
233
|
+
"",
|
|
234
|
+
"## Moves that could lift it (use one; two only if they work together)",
|
|
235
|
+
moves.why && Object.keys(moves.why).length ? `What this user did with these before: ${Object.entries(moves.why).map(([id, w]) => `${id}: ${w}`).join("; ")}.` : null,
|
|
236
|
+
moves.skipped?.length ? `Left out because the user undid them before: ${moves.skipped.join(", ")}.` : null,
|
|
237
|
+
moves.text || "No moves library found: make one structural change that only this product could make.",
|
|
238
|
+
"",
|
|
239
|
+
"## Keep",
|
|
240
|
+
"- The section's job and its content: every fact, name and number stays (all from the project).",
|
|
241
|
+
...(agent?.keep ? [`- ${agent.keep}`] : []),
|
|
242
|
+
...high.map((r) => `- What already works: ${r.label.toLowerCase()} (${agent?.scores?.[r.id] ?? measured.scores[r.id]}/10).`),
|
|
243
|
+
"- The project's tokens and components, the user's rules, every other section exactly as it is, and every state (loading, empty, error) the section has.",
|
|
244
|
+
"",
|
|
245
|
+
"## Do it once",
|
|
246
|
+
"- Upgrade this one section, once, without asking the user: this is part of the finishing pass. Ask only if two moves above pull in clearly different directions and the choice is a matter of taste; then show both ideas in one line each and let them choose.",
|
|
247
|
+
`- Then: \`${verifyCmd}\` (add \`--moves <id>\` with the move you used, so palate learns what this user keeps).`,
|
|
248
|
+
]
|
|
249
|
+
.filter((l) => l != null)
|
|
250
|
+
.join("\n");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ---- rendering helpers
|
|
254
|
+
const dataUri = (f) => `data:image/${/\.jpe?g$/i.test(f) ? "jpeg" : /\.webp$/i.test(f) ? "webp" : "png"};base64,${fs.readFileSync(f).toString("base64")}`;
|
|
255
|
+
// A 16×10 grid of a picture's top (1.6:1): ink against its own background and mean colour per cell, the same
|
|
256
|
+
// shape as the layout memory's thumbnails, so visualSimilarity compares them. Decoded by the browser (JPEG too).
|
|
257
|
+
const GRID = `async (src) => {
|
|
258
|
+
const img = new Image(); img.src = src; await img.decode();
|
|
259
|
+
const W = 320, H = 200, cols = 16, rows = 10;
|
|
260
|
+
const c = document.createElement("canvas"); c.width = W; c.height = H;
|
|
261
|
+
const g = c.getContext("2d", { willReadFrequently: true });
|
|
262
|
+
const sh = Math.min(img.naturalHeight, img.naturalWidth / 1.6);
|
|
263
|
+
g.fillStyle = "#fff"; g.fillRect(0, 0, W, H);
|
|
264
|
+
g.drawImage(img, 0, 0, img.naturalWidth, sh, 0, 0, W, H * (sh / (img.naturalWidth / 1.6)));
|
|
265
|
+
const d = g.getImageData(0, 0, W, H).data;
|
|
266
|
+
const counts = new Map();
|
|
267
|
+
for (let i = 0; i < d.length; i += 12) { const k = ((d[i] >> 3) << 10) | ((d[i + 1] >> 3) << 5) | (d[i + 2] >> 3); counts.set(k, (counts.get(k) || 0) + 1); }
|
|
268
|
+
const mode = [...counts.entries()].sort((a, b) => b[1] - a[1])[0][0];
|
|
269
|
+
const bg = [(mode >> 10) << 3, ((mode >> 5) & 31) << 3, (mode & 31) << 3];
|
|
270
|
+
const ink = [], rgb = [];
|
|
271
|
+
for (let gy = 0; gy < rows; gy++) for (let gx = 0; gx < cols; gx++) {
|
|
272
|
+
let r = 0, gg = 0, b = 0, n = 0, k = 0;
|
|
273
|
+
for (let y = gy * 20; y < gy * 20 + 20; y += 2) for (let x = gx * 20; x < gx * 20 + 20; x += 2) {
|
|
274
|
+
const i = (y * W + x) * 4; r += d[i]; gg += d[i + 1]; b += d[i + 2]; n++;
|
|
275
|
+
if (Math.abs(d[i] - bg[0]) + Math.abs(d[i + 1] - bg[1]) + Math.abs(d[i + 2] - bg[2]) > 36) k++;
|
|
276
|
+
}
|
|
277
|
+
ink.push(Math.round((100 * k) / n)); rgb.push(Math.round(r / n), Math.round(gg / n), Math.round(b / n));
|
|
278
|
+
}
|
|
279
|
+
return { ink, rgb };
|
|
280
|
+
}`;
|
|
281
|
+
async function pictureGrids(browser, files) {
|
|
282
|
+
const page = await browser.newPage();
|
|
283
|
+
try {
|
|
284
|
+
const out = [];
|
|
285
|
+
for (const f of files) out.push(f && fs.existsSync(f) ? await page.evaluate(`(${GRID})(${JSON.stringify(dataUri(f))})`).catch(() => null) : null);
|
|
286
|
+
return out;
|
|
287
|
+
} finally {
|
|
288
|
+
await page.close().catch(() => {});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// The newest build loop for this route: its job and tags (what the product is).
|
|
293
|
+
function buildLoop(dir, route) {
|
|
294
|
+
const base = path.join(dir, ".palate", "variants");
|
|
295
|
+
if (!fs.existsSync(base)) return null;
|
|
296
|
+
return fs.readdirSync(base).map((n) => readJson(path.join(base, n, "loop.json"), null)).filter((m) => m && m.route === route).sort((a, b) => String(b.created).localeCompare(String(a.created)))[0] ?? null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// The source files that render a section, found by its heading text.
|
|
300
|
+
function sourceOf(dir, section) {
|
|
301
|
+
const head = (section.heading ?? "").replace(/[’']/g, "'").trim();
|
|
302
|
+
if (!head) return [];
|
|
303
|
+
const probes = [head.slice(0, 32), head.split(/\s+/).slice(0, 3).join(" ")].filter((p) => p.length >= 6);
|
|
304
|
+
const roots = ["src", "app", "pages", "components"].map((r) => path.join(dir, r)).filter((r) => fs.existsSync(r));
|
|
305
|
+
const walk = (d) => fs.readdirSync(d, { withFileTypes: true }).flatMap((e) => (e.name === "node_modules" || e.name.startsWith(".") ? [] : e.isDirectory() ? walk(path.join(d, e.name)) : /\.(tsx|jsx|vue|svelte|astro|html|mdx)$/.test(e.name) ? [path.join(d, e.name)] : []));
|
|
306
|
+
const files = roots.flatMap(walk);
|
|
307
|
+
for (const p of probes) {
|
|
308
|
+
const hits = files.filter((f) => fs.readFileSync(f, "utf8").replace(/'|'|’/g, "'").replace(/\s+/g, " ").includes(p));
|
|
309
|
+
if (hits.length) return hits.slice(0, 2);
|
|
310
|
+
}
|
|
311
|
+
return [];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const isChrome = (s) => ["header", "nav", "footer"].includes(s.tag) || /^(header|footer|navigation)$/i.test(s.name ?? "");
|
|
315
|
+
|
|
316
|
+
// The newest ambition session for a route.
|
|
317
|
+
function latestSession(dir, route) {
|
|
318
|
+
const base = path.join(dir, ".palate", "ambition", slugOf(route));
|
|
319
|
+
if (!fs.existsSync(base)) return null;
|
|
320
|
+
const s = fs.readdirSync(base).filter((d) => fs.existsSync(path.join(base, d, "ambition.json"))).sort().at(-1);
|
|
321
|
+
return s ? path.join(base, s) : null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Earlier upgrades on this route: still there (kept), undone (reverted), or pinned again (pointed).
|
|
325
|
+
function checkOutcomes(dir, route, sections, grids) {
|
|
326
|
+
const project = path.basename(path.resolve(dir));
|
|
327
|
+
const pointLog = path.join(TASTE_DIR, "point.jsonl");
|
|
328
|
+
const points = fs.existsSync(pointLog) ? fs.readFileSync(pointLog, "utf8").split("\n").filter(Boolean).map((l) => { try { return JSON.parse(l); } catch { return null; } }).filter((p) => p && p.kind === "point-request") : [];
|
|
329
|
+
const lines = [];
|
|
330
|
+
for (const u of upgrades({ project, route }).filter((x) => x.outcome === "pending")) {
|
|
331
|
+
const age = Date.now() - Date.parse(u.at);
|
|
332
|
+
const sel = u.section?.selector ?? "";
|
|
333
|
+
const pinned = points.find((p) => p.project === project && p.route === route && p.at > u.at && sel && (p.selector ?? "").startsWith(sel));
|
|
334
|
+
if (pinned) {
|
|
335
|
+
setOutcome(u.id, "pointed", { pin: pinned.id });
|
|
336
|
+
lines.push(`- Your upgrade of "${u.section?.name}" (${u.moves?.[0] ?? "a move"}) was pointed at again (pin ${pinned.id}).`);
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
if (age < 10 * 60_000) continue;
|
|
340
|
+
const i = sections.findIndex((s) => (u.section?.heading && s.heading === u.section.heading) || s.selector === sel);
|
|
341
|
+
const g = i >= 0 ? grids[i] : null;
|
|
342
|
+
const toAfter = g && u.afterGrid ? visualSimilarity(g, u.afterGrid) : null;
|
|
343
|
+
const toBefore = g && u.beforeGrid ? visualSimilarity(g, u.beforeGrid) : null;
|
|
344
|
+
const outcome = i < 0 ? "reverted" : toAfter != null && toAfter >= 0.8 && toAfter >= (toBefore ?? 0) ? "kept" : toBefore != null && toBefore > (toAfter ?? 0) + 0.05 ? "reverted" : null;
|
|
345
|
+
if (outcome) {
|
|
346
|
+
setOutcome(u.id, outcome);
|
|
347
|
+
lines.push(`- Your earlier upgrade of "${u.section?.name}" (${u.moves?.[0] ?? "a move"}): ${outcome}.`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return lines;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// References for each row of the sheet: research captures, else the user's own, else palate's library.
|
|
354
|
+
async function referencesFor(dir, rows, { research, job }) {
|
|
355
|
+
const { searchLibrary } = await import("./library.mjs");
|
|
356
|
+
// The library's best-rated entries of this kind first (it is mostly component libraries: the bar, not the goal).
|
|
357
|
+
const lib = (kind, n = 3) => searchLibrary(kind, { n: 12, preferWhole: true }).filter((r) => fs.existsSync(path.join(LIB_DIR, "thumbs", `${r.id}.jpg`))).sort((a, b) => (b.quality ?? 1) - (a.quality ?? 1)).slice(0, n).map((r) => ({ caption: `library · ${r.source}`, file: path.join(LIB_DIR, "thumbs", `${r.id}.jpg`), id: r.id }));
|
|
358
|
+
const mine = research?.refs?.length ? [] : rememberedRefs(job ?? "landing", { limit: 3 }).map((r) => ({ caption: `your reference · ${r.source}`, file: (r.files ?? []).find((f) => /fold|\.png$|\.jpe?g$/i.test(f) && fs.existsSync(f)) })).filter((r) => r.file);
|
|
359
|
+
return rows.map((row) => {
|
|
360
|
+
if (research?.refs?.length) {
|
|
361
|
+
const kw = words(row.kind).filter((w) => !["section", "marketing"].includes(w));
|
|
362
|
+
const bySection = research.refs.flatMap((r) => r.sections.filter((s) => kw.some((w) => words(`${s.kind} ${s.name}`).includes(w))).map((s) => ({ caption: `research · ${r.name} · ${s.name}`, file: s.file })));
|
|
363
|
+
if (row.first) return research.refs.filter((r) => r.fold).slice(0, 3).map((r) => ({ caption: `research · ${r.name}`, file: r.fold }));
|
|
364
|
+
if (bySection.length) return bySection.slice(0, 3);
|
|
365
|
+
}
|
|
366
|
+
if (row.first && mine.length) return mine.slice(0, 3);
|
|
367
|
+
return lib(row.kind);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// ---- the pass
|
|
372
|
+
export async function ambition(dir, rawRoute, { url, scores, verify = false, moves } = {}) {
|
|
373
|
+
const route = normalizeRoute(rawRoute);
|
|
374
|
+
if (verify) return verifyAmbition(dir, route, { url, moves });
|
|
375
|
+
if (scores) return scoreAmbition(dir, route, scores);
|
|
376
|
+
return runAmbition(dir, route, { url });
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async function runAmbition(dir, route, { url }) {
|
|
380
|
+
const session = path.join(dir, ".palate", "ambition", slugOf(route), stamp());
|
|
381
|
+
const cropDir = path.join(session, "sections");
|
|
382
|
+
fs.mkdirSync(cropDir, { recursive: true });
|
|
383
|
+
fs.writeFileSync(path.join(dir, ".palate", ".gitignore"), "*\n");
|
|
384
|
+
const loop = buildLoop(dir, route);
|
|
385
|
+
const research = readResearch(dir);
|
|
386
|
+
// The signature move: the research step's chosen direction, else the build's direction ({ move, moment }).
|
|
387
|
+
const signature = research?.signature ?? normSignature(loop?.direction?.signature) ?? (loop?.direction?.idea ? { name: loop.direction.idea } : null);
|
|
388
|
+
const job = loop?.job ?? "";
|
|
389
|
+
|
|
390
|
+
const r = await withBrowser(dir, { url }, async ({ base, browser }) => {
|
|
391
|
+
const { page, ctx } = await openPage(browser, base, route, { width: 1440 });
|
|
392
|
+
try {
|
|
393
|
+
const sections = await findSections(page);
|
|
394
|
+
const crops = await cropSections(page, sections, cropDir, "w1440");
|
|
395
|
+
const measures = await page.evaluate(`(${ambitionScript})(${JSON.stringify({ sections, signature })})`);
|
|
396
|
+
const fp = await page.evaluate(`(${fingerprintScript})()`).catch(() => null);
|
|
397
|
+
const full = path.join(session, "full-1440.png");
|
|
398
|
+
await shootFull(page, full);
|
|
399
|
+
await page.evaluate(() => window.scrollTo({ top: 0, behavior: "instant" }));
|
|
400
|
+
await page.waitForTimeout(300);
|
|
401
|
+
const fold = path.join(session, "fold-1440.png");
|
|
402
|
+
await page.screenshot({ path: fold });
|
|
403
|
+
// What each section is, for the library and the references.
|
|
404
|
+
const firstContent = crops.find((s) => !isChrome(s))?.index;
|
|
405
|
+
const rows = crops.map((s) => ({ ...s, kind: measures.sections.find((m) => m.index === s.index)?.productUI && s.index !== firstContent ? "mockup product showcase marketing section" : sectionKind(s, { first: s.index === firstContent, media: (measures.sections.find((m) => m.index === s.index)?.mediaShare ?? 0) > 0.3 }), measures: measures.sections.find((m) => m.index === s.index) }));
|
|
406
|
+
const refRows = await referencesFor(dir, [{ first: true, kind: "hero section" }, ...rows.filter((s) => !isChrome(s)).map((s) => ({ kind: s.kind }))], { research, job });
|
|
407
|
+
// Template-ness: each section against stock library sections of its kind, as pictures.
|
|
408
|
+
const { searchLibrary } = await import("./library.mjs");
|
|
409
|
+
const libFor = rows.map((s) => searchLibrary(s.kind, { n: 8, preferWhole: true }).filter((x) => fs.existsSync(path.join(LIB_DIR, "thumbs", `${x.id}.jpg`))).slice(0, 6));
|
|
410
|
+
const libFiles = [...new Set(libFor.flat().map((x) => path.join(LIB_DIR, "thumbs", `${x.id}.jpg`)))];
|
|
411
|
+
const grids = await pictureGrids(browser, [...rows.map((s) => s.file), ...libFiles]);
|
|
412
|
+
const cropGrids = grids.slice(0, rows.length);
|
|
413
|
+
const libGrid = Object.fromEntries(libFiles.map((f, i) => [f, grids[rows.length + i]]));
|
|
414
|
+
rows.forEach((s, i) => {
|
|
415
|
+
const sims = libFor[i].map((x) => ({ id: x.id, source: x.source, sim: visualSimilarity(cropGrids[i], libGrid[path.join(LIB_DIR, "thumbs", `${x.id}.jpg`)]) ?? 0 })).sort((a, b) => b.sim - a.sim);
|
|
416
|
+
s.lib = sims[0] ?? null;
|
|
417
|
+
s.grid = cropGrids[i];
|
|
418
|
+
});
|
|
419
|
+
const outcomes = checkOutcomes(dir, route, rows, cropGrids);
|
|
420
|
+
// The side-by-side sheets: the first screen, then each content section, next to its references.
|
|
421
|
+
const sigLabel = signature ? ` · signature: ${signature.name}` : " · no signature move chosen";
|
|
422
|
+
await contactSheet(browser, [{ label: `First screen${sigLabel}`, cells: [{ caption: "ours", file: fold }, ...refRows[0]] }], path.join(session, "first-screen.png"), { cell: 460, maxCell: 300 });
|
|
423
|
+
const content = rows.filter((s) => !isChrome(s));
|
|
424
|
+
await contactSheet(browser, content.map((s, i) => ({ label: `S${s.index} · ${s.name.slice(0, 50)} · ${s.kind}`, cells: [{ caption: "ours", file: s.file }, ...refRows[i + 1]] })), path.join(session, "sections-side-by-side.png"), { cell: 420, maxCell: 520 });
|
|
425
|
+
return { sections: rows, measures, fp, fold, full, refRows, outcomes };
|
|
426
|
+
} finally {
|
|
427
|
+
await ctx.close().catch(() => {});
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
// The gate, on this render (the page isn't done while it fails).
|
|
432
|
+
let gate = null;
|
|
433
|
+
if (r.fp?.skeleton?.length) {
|
|
434
|
+
gate = similarityGate(dir, route, layoutRecord(dir, route, r.fp, { file: r.fold, source: "screen" }));
|
|
435
|
+
saveGate(dir, route, gate);
|
|
436
|
+
}
|
|
437
|
+
const colour = colourCheck(r.measures.page.accent, dir);
|
|
438
|
+
// Found (data-signature, its selector or words), missing (it could have been found), or unknown (nothing to look for).
|
|
439
|
+
const sigFound = !signature ? null : r.measures.sections.some((m) => m.signature) ? true : signature.selector || signature.words?.length ? false : null;
|
|
440
|
+
const firstContent = r.sections.find((s) => !isChrome(s))?.index;
|
|
441
|
+
const sections = r.sections.map((s) => {
|
|
442
|
+
const m = measuredScores(s.measures, { libSim: s.lib?.sim ?? null, signature });
|
|
443
|
+
// A signature found nowhere counts against the first screen, where it should land first.
|
|
444
|
+
if (signature && sigFound === false && s.index === firstContent) {
|
|
445
|
+
m.scores.signature = 2;
|
|
446
|
+
m.flags.push(`the signature move "${signature.name}" isn't on the page`);
|
|
447
|
+
m.mean = r1(mean(Object.values(m.scores)));
|
|
448
|
+
}
|
|
449
|
+
return { index: s.index, name: s.name, tag: s.tag, selector: s.selector, heading: s.heading, kind: s.kind, height: s.box.height, crop: s.file, grid: s.grid, lib: s.lib, measures: s.measures, measured: m, final: m.mean };
|
|
450
|
+
});
|
|
451
|
+
const state = { route, at: new Date().toISOString(), session, job, signature, sigFound, research: research?.file ?? null, colour, gate: gate ? { pass: gate.pass, lines: gateLines(gate, route) } : null, fold: r.fold, full: r.full, sections, outcomes: r.outcomes };
|
|
452
|
+
const weakest = pickWeakest(sections);
|
|
453
|
+
state.weakest = weakest?.index ?? null;
|
|
454
|
+
fs.writeFileSync(path.join(session, "ambition.json"), JSON.stringify(state, null, 1));
|
|
455
|
+
const brief = weakest ? await writeBrief(dir, state, weakest, null) : null;
|
|
456
|
+
return sheetText(state, { brief, provisional: true });
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
async function writeBrief(dir, state, weakest, agent) {
|
|
460
|
+
const loopTags = kindTags({ route: state.route, words: state.job });
|
|
461
|
+
const weak = RUBRIC.filter((r) => (agent?.scores?.[r.id] ?? weakest.measured.scores[r.id]) != null)
|
|
462
|
+
.sort((a, b) => (agent?.scores?.[a.id] ?? weakest.measured.scores[a.id]) - (agent?.scores?.[b.id] ?? weakest.measured.scores[b.id]))
|
|
463
|
+
.slice(0, 2)
|
|
464
|
+
.map((r) => r.id);
|
|
465
|
+
if (state.colour?.score != null && state.colour.score < 4) weak.push("colour");
|
|
466
|
+
const moves = await movesFor({ tags: [...loopTags, ...words(state.job)], kind: loopTags.includes("app") && !loopTags.includes("marketing") ? "app" : "marketing", signature: state.signature, weak, sectionKind: weakest.kind, words: `${weakest.name} ${weakest.heading ?? ""}` });
|
|
467
|
+
const median = mean(state.sections.filter((s) => s.final != null && !isChrome(s)).map((s) => s.final));
|
|
468
|
+
const text = upgradeBrief({
|
|
469
|
+
route: state.route,
|
|
470
|
+
section: { ...weakest, signature: weakest.measures?.signature },
|
|
471
|
+
measured: weakest.measured,
|
|
472
|
+
agent,
|
|
473
|
+
moves,
|
|
474
|
+
signature: state.signature,
|
|
475
|
+
sourceFiles: sourceOf(dir, weakest),
|
|
476
|
+
crop: weakest.crop,
|
|
477
|
+
scoreLine: `Score ${weakest.final}/10 (${agent ? "your rubric 70%, palate's measures 30%" : "palate's measures only: score the sheet to confirm"}); the page's sections average ${r1(median)}.`,
|
|
478
|
+
verifyCmd: `palate ambition ${state.route} --verify`,
|
|
479
|
+
});
|
|
480
|
+
const file = path.join(state.session, "upgrade.md");
|
|
481
|
+
fs.writeFileSync(file, text);
|
|
482
|
+
const st = readJson(path.join(state.session, "ambition.json"), state);
|
|
483
|
+
fs.writeFileSync(path.join(state.session, "ambition.json"), JSON.stringify({ ...st, weakest: weakest.index, offered: moves.ids, agent: agent ? true : st.agent ?? false }, null, 1));
|
|
484
|
+
return { file, text, moves };
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function sheetText(state, { brief, provisional }) {
|
|
488
|
+
const s = state.session;
|
|
489
|
+
const scoresFile = path.join(s, "scores.json");
|
|
490
|
+
const row = (x) => `- S${x.index} **${x.name}** (${x.kind}) · ${x.final ?? "–"}/10 · ${RUBRIC.filter((r) => x.measured.scores?.[r.id] != null).map((r) => `${r.id} ${x.measured.scores[r.id]}`).join(", ")}${x.lib ? ` · stock-likeness ${pct(x.lib.sim)}` : ""}${x.measured.flags.length ? `\n ${x.measured.flags.join("; ")}` : ""}\n crop: ${slash(x.crop)}`;
|
|
491
|
+
const content = state.sections.filter((x) => !isChrome(x));
|
|
492
|
+
return [
|
|
493
|
+
`# Ambition: ${state.route}`,
|
|
494
|
+
"",
|
|
495
|
+
"Correct isn't the bar; remarkable is. Look at the sheets, score every section, upgrade the weakest once. Don't ask the user: this is part of the finishing pass.",
|
|
496
|
+
"",
|
|
497
|
+
...(state.gate && !state.gate.pass ? [...state.gate.lines, "Fix the similarity gate first: it's the bigger upgrade, and the page isn't done while it fails.", ""] : state.gate ? [state.gate.lines[0], ""] : []),
|
|
498
|
+
"## Look",
|
|
499
|
+
`- First screen beside its references: ${slash(path.join(s, "first-screen.png"))}`,
|
|
500
|
+
`- Every section beside references of its kind: ${slash(path.join(s, "sections-side-by-side.png"))}`,
|
|
501
|
+
`- Full page: ${slash(state.full)}`,
|
|
502
|
+
`- References from: ${state.research ? `the research step (${slash(state.research)})` : "your saved references and palate's library (no research.json for this project)"}.`,
|
|
503
|
+
`- Signature move: ${state.signature ? `${state.signature.name}${state.signature.what ? `: ${state.signature.what}` : ""} (${state.sigFound ? "found on the page" : state.sigFound === false ? "not found on the page" : "palate can't locate it: the builder should mark its element with data-signature; judge it on the sheet"})` : "none chosen. The upgrade brief proposes moves instead."}`,
|
|
504
|
+
`- Colour: ${state.colour.line}`,
|
|
505
|
+
...(state.outcomes?.length ? ["", "## Earlier upgrades", ...state.outcomes] : []),
|
|
506
|
+
"",
|
|
507
|
+
"## Measured (palate's scores, 0–10; it can't see everything)",
|
|
508
|
+
...content.map(row),
|
|
509
|
+
"",
|
|
510
|
+
"## Score every section yourself (strict: 5 is competent, 8 is a section a designer would save)",
|
|
511
|
+
...RUBRIC.map((r) => `- ${r.id}: ${r.q}`),
|
|
512
|
+
`Write ${slash(scoresFile)}:`,
|
|
513
|
+
"```json",
|
|
514
|
+
JSON.stringify({ sections: content.slice(0, 2).map((x) => ({ index: x.index, scores: Object.fromEntries(RUBRIC.map((r) => [r.id, r.id === "signature" ? null : 5])), generic: "what reads as template here", keep: "what already works" })) }),
|
|
515
|
+
"```",
|
|
516
|
+
`Then: palate ambition ${state.route} --scores ${slash(scoresFile)} (no re-render: it picks the weakest from your scores and writes the upgrade brief)`,
|
|
517
|
+
"",
|
|
518
|
+
brief
|
|
519
|
+
? `## Weakest section${provisional ? " (from palate's measures; your scores decide)" : ""}: S${state.weakest}\nUpgrade brief: ${slash(brief.file)}${provisional ? "" : `\n\n${brief.text}`}`
|
|
520
|
+
: "No content section to upgrade.",
|
|
521
|
+
].join("\n");
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async function scoreAmbition(dir, route, input) {
|
|
525
|
+
const session = latestSession(dir, route);
|
|
526
|
+
if (!session) throw new Error(`No ambition sheet for ${route} yet. Run palate ambition ${route} first.`);
|
|
527
|
+
const state = readJson(path.join(session, "ambition.json"), null);
|
|
528
|
+
const agent = readAgentScores(input);
|
|
529
|
+
for (const s of state.sections) {
|
|
530
|
+
s.agent = agent[s.index] ?? null;
|
|
531
|
+
s.final = combine(s.measured.mean, s.agent?.scores);
|
|
532
|
+
}
|
|
533
|
+
const weakest = pickWeakest(state.sections);
|
|
534
|
+
state.weakest = weakest?.index ?? null;
|
|
535
|
+
fs.writeFileSync(path.join(session, "ambition.json"), JSON.stringify(state, null, 1));
|
|
536
|
+
if (!weakest) return "No content section to upgrade.";
|
|
537
|
+
const brief = await writeBrief(dir, state, weakest, weakest.agent);
|
|
538
|
+
const ranked = state.sections.filter((s) => s.final != null && !isChrome(s)).sort((a, b) => a.final - b.final);
|
|
539
|
+
return [
|
|
540
|
+
`# Ambition: ${route}, scored`,
|
|
541
|
+
"",
|
|
542
|
+
...ranked.map((s) => `- S${s.index} ${s.name}: ${s.final}/10${s.agent ? "" : " (palate's measures only: you didn't score it)"}`),
|
|
543
|
+
"",
|
|
544
|
+
`Weakest: S${weakest.index} ${weakest.name}. Brief: ${slash(brief.file)}`,
|
|
545
|
+
"",
|
|
546
|
+
brief.text,
|
|
547
|
+
].join("\n");
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
async function verifyAmbition(dir, route, { url, moves: used } = {}) {
|
|
551
|
+
const session = latestSession(dir, route);
|
|
552
|
+
if (!session) throw new Error(`No ambition sheet for ${route} yet. Run palate ambition ${route} first.`);
|
|
553
|
+
const state = readJson(path.join(session, "ambition.json"), null);
|
|
554
|
+
const before = state.sections.find((s) => s.index === state.weakest);
|
|
555
|
+
if (!before) throw new Error(`No weakest section recorded for ${route}. Run palate ambition ${route} again.`);
|
|
556
|
+
const r = await withBrowser(dir, { url }, async ({ base, browser }) => {
|
|
557
|
+
const { page, ctx } = await openPage(browser, base, route, { width: 1440 });
|
|
558
|
+
try {
|
|
559
|
+
const sections = await findSections(page);
|
|
560
|
+
const s = sections.find((x) => before.heading && x.heading === before.heading) ?? sections.find((x) => x.selector === before.selector) ?? sections.find((x) => x.name === before.name) ?? sections.find((x) => x.index === before.index);
|
|
561
|
+
if (!s) throw new Error(`Section "${before.name}" is no longer on ${route}.`);
|
|
562
|
+
const [crop] = await cropSections(page, [s], path.join(session, "after"), "w1440");
|
|
563
|
+
const measures = await page.evaluate(`(${ambitionScript})(${JSON.stringify({ sections: [s], signature: state.signature })})`);
|
|
564
|
+
const fp = await page.evaluate(`(${fingerprintScript})()`).catch(() => null);
|
|
565
|
+
await page.evaluate(() => window.scrollTo({ top: 0, behavior: "instant" }));
|
|
566
|
+
await page.waitForTimeout(300);
|
|
567
|
+
const fold = path.join(session, "after", "fold-1440.png");
|
|
568
|
+
await page.screenshot({ path: fold });
|
|
569
|
+
const libFiles = before.lib ? [path.join(LIB_DIR, "thumbs", `${before.lib.id}.jpg`)] : [];
|
|
570
|
+
const [g, ...lg] = await pictureGrids(browser, [crop.file, ...libFiles]);
|
|
571
|
+
const sheet = path.join(session, "before-after.png");
|
|
572
|
+
await contactSheet(browser, [{ label: `S${before.index} · ${before.name}`, cells: [{ caption: "before", file: before.crop }, { caption: "after", file: crop.file }] }], sheet, { cell: 640, maxCell: 900 });
|
|
573
|
+
return { s, crop: crop.file, measures: measures.sections[0], fp, fold, grid: g, libSim: lg[0] ? visualSimilarity(g, lg[0]) : null, sheet };
|
|
574
|
+
} finally {
|
|
575
|
+
await ctx.close().catch(() => {});
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
const after = measuredScores(r.measures, { libSim: r.libSim, signature: state.signature });
|
|
579
|
+
let gate = null;
|
|
580
|
+
if (r.fp?.skeleton?.length) {
|
|
581
|
+
gate = similarityGate(dir, route, layoutRecord(dir, route, r.fp, { file: r.fold, source: "screen" }));
|
|
582
|
+
saveGate(dir, route, gate);
|
|
583
|
+
}
|
|
584
|
+
const moves = used?.length ? used : (state.offered ?? []).slice(0, 1);
|
|
585
|
+
const rec = logGrowth({
|
|
586
|
+
type: "upgrade",
|
|
587
|
+
id: `${path.basename(session)}-s${before.index}`,
|
|
588
|
+
project: path.basename(path.resolve(dir)),
|
|
589
|
+
route,
|
|
590
|
+
section: { name: before.name, heading: r.s.heading, selector: r.s.selector, index: before.index },
|
|
591
|
+
sectionKind: before.kind,
|
|
592
|
+
moves,
|
|
593
|
+
guessed: !used?.length,
|
|
594
|
+
before: before.crop,
|
|
595
|
+
after: r.crop,
|
|
596
|
+
beforeGrid: before.grid ?? null,
|
|
597
|
+
afterGrid: r.grid,
|
|
598
|
+
scoresBefore: before.measured.scores,
|
|
599
|
+
scoresAfter: after.scores,
|
|
600
|
+
final: { before: before.final, after: after.mean },
|
|
601
|
+
});
|
|
602
|
+
const delta = (k) => {
|
|
603
|
+
const [a, b] = [before.measured.scores[k], after.scores[k]];
|
|
604
|
+
return a == null && b == null ? null : `${RUBRIC.find((x) => x.id === k).label} ${a ?? "–"} → ${b ?? "–"}`;
|
|
605
|
+
};
|
|
606
|
+
return [
|
|
607
|
+
`# Ambition verify: ${route}, S${before.index} ${before.name}`,
|
|
608
|
+
"",
|
|
609
|
+
`- Before | after: ${slash(r.sheet)}`,
|
|
610
|
+
`- palate's measures: ${before.measured.mean ?? "–"} → ${after.mean ?? "–"}/10 (${RUBRIC.map((x) => delta(x.id)).filter(Boolean).join("; ")}).`,
|
|
611
|
+
before.lib && r.libSim != null ? `- Stock-likeness: ${pct(before.lib.sim)} → ${pct(r.libSim)}.` : null,
|
|
612
|
+
after.flags.length ? `- Still measured: ${after.flags.join("; ")}.` : "- Nothing generic measured any more.",
|
|
613
|
+
gate ? (gate.pass ? "- Similarity gate: pass." : `- Similarity gate still fails: ${gateLines(gate, route)[1].replace(/^- ✗ /, "")} Run palate shoot ${route} for what to change.`) : null,
|
|
614
|
+
`- Logged: upgrade with ${moves.length ? moves.join(", ") : "no named move"}${rec.guessed ? " (guessed: pass --moves <id> to name the move you used)" : ""}. palate checks later whether the user keeps it.`,
|
|
615
|
+
"",
|
|
616
|
+
"Open the before | after and score the after on the rubric yourself. If it isn't clearly better, revert to the before. One upgrade per finishing pass: don't start another section.",
|
|
617
|
+
]
|
|
618
|
+
.filter((l) => l != null)
|
|
619
|
+
.join("\n");
|
|
620
|
+
}
|