diff --git a/.changeset/clear-pages-compose.md b/.changeset/clear-pages-compose.md new file mode 100644 index 0000000000..ceca053428 --- /dev/null +++ b/.changeset/clear-pages-compose.md @@ -0,0 +1,9 @@ +--- +'@primer/brand-mcp': patch +--- + +Improves guidance and examples delivered through the Primer Brand MCP tools: + +- Improves guidance delivered through the `primer_brand_review` tool. +- Cleaner output from the `primer_brand_examples` tool. +- Add new page design guidance advising that `River` descriptions are limited to 160 characters and the default `50:50` image-to-text ratio is preferred. diff --git a/apps/next-docs/content/components/River/index.mdx b/apps/next-docs/content/components/River/index.mdx index 6791406c03..6767787203 100644 --- a/apps/next-docs/content/components/River/index.mdx +++ b/apps/next-docs/content/components/River/index.mdx @@ -19,7 +19,7 @@ import dontVisuals from './images/dont-visuals-size.png' Use rivers to showcase features and introduce topics. Rivers are composed of images or videos paired alongside text content like headings, paragraphs, and links. -A river’s content should be short and concise, no longer than 3 or 4 sentences and in a single paragraph when possible. +A river’s content should be short and concise, no longer than 160 characters, and contained in a single paragraph when possible. @@ -34,20 +34,9 @@ A river’s content should be short and concise, no longer than 3 or 4 sentences ### Stacked -Two or more rivers can be stacked to guide the user through a set of features. When stacking rivers, alternate between left and right alignments to create a more dynamic reading flow. When alternating alignments, use a `40:60` image to text ratio, otherwise keep the ratio to `50:50`. +Two or more rivers can be stacked to guide the user through a set of features. Keep rivers in a stack consistently aligned to create a predictable reading flow. For gridline rivers, always use start alignment. Don't use zig-zag layouts. -It is possible to use 2 or more following left or right river to create a simple alignment promoting easy scroll scan. - - - - - Alternate rivers with left and right alignments. - - - - Don't break the flow in a stack of rivers that would otherwise stay aligned. - - +Prefer the default 50:50 image-to-text ratio where possible. Use 60:40 only when the visual needs more space or emphasis. Note that too many rivers can make the design feel repetitive. In that situation, consider introducing a breakout section or break the content with a different component, such as [pillar](/components/Pillar) or [card](/components/Card) to provide a better visual hierarchy and experience. For example, use the river for the top features you want to highlight and then use pillars to showcase the rest. @@ -179,7 +168,7 @@ The image is automatically styled to fit the width of the parent container. If y - We recommend using a river left as the first river of the flow to start with a visual and avoid stacking text with above section on mobile - River components stacks create a unit, the set should be considered to be the main parent section. The parent section should be spaced as a regular section with the largest spacing while internal elements should use smaller spacing -- If the image is critical for the user to understand the message, default to right aligned. If the text is critical for the user to understand the image, choose left aligned. +- For a standalone river, choose its alignment based on whether the visual or text needs emphasis. Keep every river in a stack consistently aligned. ### Link diff --git a/packages/e2e/scripts/playwright/axe-clean.spec.ts b/packages/e2e/scripts/playwright/axe-clean.spec.ts index 0dc063944f..e866b17216 100644 --- a/packages/e2e/scripts/playwright/axe-clean.spec.ts +++ b/packages/e2e/scripts/playwright/axe-clean.spec.ts @@ -40,8 +40,6 @@ const testsToSkip = [ 'components-videoplayer-features--with-poster', // video makes this too flakey 'components-videoplayer-features--without-branding', // video makes this too flakey 'components-videoplayer--playground', // video makes this too flakey - 'recipes-feature-previews-level-1--level-one-side-by-side-enterprise', // video makes this too flakey - 'recipes-feature-previews-level-1--level-one-side-by-side', // custom, unrelated background image 'components-eyebrowbanner-features--on-custom-background-dark', // custom, unrelated background image 'components-eyebrowbanner-features--on-custom-background-light', // custom, unrelated background image 'components-subdomainnavbar--skip-to-main-tag', // contains main tag which is in conflict with the default role="main" element @@ -60,7 +58,7 @@ const testsToSkip = [ const ignoreViolations = { 'landmark-one-main': {except: []}, // on most of the stories we don't have a main landmark - 'page-has-heading-one': {except: ['components-hero', 'recipes-feature-previews']}, // on some stories we dont have a heading, + 'page-has-heading-one': {except: ['components-hero']}, // on some stories we dont have a heading, region: {except: []}, // on most of the stories we don't have a region landmark } diff --git a/packages/e2e/scripts/playwright/playwright.generate-tests.ts b/packages/e2e/scripts/playwright/playwright.generate-tests.ts index 9f010db9d1..08c2be5f35 100644 --- a/packages/e2e/scripts/playwright/playwright.generate-tests.ts +++ b/packages/e2e/scripts/playwright/playwright.generate-tests.ts @@ -65,41 +65,11 @@ const waitForTimeoutLookup = { 'components-box-features--animation': 6000, // for the animation 'components-ide--playground': 2000, // for the animation 'components-ide--default': 2000, // for the animation - 'recipes-seo-article-page--playground': 5000, // for the animation - 'recipes-seo-article-page--all-headings': 5000, // for the animation - 'recipes-seo-article-page--ai-theme': 5000, // for the animation - 'recipes-seo-article-page--collaboration-theme': 5000, // for the animation - 'recipes-seo-article-page--enterprise-theme': 5000, // for the animation - 'recipes-seo-article-page--security-theme': 5000, // for the animation - 'recipes-seo-article-page--productivity-theme': 5000, // for the animation - 'recipes-seo-article-page--light-hero-image': 5000, // for the animation - 'recipes-seo-article-page--dark-hero-image': 5000, // for the animation - 'recipes-solutions-categorypage--light': 4000, // for the animation - 'recipes-solutions-categorypage--dark': 4000, // for the animation - 'recipes-solutions-solution-industry--maximum': 3500, // for the animation - 'recipes-solutions-solution-industry--maximum-dark': 3500, // for the animation - 'recipes-solutions-solution-industry--minimum': 3500, // for the animation - 'recipes-solutions-solution-industry--minimum-dark': 3500, // for the animation - 'recipes-solutions-solution-org-size--maximum': 3500, // for the animation - 'recipes-solutions-solution-org-size--maximum-dark': 3500, // for the animation - 'recipes-solutions-solution-org-size--minimum': 3500, // for the animation - 'recipes-solutions-solution-org-size--minimum-dark': 3500, // for the animation - 'recipes-solutions-solution-use-case--minimum': 2000, // for the footer logos - 'recipes-solutions-solution-use-case--minimum-dark': 2000, // for the footer logos - 'recipes-solutions-solution-use-case--maximum-dark': 2000, // for the footer logos - 'recipes-solutions-solution-use-case--maximum': 2000, // for the footer logos - 'recipes-solutions-overview--light': 3500, // for the animation - 'recipes-solutions-overview--dark': 3500, // for the animation 'components-riverstoryscroll--default': 3500, // for the animation 'components-riverstoryscroll-features--with-timeline': 3500, // for the animation 'components-riverstoryscroll-features--with-timeline-narrow': 3500, // for the animation 'components-riverstoryscroll-features--enterprise-example': 3500, // for the animation 'components-riverstoryscroll-features--enterprise-example-narrow': 3500, // for the animation - 'recipes-feature-previews-level-2--level-two-playground': 4000, // for the animation - 'recipes-feature-previews-level-2--level-two-point-one': 4000, // for the animation - 'recipes-feature-previews-level-2--level-two-point-two': 4000, // for the animation - 'recipes-feature-previews-level-2--level-two-point-three': 4000, // for the animation - 'recipes-feature-previews-level-2--level-two-point-four': 4000, // for the animation 'components-textrevealanimation--playground': 3000, // for the animation 'components-textrevealanimation-examples--with-large-testimonial': 3000, // for the animation 'components-textrevealanimation-examples--with-hero': 3000, // for the animation @@ -131,9 +101,7 @@ const waitForTimeoutLookup = { 'components-videoplayer-features--tooltip-visible-on-focus': 5000, // for video metadata to load 'components-hero-features-images-and-videos--with-video-block-end-default': 5000, // for video metadata to load 'components-hero-features-images-and-videos--with-video-inline-end': 5000, // for video metadata to load - 'recipes-flextemplate-flextemplate--default': 4000, // for video metadata to load 'components-textcursoranimation--playground': 4000, // for the animation to complete - 'recipes-flextemplate-flexsection--default': 1000, // longer load time 'components-subnav-features--delayed-active-link': 2000, // because the story sets an initial delay, 'components-logosuite-features--grid-line-expressive-kitchen-sink': 3000, // for the animation to complete 'components-logosuite-features--takeover-button': 3000, // for the animation to complete @@ -177,7 +145,6 @@ const skipTestLookup = [ 'components-logosuite-features--mixed-width', // animation only 'components-logosuite-features--following-hero', // animation only 'components-logosuite-features--stacked', // animation only - 'recipes-feature-previews-level-1--level-one-side-by-side-enterprise', // video makes this too flakey 'components-subdomainnavbar--overflow-menu-open', // flakey despite timeout 'components-ide-features--editor-only', // animation too long 'components-ide-features--editor-no-replay-button', // animation too long @@ -187,7 +154,6 @@ const skipTestLookup = [ 'components-ide-features--perspective-example-light', // animation too long 'components-ide-features--all-glass', // animation too long 'components-ide-features--editor-custom-icons', // animation too long - 'recipes-seo-category-page--default', // template contains randomisation 'components-statistic-features--animations', // animation only 'components-riverstoryscroll-features--video-narrow', // video makes this too flakey 'components-riverstoryscroll-features--video', // video makes this too flakey diff --git a/packages/mcp/content/page-design.md b/packages/mcp/content/page-design.md index d5719afe41..10626be0f5 100644 --- a/packages/mcp/content/page-design.md +++ b/packages/mcp/content/page-design.md @@ -1,6 +1,6 @@ # Page design patterns -These are the page design guidelines for GitHub marketing and landing pages, beyond what the component APIs or documentation guidelines recommend. Apply these by default unless the brief says otherwise. These are **design conventions** and the `primer_brand_review` tool does not flag them, so consult this before composing a page. +These page-level guidelines complement the component APIs and documentation. Apply them unless the brief says otherwise. `primer_brand_review` catches some code-level mistakes automatically, but it cannot judge every visual or layout decision; use this guide for the full composition rules. Learn individual component APIs and usage with `primer_brand_docs` and `primer_brand_component`. This guide is the step after: how to lay out an entire page and use those components alongside your custom ones correctly. @@ -36,69 +36,161 @@ Every full page should be framed top and bottom, unless the user has requested a ### Contain content within the grid -Body content must always sit in a centered, max-width column framed by the brand's gridlines — it should rarely stretch edge-to-edge. +Body content must sit in one centered, max-width grid framed by the brand's gridlines — it should rarely stretch edge-to-edge. Examples of this are in the Flexsuite recipes. -- **Do** — keep content (heroes, rivers, tables, card grids, CTAs, prose) in a shared max-width column with clear left and right gutters, and let thin ruled gridlines run down both sides of the column with full-bleed horizontal rules between major sections. -- **Don't** — stretch tables, card grids, CTAs, or text edge-to-edge, or let a section bleed full-width unless it is a deliberate background band. +- **Do** — keep heroes, `River`s, `ComparisonTable` / `PricingOptions`, connected Card or Pillar groups, forms, `CTABanner`s, and prose on the same `Grid` / `Section` column. Draw thin side rules on the column and full-bleed horizontal rules between major sections. +- **Don't** — give each section a different width, stretch content edge-to-edge, or let a section bleed full-width unless it is a deliberate background band behind the shared grid. - **Mobile** — use a modest, consistent side inset and make sure nothing overflows the viewport. Resolve gutter, inset, and gridline (border) values with `primer_brand_tokens`; don't hardcode hex or pixel values. -### Spacing +### Responsive rules Generous spacing is what lets a layout breathe; the Flexsuite recipes are a good reference for the rhythm to aim for. -- **Do** — use `Box` and `Stack` (both have responsive spacing props) to add consistent rhythm between sections, and take spacing steps from the standard scale so gaps repeat predictably across sections and inside cards. +- **Do** — use `Box` and `Stack` responsive spacing props and the established scale. Useful page-composition steps include `--base-size-20` for narrow gutters, `--base-size-60` / `--base-size-64` for regular section rhythm, and `--base-size-80` for wide breathing room. +- **Do** — match the canonical wide `Grid` / container gutter instead of reproducing reviewed measurements as hardcoded values. - **Don't** — pack sections edge-to-edge, hand-roll ad-hoc margins, or invent one-off gap values. ### Typographic hierarchy A page has one clear headline and a calm step-down from there. -- **Do** — use a single hero heading, make secondary section headings a clear step smaller, and set body copy at the standard body size and weight. Left-align long-form copy; reserve centering for short hero or section intros. +- **Do** — use a single hero heading, make secondary section headings a clear step smaller, and keep body copy regular weight. Left-align long-form copy; reserve centering for short hero or section intros. - **Don't** — size secondary headings close to the hero, set body text in heavy weights, or center long paragraphs. Resolve exact sizes and weights with `primer_brand_tokens`. ## Component & element patterns -### Heroes carry media +### Hero -A text-only hero reads as unfinished; heroes should carry a visual and lead with a label. +**Do** -- **Do** — give `Hero` a `Hero.Image` (or `Hero.Video`); source imagery from `primer_brand_asset` (Octovisuals) or generate it with the Asset Generator MCP (see _Generated imagery_ below). Lead the hero with an eyebrow label (see _Labels hug their content_), and bound decorative or illustrative media with a set aspect ratio and max height so it stays inside the grid. -- **Don't** — ship a bare, text-only hero, drop the eyebrow, or let an illustration run arbitrarily tall or bleed full-width. +- Include relevant media and a label. Prefer a real product shot via `Hero.Image` / `Hero.Video`; use Asset Generator `create_product_landscape` when generating one, or `create_wallpaper` when a product shot does not fit. +- Keep decorative or illustrative media inside the shared grid with a stable aspect ratio and a token-backed maximum height so it cannot dominate the page or bleed full-width. +- If needed, place custom media after `Hero`; use `trailingComponent` only when it must live inside the Hero composition. -### Generated imagery adds color and interest +**Don't** -Bring on-brand color and life to the page with the Asset Generator MCP (when installed) instead of leaving large areas flat — most pages want at least one generated visual. +- Add irrelevant hero media or use social templates such as `create_social_square` or `create_landscape` for hero media. +- Let decorative or illustrative Hero media grow arbitrarily tall or bleed outside the shared grid. -- **Do** — use **`create_product_landscape`** when the visual demos a product or feature (a hero or section showing the thing itself), and **`create_wallpaper`** for everything else, to add a colorful on-brand backdrop or accent. Browse the current set with `list_templates` / `list_themes` and pick a theme that fits the page's topic. -- **Don't** — reach for social media-specific templates like `create_social_square` or `create_landscape` when a product shot or wallpaper fits better. +### River -### Group cards inside gridlines +**Do** -A grid of items (features, pathways, plans) uses the connected **gridline** grid, not floating cards. +- Use `` throughout a page; omitting `align` also means start. +- Keep River descriptions to a maximum of 160 characters. +- Prefer the default `50:50` image-to-text ratio where possible; set `imageTextRatio="60:40"` only when the visual needs more space or emphasis. -- **Do** — render a `Grid` with `columnGap="none" rowGap="none" enableGutters={false}` inside a bordered frame and let the frame draw the shared lines. Refer to the Flexsuite recipes for an example of this. -- **Don't** — output separate bordered `Card`s with gaps between them. +**Don't** -### Labels hug their content +- Zigzag gridline Rivers with `align="end"`. -Lead heroes and sections with an eyebrow/section label; it is intrinsic width, and stretching it reads as off-brand. +### Repeated panels -- **Do** — use `Hero.Label` / `SectionIntro.Label` / `EyebrowText` for the standard treatment (a short, monospace, uppercase label) and let it size to its content; alignment follows the section (start by default, or centered inside a centered `SectionIntro`). -- **Don't** — set a label full-width, give it a block/full-bleed background, or hand-style your own instead of the label components. +**Do** -### Sweat the small details +- Place `Card`, `Pillar`, `Box`, or custom items in a square frame using ``. +- Draw shared dividers on custom frame/cell wrappers and use `border-radius: 0` there. -Small, repeated treatments are where a page quietly drifts off-brand. +**Don't** -- **Do** — use dot bullets for lists; keep buttons in their real interactive states (hover/active) and use a `Button` for a primary CTA rather than a bare link; show FAQ/accordion category navigation only when there are several categories; leave `Icon` at its default color — which renders green — wherever Octicons appear (`Card.Icon`, `Pillar.Icon`, and standalone `Icon`) so icons read as one consistent accent. -- **Don't** — use dashes as bullets, add divider rules between list items or sections, ship flat/stateless buttons, render an empty single-category sidebar, or override the `color` prop on `Icon` or `Card.Icon` to tint icons off-green without a strong, deliberate reason (`Pillar.Icon` has no `color` prop — it's already locked to green). +- Render repeated panels as separate rounded cards, double their shared borders, or override `Card` / `Pillar` internals. +- `Pillar` has no grid variant; don't invent one. -## General guidance +### CTABanner -- If browser tooling (e.g. the Playwright MCP) is available, verify your work visually before finishing: serve the page locally, open it, and take screenshots across different breakpoints. Review the screenshots against this guidance and automatically fix obvious defects like content that bleeds edge-to-edge instead of sitting in the gridline column, clipped or overflowing content, cramped or one-off spacing, stretched/full-width labels that should preserve their intrinsic width, a hero with no eyebrow, an illustration that runs too tall, dashes used as bullets, low-contrast text, a text-only hero, broken images, and off-brand tells (glows, purple gradients, pill buttons, glassmorphism, placeholder copy). Re-screenshot to confirm the fixes. +**Do** + +- Without media, use the default `CTABanner` with `align="center"` and `hasGridLines`. +- With media, use `` with a direct `CTABanner.Image`. Use Octovisuals for artwork; reserve `CTABanner.Logo` for genuine logos. + +**Don't** + +- Use `CTABanner variant="balanced"` without a direct `CTABanner.Image`, or use `CTABanner.Logo` for decorative artwork. + +### Forms + +**Do** + +- Use a square, zero-gap `Grid` with connected benefits beside a subtle form surface. Use responsive token gutters, Primer Brand form controls, and an enabled `