Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions .cursor-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
{
"name": "codecademy-gamut-cursor",
"name": "gamut",
"owner": {
"name": "Codecademy"
},
"metadata": {
"description": "Cursor plugins for the Gamut design system: core usage, accessibility, and theming."
"description": "Gamut design system agent pack (Cursor + Claude): consumption, accessibility, and theming. Single plugin; see packages/agent-plugin."
},
"plugins": [
{
"name": "codecademy-gamut",
"source": "gamut-cursor-plugins/gamut-core",
"description": "Core Gamut consumption: layout, system props, gamut-styles utilities, ESLint alignment, Storybook links."
},
{
"name": "codecademy-gamut-a11y",
"source": "gamut-cursor-plugins/gamut-a11y",
"description": "WCAG-minded Gamut usage and composition when primitives are incomplete."
},
{
"name": "codecademy-gamut-themes",
"source": "gamut-cursor-plugins/gamut-themes",
"description": "ColorMode, Background, semantic tokens, hooks, and platform themes."
"name": "gamut",
"source": "packages/agent-plugin",
"description": "Core Gamut usage, accessibility patterns, and ColorMode/Background theming for application code. Rules + skills; canonical docs in docs/agents/."
}
]
}
2 changes: 1 addition & 1 deletion .cursor/rules/gamut-component-building.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ alwaysApply: false
- **TypeScript** — Derive props from implementation: `StyleProps<typeof composed>` after `variance.compose` / `variant`; `ComponentProps<typeof StyledX>` for Emotion styled roots; intersect with bases (`ButtonBaseProps & ComponentProps<typeof ButtonBase>`). Model variant-specific APIs with discriminated unions and `never` for illegal combos. Narrow handlers with `HTMLProps<…>['onClick']` or `ComponentProps<typeof Child>[…]`. Exemplars: `Tag/types.tsx`, `Badge/index.tsx`, `Button/shared/types.ts`, `Form/elements/Form.tsx`, `Anchor/index.tsx`.
- **React** — Match neighboring `React.FC<Props>` usage; use `forwardRef` when refs matter; follow Rules of Hooks, effect cleanup, and composition over huge prop lists; prefer semantic DOM and Gamut a11y patterns.
- **Tokens / ColorMode** — Semantic colors and gamut-styles tokens: see `.cursor/rules/gamut-library.mdc`.
- **Depth** — Full checklists and links: **gamut-library-authoring** skill (`.cursor/skills/gamut-library-authoring/SKILL.md`) and [reference.md](.cursor/skills/gamut-library-authoring/reference.md).
- **Depth** — Full checklists and links: **[`docs/agents/gamut-library-authoring.md`](docs/agents/gamut-library-authoring.md)** and `.cursor/skills/gamut-library-authoring/SKILL.md`.
163 changes: 11 additions & 152 deletions .cursor/rules/gamut-figma-rules.mdc
Original file line number Diff line number Diff line change
@@ -1,160 +1,19 @@
---
description: Figma Dev Mode MCP rules
description: Figma → Gamut implementation (MCP / Dev Mode); mandatory checks before codegen
alwaysApply: true
---

# Figma Dev Mode MCP Rules
# Figma → Gamut (editor rule)

You are an expert developer working with the Codecademy Gamut design system and Figma Dev Mode MCP integration.
**Canonical, tool-agnostic guide:** [`docs/agents/figma-from-design.md`](docs/agents/figma-from-design.md) — follow it in full when implementing from Figma.

When generating code from Figma designs, follow these rules:
## Mandatory (summary)

## MANDATORY Pre-Generation Steps
1. Inspect Figma layer / component metadata with your Figma integration; if icon or nested names are missing, infer from visuals, **verify icons exist** under `packages/gamut-icons`, then confirm with the user after generating code.
2. **Read** `packages/gamut-styles/src/variables/spacing.ts`, `colors.ts`, `typography.ts`, and `borderRadii.ts` before changing visuals.
3. **Search** `packages/gamut/src` (and patterns/icons/illustrations packages) for existing components; extend instead of duplicating.
4. Use **tokens and semantic colors** only (no ad hoc hex or raw `'NNpx'` where a token exists); use Emotion + `@codecademy/gamut-styles` patterns (`system.css`, `variant`, `styledOptions`, `variance.compose`) like the rest of Gamut.
5. Map UI to **`@codecademy/gamut`**, **`gamut-patterns`**, **`gamut-icons`**, **`gamut-illustrations`** per design; use real Figma/MCP assets when URLs are provided—no placeholders.
6. Meet **WCAG** expectations; align with `packages/styleguide/src/lib/Meta/Best practices.mdx`.

**BEFORE generating ANY code from Figma, you MUST:**

1. **Inspect the Figma layer hierarchy**:

- Call `get_metadata` WITH the nodeId to get parent component info
- Call `get_metadata` WITHOUT nodeId (empty string) to attempt to get CHILD layers
- **IMPORTANT**: Current limitation - `get_metadata` may not return nested child layer names (icons, nested components, etc.)
- **If child layer names are not available from tooling:**
- Analyze the screenshot and make your best guess about which icons/nested components are used
- Look for visual clues (user icon, gear icon, etc.) and match them to likely Gamut icon names
- Search the codebase to verify the icon exists (e.g., check for `PersonIcon`, `GearIcon`, etc. in `/packages/gamut-icons/src`)
- Generate the code using your best guess
- **AFTER generating the code**, ask the user to confirm the icons are correct
- Example: "I've generated the code using PersonIcon and GearIcon based on what I see in the screenshot. Can you confirm these are the correct icons from the Figma layers?"
- Map icon layer names to components in the codebase (e.g., "Regular/Interface/PersonIcon" → `PersonIcon`, "Mini/MiniCheckCircleIcon" → `MiniCheckCircleIcon`)

2. **Read token files** (use read_file tool on ALL of these):

- `/packages/gamut-styles/src/variables/spacing.ts`
- `/packages/gamut-styles/src/variables/colors.ts`
- `/packages/gamut-styles/src/variables/typography.ts`
- `/packages/gamut-styles/src/variables/borderRadii.ts`

3. **Search for existing components** (use codebase_search):

- Check if similar component exists in `/packages/gamut/src`
- If exists, extend it instead of creating new one

4. **Understand the design system patterns**:
- Read example components like Badge, Tag, or Button
- Follow variance, system props, and styledOptions patterns

## Asset Management

- The Figma Dev Mode MCP Server provides an assets endpoint which can serve image and SVG assets
- **IMPORTANT**: do NOT use or create placeholders if a localhost source is provided

## Component Usage

- **IMPORTANT**: Always use components from `/packages` whenever possible
- Check if the Figma component name matches a Gamut component name and use that component
- **IMPORTANT**: All patterns should come from `/packages/gamut-patterns` - use the design's metadata to match the Figma component name to the pattern component
- **IMPORTANT**: All illustrations should come from `/packages/gamut-illustrations` - use the design's metadata to match the Figma component name to the illustration component
- **IMPORTANT**: All icons should come from `/packages/gamut-icons`:
- Try to get icon layer names from Figma metadata
- If layer names are not available, make your best guess based on the screenshot and verify the icon exists in the codebase
- Generate the code with your best guess, then confirm with the user after
- Map icon layer names to Gamut components (e.g., "Regular/Interface/PersonIcon" → `PersonIcon` from `@codecademy/gamut-icons`)

## Styling Guidelines - STRICT RULES

### ❌ NEVER Do This:

```tsx
// NEVER use hardcoded hex colors
color: '#ffffff',
backgroundColor: '#000000',

// NEVER use CSS properties not in system props
backdropFilter: 'blur(1px)',

// NEVER use inline styles
style={{ fontSize: 14 }}
```

### ✅ ALWAYS Do This:

```tsx
// ALWAYS use spacing tokens (4, 8, 12, 16, 24, 32, 40, 48, 64, 96)
height: 24, // from spacing.ts
width: 64, // from spacing.ts

// ALWAYS use fontSize tokens (14, 16, 18, 20, 22, 26, 34, 44, 64)
fontSize: 14, // from typography.ts

// ALWAYS use borderRadii tokens (none, sm, md, lg, xl, full)
borderRadius: 'full', // from borderRadii.ts

// ALWAYS use semantic color tokens
bg: 'background',
color: 'text',
borderColor: 'border',

// ALWAYS use system props via system.css or styled components
system.css({
bg: 'black',
color: 'white',
borderRadius: 'full',
})
```

### Token Mapping Rules:

1. **Spacing/Sizing**: Map Figma values to closest token from `spacing.ts`

- 4px, 8px, 12px, 16px, 24px, 32px, 40px, 48px, 64px, 96px

2. **Colors**: Use semantic tokens OR core colors from `colors.ts`

- Semantic: `background`, `text`, `border`, `text-secondary`, etc.
- Core: `navy`, `white`, `black`, `blue`, `green`, `red`, `yellow`, etc.
- For Background component only: use color names (navy, white, etc.)

3. **Border Radius**: Use tokens from `borderRadii.ts`

- none (0px), sm (2px), md (4px), lg (8px), xl (16px), full (999px)

4. **Typography**: Use tokens from `typography.ts`

- fontFamily: `accent`, `base`, `monospace`, `system`
- fontSize: 14, 16, 18, 20, 22, 26, 34, 44, 64
- fontWeight: 400, 700 or `base`, `title`
- lineHeight: `base` (1.5), `title` (1.2), `spacedTitle` (1.3)

5. **If no exact match**: Document in code comment why custom value needed

### Emotion & CSS-in-JS Patterns:

- **IMPORTANT**: Do not use inline styles
- Use `styled` from `@emotion/styled`
- Use `system.css()` for style objects
- Use `styledOptions` for styled component options
- Compose system props with `variance.compose()`

## Accessibility & Best Practices

- **IMPORTANT**: Follow WCAG requirements for accessibility
- Always follow best practices from `/packages/styleguide/src/lib/Meta/Best Practices.mdx`

## Implementation

- Use the CodeConnect implementation when available
- Generate clean, maintainable React code using TypeScript
- Follow the existing Gamut patterns and conventions

## Post-Generation Validation

After generating code, verify:

- [ ] No hardcoded hex colors (`#` in color values)
- [ ] No hardcoded pixel strings (`'24px'` format)
- [ ] All spacing values match tokens from spacing.ts
- [ ] All colors use semantic tokens or theme colors
- [ ] All border radius uses borderRadii tokens
- [ ] Component follows Gamut patterns (variance, system props, styledOptions)
- [ ] No inline styles
- [ ] Uses emotion styled components
After codegen, verify: no stray `#` theme colors, token-aligned spacing/type/radius, no inline styles for token-level concerns, Storybook-aligned patterns.
6 changes: 3 additions & 3 deletions .cursor/rules/gamut-library.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ alwaysApply: false
- Read token sources in `packages/gamut-styles/src/variables/` before changing colors, spacing, type, or radii. Avoid hardcoded hex and non-token pixel values.
- Use semantic color keys in component styles so they work under every ColorMode.
- Add or update Storybook MDX in `packages/styleguide` for public API or behavior changes.
- For **component file layout, variance typing, React conventions, and Storybook file pairing** in `packages/gamut` / `packages/styleguide`, follow `.cursor/rules/gamut-component-building.mdc` and the **gamut-library-authoring** skill below.
- Follow `.cursor/rules/figma-rules.mdc` for icon/pattern/illustration package usage when implementing from design.
- For detailed workflows (tokens, styling, MDX, quality gates), use the **gamut-library-authoring** Cursor skill (`/gamut-library-authoring` in chat, or open `.cursor/skills/gamut-library-authoring/SKILL.md`).
- For **component file layout, variance typing, React conventions, and Storybook file pairing** in `packages/gamut` / `packages/styleguide`, follow `.cursor/rules/gamut-component-building.mdc` and **gamut-library-authoring** (see `docs/agents/gamut-library-authoring.md` and `.cursor/skills/gamut-library-authoring/SKILL.md` when using Cursor).
- Follow `.cursor/rules/gamut-figma-rules.mdc` and [`docs/agents/figma-from-design.md`](docs/agents/figma-from-design.md) for icon/pattern/illustration boundaries when implementing from design.
- For detailed workflows (tokens, styling, MDX, quality gates), use **[`docs/agents/gamut-library-authoring.md`](docs/agents/gamut-library-authoring.md)** and the **gamut-library-authoring** skill in `.cursor/skills/`.
78 changes: 3 additions & 75 deletions .cursor/skills/gamut-library-authoring/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,80 +10,8 @@ description: >-

# Gamut library authoring

## Scope
**Canonical guide (tool-agnostic):** [`docs/agents/gamut-library-authoring.md`](../../../docs/agents/gamut-library-authoring.md)

Work lives under this monorepo: `packages/gamut`, `packages/gamut-styles`, `packages/gamut-patterns`, `packages/gamut-icons`, `packages/gamut-illustrations`, `packages/styleguide`. Do not treat this skill as guidance for app repos that only install `@codecademy/gamut`.
**Repository index:** [`AGENTS.md`](../../../AGENTS.md)

**Cursor rules:** `.cursor/rules/gamut-library.mdc` (tokens, ColorMode, Figma boundaries) and `.cursor/rules/gamut-component-building.mdc` (component structure, TS, React, Storybook pairing for `packages/gamut` + `packages/styleguide`).

## Architecture

- Components: `packages/gamut/src` — extend existing components before adding overlapping primitives.
- Patterns: `packages/gamut-patterns` — page-level compositions.
- Icons / illustrations: `packages/gamut-icons`, `packages/gamut-illustrations`.
- Tokens: single source in `packages/gamut-styles/src/variables/` (`spacing`, `colors`, `typography`, `borderRadii`). No ad-hoc hex or arbitrary pixel strings where a token exists.

## Component structure (`packages/gamut`)

- Default: one **PascalCase** folder with `index.tsx` (or `index.ts` re-exporting siblings) and `__tests__/<Component>.test.tsx`.
- Large UIs: add `shared/` for types/styles/variants, `elements/` for presentational pieces, or domain subfolders (`layout/`, `inputs/`) following `Button/`, `Form/`, `BarChart/`, `GridForm/`.
- **Barrel:** every public component or type consumers need must be exported from `packages/gamut/src/index.tsx`. Use `export type { … }` when values should not be re-exported.

## Storybook and snippets (`packages/styleguide`)

- Place docs under `packages/styleguide/src/lib/` in the atomic layer that matches the component (Atoms, Molecules, Organisms, Layouts, Typography, etc.); folder structure mirrors the Storybook sidebar.
- For each component: **`ComponentName.stories.tsx`** + **`ComponentName.mdx`** (kebab-case filenames) in that component’s folder.
- VS Code (repo root): type **`component-story`**, **`component-doc`**, or **`toc-story`** to insert templates from `.vscode/stories.code-snippets`.
- Include a flagship/default story, **`Controls`** where appropriate, and prose in MDX (`parameters` with `title`, `subtitle`, `design`, `status`, `source.githubLink`). Prefer examples that **Show code** as copy-paste-ready (avoid heavy indirection in the snippet users copy).
- Meta guides: `packages/styleguide/src/lib/Meta/Gamut writing guide/Stories/About.mdx`, `Component story documentation.mdx`, `Component code examples.mdx`.

## TypeScript and variance

- **Derive props from styling:** after `const x = variance.compose(system.space, …)` or `variant({ … })`, extend with `StyleProps<typeof x>`. Chain multiple `StyleProps<typeof …>` when variants and states are separate (see `Anchor`, `Tag/types.tsx`).
- **Derive from styled component:** `export type FooProps = ComponentProps<typeof StyledFoo>` for Emotion roots built with `styled('tag', styledOptions<'tag'>())(…)`.
- **Compose with bases:** e.g. `ButtonBaseProps & ComponentProps<typeof ButtonBase>` so system props and the underlying component stay aligned.
- **Variants:** use **discriminated unions** (`export type Props = A | B | C`) when `variant` or mode changes required props. Use **`never`** on disallowed props per branch so invalid combinations fail at compile time (`Tag`, `Badge` standard vs `custom`).
- **DOM handlers:** prefer `HTMLProps<HTMLAnchorElement>['onClick']`, `ComponentProps<typeof SubComponent>['onClick']`, etc., over `Function` or `any`.
- **Shared types:** reuse `WithChildrenProp`, `IconComponentType`, `Partial<IconComponentType>` from `packages/gamut/src/utils/types.ts`; follow generics like `InlineIconButtonProps` in `Button/shared/types.ts` for polymorphic wrappers.
- **Gold components:** adding a variant usually means a new union member and fixing consumers; avoid new `as any`; reserve exceptions for documented edge cases only.

## React

- Match **local file style** (`React.FC<Props>` is common in Gamut).
- Use **`forwardRef`** when consumers or libraries need the underlying DOM ref.
- **Rules of Hooks**; name shared logic `use*`. Effects: correct dependency arrays, cleanup for subscriptions/timers; avoid mirroring props into state when derived state or a `key` reset is clearer ([You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect)).
- **Memoization:** `useMemo` / `useCallback` / `React.memo` when profiling or stable identity is required—not by default.
- **Composition:** prefer `children` and subcomponents over flat prop explosion; page templates belong in `gamut-patterns`.
- **Lists:** stable keys; avoid index keys for reorderable/dynamic lists.
- **Forms:** be explicit about controlled vs uncontrolled behavior; align with `ConnectedForm` / `GridForm` when touching those flows.
- **Accessibility:** semantic elements first (`button`, `a`, `label` + `htmlFor`); use `aria-*` for bespoke widgets. See styleguide Meta and `Best practices.mdx`.

## Styling

- Emotion + `@codecademy/gamut-styles`: `css`, `variant`, `states`, system props via `system.css`, `styledOptions`, variance `compose` where the codebase already does.
- Semantic color keys only in component styles so components work in any ColorMode.
- Avoid nested tag selectors and `${GamutComponent}` selectors; prefer system props, layout primitives (`FlexBox`, `GridBox`), and explicit wrappers.

## ColorMode and Background

- When changing theme behavior, read `packages/styleguide/src/lib/Foundations/ColorMode/ColorMode.mdx` and `packages/gamut-styles/src/ColorMode.tsx` / `Background` implementation.
- Components should consume **semantic** aliases (`text`, `background`, `primary`, etc.), not raw palette names in ways that break mode switching.

## Documentation and AI-facing MDX

- New or changed components need Storybook MDX under `packages/styleguide`; keep props tables accurate ([Storybook Autodocs](https://storybook.js.org/docs/writing-docs/autodocs) where used).
- Cross-link [published Storybook](https://gamut.codecademy.com/) paths for reviewers and agents.
- Human-oriented overview for contributors: `packages/styleguide/src/lib/Meta/Gamut writing guide/Building components in Gamut.mdx` (if present).

## Accessibility

- Follow WCAG-minded patterns; use styleguide Meta and per-component pages. Prefer built-in Gamut props and semantics over bespoke DOM.

## Quality gates

- Respect `eslint-plugin-gamut` and repo ESLint config for touched packages.
- Add or update stories and visual/docs coverage when behavior or public API changes.

## Further reading

See [reference.md](reference.md) for token paths, exemplar source files, snippet names, Meta MDX paths, and Figma rule alignment.
When this repo is open in **Cursor**, project rules also apply: `.cursor/rules/gamut-library.mdc`, `.cursor/rules/gamut-component-building.mdc`, and `.cursor/rules/gamut-figma-rules.mdc` (Figma → code). Use the markdown files above for full depth; this skill exists so assistants discover the workflow.
Loading
Loading