PageAI full logo
Updated on

How to Generate Cursor Rules for Any Project File (No More Manual Writing)

How to Generate Cursor Rules for Any Project File (No More Manual Writing)

It's 2025 outside, so people should stop writing Cursor rules by hand.
Not sure why, but many still go snooping around github for rule files or writing them from scratch.

Turns out there's a much better way to do it, but somehow it's not more widespread.
I'm not sure why, but this is by far the fastest and most scalable way to do it.

I'll teach you how to automatically generate Cursor rules for any project file, language, or framework without spending hours writing them manually.

By the end of this article, you'll have a systematic approach to creating perfect, project-specific coding guidelines.
Let's go πŸ’ͺ

πŸ“Ί If you wanna see this as a video instead, please knock yourself out:

The Manual Cursor Rules Problem

It has been scientifically proven that Cursor rules increase the wellbeing of the vibe coder by at least 27%.
Ok, not really but they definitely seem to help, especially with silly small mistakes that end up costing you a lot of time.

You see the above and then you try to create your own, you end up writing things like this :/

.cursor/rules/haskell.mdc
What is a monad?

And then you realize... The year is 2025.

Nobody has time for writing 😱 manual things anymore. We all need to ship. We need to get things done.

So let's do this properly instead.

What you'll learn

In this tutorial, I'll show you how to automatically generate Cursor rules for any type of project file, whether it's:

  • React components
  • Backend services
  • Utility functions
  • CSS files
  • Database schemas
  • API routes
  • You name it

We'll cover:

  1. Setting up foundational rules (the meta-rules)
  2. Documenting your project structure automatically
  3. Analyzing your tech stack and dependencies
  4. Generating rules generically with a prompt + command combo
  5. Scaling this approach to any codebase or type of file

Note: the Rules shown in this article also contain metadata (the stuff between the --- lines). πŸ‘‰ To add the rules correctly, make a plain text file with e.g. TextEdit or Notepad etc., and paste the content in there, then fire up Cursor to check if it's working.


If you paste them in Cursor, you'll need to remove the metadata and set it manually in the Cursor UI (check the video to see how).

1. Foundational rules

Before we dive into generating specific rules, you need a couple of foundational rules. These are not necessarily specific to your projectβ€”you can copy-paste them from below.

1.1 The Cursor Rules... rule

The first rule you need to add is a rule for Cursor rules themselves. Having this in place will ensure all other rules we make later won't be created in the wrong location and have a good structure.

Create a file called .cursor/rules/cursor-rules.mdc:

.cursor/rules/cursor-rules.mdc
---
description: How to add or edit Cursor rules in our project
globs:
alwaysApply: false
---
# Cursor Rules Location

How to add new cursor rules to the project

1. Always place rule files in PROJECT_ROOT/.cursor/rules/:
    ```
    .cursor/rules/
    β”œβ”€β”€ your-rule-name.mdc
    β”œβ”€β”€ another-rule.mdc
    └── ...
    ```

2. Follow the naming convention:
    - Use kebab-case for filenames
    - Always use .mdc extension
    - Make names descriptive of the rule's purpose

3. Directory structure:
    ```
    PROJECT_ROOT/
    β”œβ”€β”€ .cursor/
    β”‚   └── rules/
    β”‚       β”œβ”€β”€ your-rule-name.mdc
    β”‚       └── ...
    └── ...
    ```

4. Never place rule files:
    - In the project root
    - In subdirectories outside .cursor/rules
    - In any other location

5. Cursor rules have the following structure:

```
---
description: Short description of the rule's purpose
globs: optional/path/pattern/**/*
alwaysApply: false
---
# Rule Title

Main content explaining the rule with markdown formatting.

1. Step-by-step instructions
2. Code examples
3. Guidelines

Example:

```typescript
// Good example
function goodExample() {
  // Implementation following guidelines
}

// Bad example
function badExample() {
  // Implementation not following guidelines
}
```

Download cursor-rules.mdc

1.2 The self-improvement rule

The second foundational rule is the self-improvement rule. This actually "teaches Cursor" how to create more rules by itself. It will look at patterns and repeated instructions and create more rules based on that.

Create .cursor/rules/self-improvement.mdc:

.cursor/rules/self-improvement.mdc
---
description: Guidelines for continuously improving Cursor rules based on emerging code patterns and best practices.
globs: **/*
alwaysApply: true
---
## Rule Improvement Triggers

- New code patterns not covered by existing rules
- Repeated similar implementations across files
- Common error patterns that could be prevented
- New libraries or tools being used consistently
- Emerging best practices in the codebase

# Analysis Process:
- Compare new code with existing rules
- Identify patterns that should be standardized
- Look for references to external documentation
- Check for consistent error handling patterns
- Monitor test patterns and coverage

# Rule Updates:

- **Add New Rules When:**
  - A new technology/pattern is used in 3+ files
  - Common bugs could be prevented by a rule
  - Code reviews repeatedly mention the same feedback
  - New security or performance patterns emerge

- **Modify Existing Rules When:**
  - Better examples exist in the codebase
  - Additional edge cases are discovered
  - Related rules have been updated
  - Implementation details have changed

- **Example Pattern Recognition:**

  ```typescript
  // If you see repeated patterns like:
  const data = await prisma.user.findMany({
    select: { id: true, email: true },
    where: { status: 'ACTIVE' }
  });

  // Consider adding to [prisma.mdc](mdc:shipixen/.cursor/rules/prisma.mdc):
  // - Standard select fields
  // - Common where conditions
  // - Performance optimization patterns
  ```

- **Rule Quality Checks:**
- Rules should be actionable and specific
- Examples should come from actual code
- References should be up to date
- Patterns should be consistently enforced

## Continuous Improvement:

- Monitor code review comments
- Track common development questions
- Update rules after major refactors
- Add links to relevant documentation
- Cross-reference related rules

## Rule Deprecation

- Mark outdated patterns as deprecated
- Remove rules that no longer apply
- Update references to deprecated rules
- Document migration paths for old patterns

## Documentation Updates:

- Keep examples synchronized with code
- Update references to external docs
- Maintain links between related rules
- Document breaking changes

Follow [cursor-rules.mdc](mdc:.cursor/rules/curs or-rules.mdc) for proper rule formatting and structure.

Download self-improvement.mdc

2. Directory structure rule

This one is a fantastic hack. Basically, you don't want every Cursor chat to half-ass file-listing part of your directories or even worse ― duplicating some of the locations in another directory.

This also "teaches Cursor" what's already implemented, so when you ask it to add a new feature it's better at understanding the context.

Here's how you generate it.
Open up a new chat and type:

@cursor-rules.mdc List all source files and folders in the project,
and create a new cursor rule outlining the directory structure and important files and folders.

This will create a rule that looks like the below but beware!
You can't just copy-paste it into your project, you need to submit the prompt yourself.

.cursor/rules/project-structure.mdc
---
description:
globs:
alwaysApply: true
---
# Page UI Project Structure

This rule outlines the directory structure and organization of the Page UI project - a collection of landing page components, templates, and tools for React/Next.js applications.

## Project Overview

**Page UI** (`@page-ui/wizard`) is a landing page component library and template collection that provides:
- Copy-paste React/Next.js components
- Complete landing page templates
- CLI tools for easy setup
- Tailwind CSS theming system
- Shadcn UI compatibility

## Root Directory Structure

```
page-ui/
β”œβ”€β”€ components/          # 🎨 Reusable React components (shared library)
β”œβ”€β”€ website/            # 🌐 Documentation & demo website (Next.js app)
β”œβ”€β”€ templates/          # πŸ“„ Complete landing page templates
β”œβ”€β”€ packages/           # πŸ“¦ CLI tools and utilities
β”œβ”€β”€ package.json        # πŸ“‹ Main package manifest (CLI tool)
β”œβ”€β”€ README.md          # πŸ“– Project documentation
└── LICENSE.md         # βš–οΈ MIT license
```

## Components Directory (`/components/`)

**Purpose**: Shared component library that can be used in both the website and external projects.

```
components/
β”œβ”€β”€ landing/           # 🏠 Landing page specific components
β”‚   β”œβ”€β”€ about/        # About sections & company info
β”‚   β”œβ”€β”€ app-store-button/ # App store download buttons
β”‚   β”œβ”€β”€ bento-grid/   # Grid layout components
β”‚   β”œβ”€β”€ blog/         # Blog listing components
β”‚   β”œβ”€β”€ card/         # Product cards & showcases
β”‚   β”œβ”€β”€ cta/          # Call-to-action components
β”‚   β”œβ”€β”€ cta-backgrounds/ # CTA background variations
β”‚   β”œβ”€β”€ discount/     # Discount & sale banners
β”‚   β”œβ”€β”€ feature/      # Feature showcases
β”‚   β”œβ”€β”€ footer/       # Page footers
β”‚   β”œβ”€β”€ leading/      # Leading pills & badges
β”‚   β”œβ”€β”€ navigation/   # Headers & navigation
β”‚   β”œβ”€β”€ newsletter/   # Newsletter signup forms
β”‚   β”œβ”€β”€ pricing/      # Pricing sections
β”‚   β”œβ”€β”€ pricing-comparison/ # Pricing comparison tables
β”‚   β”œβ”€β”€ problem-agitator/ # Problem statement sections
β”‚   β”œβ”€β”€ rating/       # Rating & review components
β”‚   β”œβ”€β”€ showcase/     # Product showcase sections
β”‚   β”œβ”€β”€ social-proof/ # Social proof & testimonials
β”‚   β”œβ”€β”€ stats/        # Statistics & metrics
β”‚   β”œβ”€β”€ team/         # Team member profiles
β”‚   └── testimonial/  # Customer testimonials
β”œβ”€β”€ shared/           # πŸ”§ Common UI components
β”‚   β”œβ”€β”€ ui/          # Shadcn-style base components
β”‚   β”œβ”€β”€ Header.tsx   # Global header component
β”‚   β”œβ”€β”€ Footer.tsx   # Global footer component
β”‚   └── ThemeSwitch.tsx
β”œβ”€β”€ bricks/           # 🧱 Interactive demo system
β”‚   β”œβ”€β”€ theme/       # Theming & color management
β”‚   β”œβ”€β”€ controls/    # Interactive controls
β”‚   └── state/       # State management
β”œβ”€β”€ blog/            # πŸ“ Blog-related components
β”œβ”€β”€ icons/           # 🎯 Custom icon components
β”œβ”€β”€ lib/             # πŸ› οΈ Utility functions
└── data/            # πŸ“Š Configuration data
```

## Website Directory (`/website/`)

**Purpose**: Next.js documentation website with demos, docs, and interactive examples.

```
website/
β”œβ”€β”€ app/             # πŸš€ Next.js 15+ App Router
β”‚   β”œβ”€β”€ docs/        # Documentation pages
β”‚   β”œβ”€β”€ api/         # API routes (newsletter, etc.)
β”‚   β”œβ”€β”€ tags/        # Blog tagging system
β”‚   └── [...slug]/   # Dynamic routing
β”œβ”€β”€ components/       # 🎨 Website-specific components (mirrors /components/)
β”œβ”€β”€ data/            # πŸ“Š Content & configuration
β”‚   β”œβ”€β”€ docs/        # Documentation content (MDX)
β”‚   β”œβ”€β”€ config/      # Site configuration
β”‚   └── authors/     # Author information
β”œβ”€β”€ demo/            # πŸŽͺ Interactive component demos
β”œβ”€β”€ layouts/         # πŸ“ Page layout components
β”œβ”€β”€ public/          # 🌐 Static assets
β”œβ”€β”€ css/             # 🎨 Global styles & Prism themes
└── contentlayer.config.ts # πŸ“„ Content processing
```

## Templates Directory (`/templates/`)

**Purpose**: Complete, production-ready landing page templates.

```
templates/
└── landing-page-templates/
    β”œβ”€β”€ template/
    β”‚   β”œβ”€β”€ specta/         # Creator platform template
    β”‚   β”œβ”€β”€ gnomie-ai/      # B2C AI SaaS template
    β”‚   β”œβ”€β”€ minimum-via/    # Minimalist product template
    β”‚   β”œβ”€β”€ screenshot-two/ # Developer tool template
    β”‚   β”œβ”€β”€ emerald-ai/     # AI platform template
    β”‚   └── front-centre/   # Agency template
    └── page.tsx           # Template showcase page
```

## Packages Directory (`/packages/`)

**Purpose**: CLI tools and utilities for the Page UI ecosystem.

```
packages/
└── cli/
    β”œβ”€β”€ index.mjs      # πŸ› οΈ Main CLI entry point
    β”œβ”€β”€ files/         # Template files for init
    └── README.md      # CLI documentation
```

## Key Configuration Files

### Package Management
- `package.json` - Main CLI package configuration
- `website/package.json` - Website dependencies

### Build & Development
- `website/next.config.js` - Next.js configuration
- `website/tailwind.config.js` - Tailwind CSS setup
- `website/tsconfig.json` - TypeScript configuration
- `website/contentlayer.config.ts` - Content processing

### Styling & Theming
- `website/css/globals.css` - Global styles & CSS variables

## Component Organization Patterns

### Landing Components (`/components/landing/`)
- **Grouped by function**: CTA, testimonials, pricing, features
- **Self-contained**: Each component includes its own styling
- **Export pattern**: Centralized exports via `index.ts`
- **Naming convention**: `Landing[Purpose][Variant].tsx`

### Shared Components (`/components/shared/`)
- **Base UI**: Shadcn-compatible components in `/ui/`
- **Layout**: Headers, footers, navigation
- **Utilities**: Theme switching, analytics, etc.

### Brick System (`/components/bricks/`)
- **Interactive demos**: Live component playground
- **Theme management**: Color scheme generation
- **Code generation**: Export configurations as code

## File Naming Conventions

### Components
- **PascalCase**: `LandingFeatureSection.tsx`
- **Descriptive**: Purpose clearly indicated in name
- **Consistent prefixes**: `Landing*`, `Blog*`, etc.

### Directories
- **kebab-case**: `landing-page-templates`
- **Descriptive**: Clear purpose indication
- **Grouped logically**: Related components together

### Template Structure
```typescript
// Template organization
template/
β”œβ”€β”€ bricks/           # Component implementations
β”œβ”€β”€ [name]-logo.svg   # Brand assets
β”œβ”€β”€ [name].tsx        # Main template file
└── page.tsx          # Demo page (optional)
```

Download project-structure.mdc

After it does this, you'll want to check a few things:

  1. Ensure that all directories were expanded and the AI was not lazy and wrote [+20 more], ...other directories etc.

  2. Ensure that it didn't include config files or common folders such as .git, that won't be helpful.

  3. Ensure that it captured utilities, shared components and conventions that are not obvious to the AI.

This is gonna be super neat because it's going to eliminate some of the silly mistakes AI sometimes does and prevent it from reinventing the wheel, duplicating code and setup etc.

3. Tech stack rule

This is easily the rule that'll reduce most of the mistakes AI makes. You won't have to explain to it what's the latest version of your favorite framework, what's the new way of doing things etc.

This is tedious to write, so this prompt will come in handy!

@cursor-rules.mdc @package.json Analyze all major dependencies
and create a cursor rule outlining the stack of the application
and the versions I'm using, and any remarks on best practices on those versions.

The output will look something like this:

.cursor/rules/tech-stack.mdc
---
description:
globs:
alwaysApply: true
---
# Page UI Tech Stack & Dependencies Guide

## Project Overview

**Page UI** is a landing page component library built on modern React/Next.js stack with:
- **Website**: Next.js 14 documentation site with component demos
- **CLI Tool**: `@page-ui/wizard` for easy project initialization
- **Components**: Copy-paste React components built on Radix UI + Tailwind CSS

## Core Framework Stack

### **Next.js 14.2.24** (App Router)
- **Framework**: React meta-framework with App Router architecture
- **Features Used**: API routes, SSG/SSR, OG image generation, bundle analysis
- **Best Practice**: Use App Router patterns, avoid pages directory

### **React 18.2.0**
- **UI Library**: Core React library with concurrent features
- **Features**: Suspense, automatic batching, server components
- **Best Practice**: Use React 18 patterns

### **TypeScript 5.1.3**
- **Configuration**: Strict mode enabled for better type safety
- **Best Practice**: Modern TS version

## UI Component System

### **Radix UI Primitives** (v1.x series)
Complete accessibility-first component library ecosystem:

**Best Practices**:
- Use compound component patterns
- Always customize with Tailwind classes, not inline styles
- Implement proper ARIA attributes (built-in)
- Wrap in custom components for consistent styling

### **Shadcn/UI Design Pattern**
- **Location**: `/components/shared/ui/` directory
- **Philosophy**: Copy-paste components, not NPM dependencies
- **Styling**: Tailwind CSS + CSS variables for theming
- **Variants**: Uses `class-variance-authority` for type-safe variants

## Styling & Design System

### **Tailwind CSS 3.3.3** + Ecosystem
```json
{
  "tailwindcss": "^3.3.3",
  "@tailwindcss/forms": "^0.5.4",
  "@tailwindcss/typography": "^0.5.9",
  "tailwindcss-animate": "^1.0.7",
  "tailwind-merge": "^1.14.0"
}
```

**Best Practices**:
- Use `tailwind-merge` for conditional classes: `cn(baseClasses, conditionalClasses)`
- Leverage CSS variables for theming: `hsl(var(--primary))`
- Use plugins for forms and typography
- Implement consistent spacing and color systems

### **Animation Libraries**
- **Framer Motion 10.16.4**: Complex animations, page transitions
- **Tailwind Animate**: Simple CSS animations
- **Best Practice**: Use CSS animations for simple effects, Framer Motion for complex interactions

```typescript
// Framer Motion best practices:
import { motion, AnimatePresence } from 'framer-motion'

function AnimatedComponent() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: -20 }}
      transition={{ duration: 0.3 }}
    >
      Content
    </motion.div>
  )
}
```

## State Management & Forms

### **Zustand 4.5.2** (Global State)
- **Philosophy**: Minimal, unopinionated state management
- **Usage**: Theme preferences, global UI state, component playground state
- **Best Practice**: Create typed stores with proper selectors

```typescript
interface ThemeState {
  theme: 'light' | 'dark'
  setTheme: (theme: 'light' | 'dark') => void
}

export const useThemeStore = create<ThemeState>((set) => ({
  theme: 'light',
  setTheme: (theme) => set({ theme }),
}))
```

### **React Hook Form 7.46.2** + Validation
- **Form Library**: Performant, uncontrolled forms
- **Validation**: `@hookform/resolvers` ^3.3.1 + `zod` ^3.22.2
- **Integration**: Works seamlessly with Radix UI form components

```typescript
// Best practice form setup:
const formSchema = z.object({
  email: z.string().email(),
  name: z.string().min(2),
})

function ContactForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
  })

  return <form onSubmit={form.handleSubmit(onSubmit)}>...</form>
}
```

### **Zod 3.22.2** (Schema Validation)
- **Usage**: Form validation, API response validation, type generation
- **Best Practice**: Define schemas close to usage, leverage type inference

## Content Management System

### **Custom Contentlayer Implementation**
```json
{
  "@shipixen/next-contentlayer-module": "1.0.2",
  "shipixen-contentlayer": "1.0.2",
  "@shipixen/pliny": "1.0.13"
}
```

**Features**:
- Type-safe MDX processing
- Frontmatter parsing
- Automated content imports
- RSS feed generation

### **MDX Processing Pipeline**
**Remark Plugins** (Markdown processing):
- `remark-gfm` ^3.0.1: GitHub Flavored Markdown
- `remark-math` ^5.1.1: Math expressions

**Rehype Plugins** (HTML processing):
- `rehype-slug` ^5.1.0: Auto-generate heading IDs
- `rehype-autolink-headings` ^6.1.0: Auto-link headings
- `rehype-prism-plus` ^1.6.1: Syntax highlighting
- `rehype-katex` ^6.0.3: Math rendering

**Best Practices**:
- Process content at build time, not runtime
- Use consistent plugin versions for stable builds
- Type-safe content queries with generated types

## Development Experience

### **Code Quality Tools**
```json
{
  "eslint": "^8.45.0",
  "@typescript-eslint/eslint-plugin": "^6.1.0",
  "@typescript-eslint/parser": "^6.1.0",
  "eslint-config-next": "^14.2.24",
  "eslint-config-prettier": "^8.8.0",
  "prettier": "^3.0.0",
  "prettier-plugin-tailwindcss": "^0.4.1"
}
```

**Git Workflow**:
- **Husky 8.0.0**: Git hooks automation
- **lint-staged 13.0.0**: Pre-commit linting and formatting

### **Interactive Development Tools**
- **Monaco Editor 0.45.0**: In-browser code editing for component playground
- **Command Palette**: `cmdk` ^0.2.0 for global search and navigation
- **Bundle Analyzer**: `@next/bundle-analyzer` for performance monitoring

## CLI Tooling (@page-ui/wizard)

### **Package Configuration**
```json
{
  "name": "@page-ui/wizard",
  "type": "module",
  "bin": "./packages/cli/index.mjs",
  "engines": {
    "node": ">=14.17.0"
  }
}
```

### **CLI Dependencies**
```json
{
  "chalk": "^5.3.0",      // Terminal colors and styling
  "commander": "^12.0.0",  // Command-line interface framework
  "enquirer": "^2.4.1",   // Interactive CLI prompts
  "ora": "^8.0.1"         // Loading spinners for CLI
}
```

**Best Practices**:
- Use ESM modules (`.mjs` extension)
- Provide interactive prompts with enquirer
- Show progress with ora spinners
- Consistent terminal styling with chalk

## Analytics & External Services

### **Vercel Ecosystem**
- **Analytics**: `@vercel/analytics` ^1.1.1
- **OG Images**: `@vercel/og` ^0.5.20
- **Best Practice**: Use Vercel's native tooling for optimal performance

### **Product Analytics**
- **PostHog 1.130.1**: Feature flags, user tracking, A/B testing
- **Best Practice**: Privacy-compliant setup with proper consent management

### **HTTP Client**
- **Axios 1.7.7**: API calls, newsletter subscriptions
- **Best Practice**: Create axios instances with base configuration

## Utility Libraries

### **Date & Time**
- **date-fns 2.30.0**: Modular date utility library
- **Best Practice**: Import only needed functions for tree-shaking

```typescript
// βœ… Good: Tree-shakeable imports
import { format, parseISO } from 'date-fns'

// ❌ Bad: Full library import
import * as dateFns from 'date-fns'
```

### **Styling & UI Utilities**
- **clsx 2.0.0**: Conditional className utility
- **class-variance-authority 0.7.0**: Type-safe component variants
- **chroma-js 2.4.2**: Color manipulation and theme generation

### **Data Presentation**
- **@tanstack/react-table 8.10.7**: Powerful table component
- **lucide-react 0.400.0**: Icon library
- **sonner 1.3.1**: Toast notifications

Download tech-stack.mdc

Similar to the project structure rule, you'll want to run this in your own codebase and not copy the above output.

This rule also works with other languages / dependency managers.

This is going to help you when the AI is going to use an outdated pattern of a certain framework or a certain function that's deprecated, or switch to new ways of doing things that have been introduced in the latest versions of that framework.

But what if you want to add a new dependency?
Here's what to prompt:

@cursor-rules.mdc @package.json Analyze all major dependencies
and update the @tech-stack.mdc rule with the latest versions of the dependencies, outlining the best practices for those versions.

This will update the @tech-stack.mdc rule with the latest versions of the dependencies so you can keep vibe coding for days. Or until you hit those rough rate limits.

4. Generating rules generically for any file type

Now here's where the magic happens. Give a man a 🐠 Cursor rule and you will feed him for a day. Teach a man to generate Cursor rules and you feed him for a lifetime 🐠🐠🐠.

I'm actually not sure why this is not more widespread. It's a really simple way to do it, and it's gonna work every single time, no matter if it's a backend file, frontend file, a CSS file ― any file type, really.

Let's say you want to create a Cursor rule for React components. You have a component that follows a certain pattern, and you want to create more components like this.

Here's how you do it:

Open up a new Cursor chat and then, attach one or more good example files from the codebase, then type the /Generate Cursor Rules command and prompt it:

@cursor-rules.mdc @components/ui/button.tsx
/Generate Cursor Rules
I want to generate a cursor rule for this React component. Please analyze it carefully and outline all of the conventions found. Output as one rule file only.

For example, if you analyze a landing page component, it might find:

  • Component structure patterns
  • Props patterns (how you usually define a component's props)
  • Event handler conventions
  • Styling patterns
  • Accessibility practices
  • TypeScript usage patterns

The output will include notes on styling, accessibility, and best practices that it could identify, which are actually pretty good:

.cursor/rules/react-components.mdc
---
description: Creating or updating landing page components
globs:
alwaysApply: false
---
# Page UI Landing Components Guide

## Component Architecture & Philosophy

Page UI landing components follow a **shadcn-inspired** design pattern with these core principles:

- **Copy-paste friendly**: Components are self-contained with minimal external dependencies
- **Highly configurable**: Extensive props for customization without code changes
- **Accessibility-first**: Built on Radix UI primitives with proper ARIA attributes
- **Responsive by default**: Mobile-first design with Tailwind CSS
- **Theme-aware**: Support for primary/secondary variants and dark mode

## Naming Conventions

### Component Names
All landing components follow this strict pattern:
```typescript
// βœ… Correct naming pattern
export const Landing[Purpose][Variant?] = () => {}

// Examples:
LandingNewsletterSection     // Main section component
LandingNewsletterInput       // Sub-component for input
LandingPrimaryImageCtaSection // CTA with specific variant/type
LandingTestimonialGrid       // Layout variant
```

### File Organization
```
components/landing/
β”œβ”€β”€ [category]/              # Group by functional purpose
β”‚   β”œβ”€β”€ Landing[Name].tsx    # Main component
β”‚   β”œβ”€β”€ Landing[Name][Type].tsx # Variants
β”‚   └── index.ts            # Export centralization
└── index.ts                # Root exports
```

**Category Examples**: `newsletter/`, `cta/`, `testimonial/`, `pricing/`, `social-proof/`

## Required Component Structure

### 1. File Header Pattern
```typescript
'use client';  // Always first line for interactive components

import clsx from 'clsx';
import Image from '@/components/shared/Image';
import { ComponentName } from '@/components/shared/ui/component-name';

/**
 * A component meant to be used in the landing page.
 * [Clear description of purpose and usage context]
 */
```

### 2. Props Interface Pattern
**Always use inline type definitions** (not separate interfaces):

```typescript
export const LandingComponentName = ({
  // Core content props
  children,
  className,
  innerClassName,          // For inner container styling
  title,
  titleComponent,          // Alternative to title string
  description,
  descriptionComponent,    // Alternative to description string

  // Functional props with sensible defaults
  buttonLabel = 'Default Label',
  placeholderLabel = 'Default Placeholder',
  textPosition = 'center',
  variant = 'primary',

  // Boolean flags with defaults
  withBackground = false,
  withBackgroundGlow = false,
  disabled = false,

  // Event handlers with empty defaults
  onSubmit = () => {},
}: {
  // Always use React.ReactNode for flexible content
  children?: React.ReactNode;
  className?: string;
  innerClassName?: string;
  title?: string | React.ReactNode;
  titleComponent?: React.ReactNode;
  description?: string | React.ReactNode;
  descriptionComponent?: React.ReactNode;

  // String props with specific values
  buttonLabel?: string;
  placeholderLabel?: string;
  textPosition?: 'center' | 'left';      // Always define allowed values
  variant?: 'primary' | 'secondary';     // Standard variant system

  // Boolean props
  withBackground?: boolean;
  withBackgroundGlow?: boolean;
  disabled?: boolean;

  // Event handlers
  onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void;
}) => {
```

## Styling Conventions

### 1. className Assembly Pattern
**Always use clsx** for conditional classes:

```typescript
<section
  className={clsx(
    // Base classes first (required styling)
    'w-full flex flex-col justify-center items-center gap-8 py-12 lg:py-16',

    // Conditional classes (variant-based)
    withBackground && variant === 'primary'
      ? 'bg-primary-100/20 dark:bg-primary-900/10'
      : '',
    withBackground && variant === 'secondary'
      ? 'bg-secondary-100/20 dark:bg-secondary-900/10'
      : '',

    // State-dependent classes
    withBackgroundGlow ? 'relative overflow-hidden' : '',

    // User-provided className last
    className,
  )}
>
```

### 2. Container Structure Pattern
```typescript
<section className="outer-section-classes">
  {/* Background effects */}
  {withBackgroundGlow ? (
    <div className="background-glow-container">
      <GlowBg variant={backgroundGlowVariant} />
    </div>
  ) : null}

  {/* Main content container */}
  <div
    className={clsx(
      'container-wide w-full pt-12 p-6 flex flex-col items-center justify-center relative',
      innerClassName,
    )}
    style={{ minHeight }}  // Dynamic styles via style prop
  >
    {/* Content wrapper */}
    <div className={clsx(
      'flex flex-col gap-4',
      textPosition === 'center'
        ? 'md:max-w-lg xl:max-w-2xl items-center text-center'
        : 'items-start',
    )}>
      {/* Component content */}
    </div>
  </div>
</section>
```

### 3. Responsive Design Pattern
Follow **mobile-first** approach:
```typescript
// βœ… Correct responsive classes
'w-14 h-14 shrink-0 rounded-full sm:w-16 sm:h-16 md:w-20 md:h-20'
'text-2xl md:text-3xl lg:text-4xl'
'py-12 lg:py-16'
'gap-4 md:gap-6 lg:gap-8'

// ❌ Avoid desktop-first
'lg:w-20 lg:h-20 md:w-16 md:h-16 w-14 h-14'
```

## Content Rendering Patterns

### 1. Title/Description Component Pattern
**Always provide both string and component alternatives**:

```typescript
{title ? (
  <h2 className="text-2xl md:text-3xl lg:text-4xl font-semibold leading-tight">
    {title}
  </h2>
) : (
  titleComponent
)}

{description ? (
  <p className="md:text-lg -mt-3">{description}</p>
) : (
  descriptionComponent
)}
```

### 2. Conditional Feature Rendering
```typescript
{withAvatars ? (
  <div className="flex mb-6">
    {/* Avatar components with consistent styling */}
  </div>
) : null}

{/* Alternative using && operator for simpler conditions */}
{children && <div className="mt-4">{children}</div>}
```

## Color System & Variants

### 1. Standard Variant System
**Always support primary/secondary variants**:
```typescript
// Background variants
variant === 'primary' ? 'bg-primary-100/20 dark:bg-primary-900/10' : ''
variant === 'secondary' ? 'bg-secondary-100/20 dark:bg-secondary-900/10' : ''

// Border variants
variant === 'primary' ? 'border-2 border-primary-500' : ''
variant === 'secondary' ? 'border-2 border-secondary-500' : ''
```

### 2. Dark Mode Support
**Always include dark mode variants**:
```typescript
'bg-primary-100/20 dark:bg-primary-900/10'
'text-gray-700 dark:text-gray-300'
'dark:opacity-50 opacity-100'
```

## State Management Patterns

### 1. Event Handler Defaults
```typescript
// βœ… Always provide safe defaults
onSubmit = () => {},
onClick = () => {},
onToggle = () => {},

// Props interface
onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void;
```

### 2. Boolean Flag Patterns
```typescript
// βœ… Descriptive boolean props with defaults
withBackground = false,
withBackgroundGlow = false,
withAvatars = false,
disabled = false,

// ❌ Avoid ambiguous boolean names
isActive = false,     // What does "active" mean?
enabled = true,       // Double negative with disabled
```

## Accessibility Standards

### 1. Form Accessibility
```typescript
<Label htmlFor="email" className="sr-only">
  {inputLabel}
</Label>
<Input
  type="email"
  id="email"
  name="email"
  placeholder={placeholderLabel}
  required
  disabled={disabled}
/>
```

### 2. Image Accessibility
```typescript
<Image
  src="/static/images/people/1.webp"
  alt="Person 1"  // Always meaningful alt text
  width={200}
  height={200}
  className="w-14 h-14 shrink-0 rounded-full"
/>
```

## Performance Patterns

### 1. Import Organization
```typescript
// External libraries first
import clsx from 'clsx';

// Internal shared components
import Image from '@/components/shared/Image';
import { GlowBg } from '@/components/shared/ui/glow-bg';

// Sibling components
import { LandingNewsletterInput } from './LandingNewsletterInput';
```

### 2. Conditional Rendering Optimization
```typescript
// βœ… Efficient conditional rendering
{withBackgroundGlow ? (
  <div className="background-container">
    <GlowBg variant={backgroundGlowVariant} />
  </div>
) : null}

// ❌ Avoid always-rendered hidden elements
<div className={withBackgroundGlow ? 'block' : 'hidden'}>
  <GlowBg variant={backgroundGlowVariant} />
</div>
```

## Export Patterns

### 1. Component Exports
```typescript
// Individual component files
export const LandingComponentName = ({ ... }) => { ... };

// Index files - centralized exports
export { LandingNewsletterSection } from './newsletter/LandingNewsletterSection';
export { LandingNewsletterInput } from './newsletter/LandingNewsletterInput';
```

### 2. Multi-Component Exports
```typescript
// For components with multiple related exports
export {
  LandingPrimaryImageCtaSection,
  LandingPrimaryVideoCtaSection,
  LandingPrimaryTextCtaSection,
} from './cta/LandingPrimaryCta';
```

## Common Anti-Patterns to Avoid

### ❌ Don't Do
```typescript
// Missing 'use client' directive for interactive components
// Missing default values for optional props
// Using separate interface definitions
// Hardcoded styles without variants
// Missing dark mode support
// Inconsistent naming (not starting with "Landing")
// Using div for semantic sections
// Missing accessibility attributes

// Bad prop interface
interface Props {
  title: string;
}
export const BadComponent = (props: Props) => {}

// Bad conditional classes
className={`base-class ${isActive ? 'active-class' : ''}`}
```

### βœ… Do This Instead
```typescript
'use client';

export const LandingGoodComponent = ({
  title,
  variant = 'primary',
  withBackground = false,
}: {
  title?: string | React.ReactNode;
  variant?: 'primary' | 'secondary';
  withBackground?: boolean;
}) => {
  return (
    <section
      className={clsx(
        'base-classes',
        variant === 'primary' ? 'primary-classes' : 'secondary-classes',
        withBackground ? 'bg-classes dark:bg-dark-classes' : '',
      )}
    >
      {/* Content */}
    </section>
  );
};
```

## Component Documentation

### JSDoc Pattern
```typescript
/**
 * A component meant to be used in the landing page.
 * [Specific purpose and functionality description].
 *
 * @example
 * <LandingNewsletterSection
 *   title="Subscribe to our newsletter"
 *   description="Get updates on new features"
 *   variant="primary"
 *   withBackground
 * />
 */
```

Follow these patterns for consistency across all landing page components. Reference existing components like [LandingNewsletterSection.tsx](mdc:components/landing/newsletter/LandingNewsletterSection.tsx) and [LandingNewsletterInput.tsx](mdc:components/landing/newsletter/LandingNewsletterInput.tsx) for implementation examples.

Download react-components.mdc

You can probably see where this is going.
The key is to use the /Generate Cursor Rules command and then, to attach the file you want to analyze that's already in the codebase.

If you don't have that file yet, get it from an open source project on GitHub. For example, in this cases I might get it from the shadcn/ui project.

Pro tip: These types of rules should be Agent-requested and not always attached like the other rules.

5. Cursor rules for utility functions

You can essentially do this with any single file. Let's take another example and generate a rule for a utility function.

  1. Attach your utility file (e.g., base64ToBlob.ts)
  2. Type /Generate Cursor Rules
  3. Prompt it to analyze the file and generate a rule
@cursor-rules.mdc @utils/base64ToBlob.ts
/Generate Cursor Rules
I want to generate a cursor rule for this utility function.
Analyze it carefully and outline all of the conventions found. Output as one rule file only.

This will create a utility function convention rule that might include:

  • Type safety patterns
  • Implementation approaches
  • Error handling conventions
  • Documentation standards
  • General guidelines like:
    • Keep utility functions pure and side-effect free
    • Prefer functional, declarative code
    • Use descriptive, action-oriented function names
    • Keep implementation concise and focused on single responsibility

Here's how this could look like:

.cursor/rules/utility-functions.mdc
---
description: Creating/updating a utility function
globs:
alwaysApply: false
---
# Utility Functions Conventions

This rule defines conventions for utility functions based on patterns found in the codebase.

## File Organization

- Place utility functions in dedicated directories:
  - `utils/` for general utilities
  - `lib/` for shared library functions

- Use descriptive, kebab-case filenames that clearly indicate the function's purpose
- One utility function per file for better modularity

**Example from codebase:**
```typescript
// app/api/generate/util/base64-to-blob.ts - feature-specific utility
export function base64ToBlob(base64Data: string, mimeType: string): Blob { /* ... */ }
```

## Function Documentation

- **Always include comprehensive JSDoc comments** for utility functions
- Document the purpose, parameters, and return values
- Specify parameter constraints or expectations in descriptions
- Use consistent JSDoc formatting

**Template:**
```typescript
/**
 * Brief description of what the function does
 * @param paramName Description of parameter (include type constraints)
 * @param anotherParam Description with any special notes
 * @returns Description of return value and type
 */
export function functionName({ param1, param2 }: { param1: Type1; param2: Type2 }): ReturnType {
  // implementation
}
```

**Good example from [base64-to-blob.ts](mdc:shipixen/shipixen/shipixen/packages/website/app/api/generate/util/base64-to-blob.ts):**
```typescript
/**
 * Converts a base64 string to a Blob object
 * @param base64Data Base64 encoded string (without the data:image prefix)
 * @param mimeType MIME type of the resulting blob
 * @returns Blob object
 */
export function base64ToBlob(base64Data: string, mimeType: string): Blob {
  // implementation
}
```

## TypeScript Patterns

- **Use explicit type annotations** for all parameters and return types
- **Prefer primitive parameter passing** for simple utilities (not object destructuring)
- **Use descriptive parameter names** that clearly indicate their purpose
- **Leverage built-in browser APIs** when appropriate (like `atob()`, `Uint8Array`, `Blob`)

**Pattern:**
```typescript
// Good: Clear types and descriptive names
export function convertData(inputData: string, outputType: string): TargetType {
  return processedResult;
}

// Avoid: Unclear parameter purposes
export function convert(data: any, type: any): any {
  return result;
}
```

## Implementation Patterns

- **Use explicit loops** over functional array methods for performance-critical operations
- **Declare variables with appropriate scope** (prefer `const` over `let` when possible)
- **Use descriptive variable names** that indicate data transformation steps
- **Minimize intermediate variables** while maintaining readability

**Example from codebase:**
```typescript
export function base64ToBlob(base64Data: string, mimeType: string): Blob {
  const byteCharacters = atob(base64Data);           // Clear transformation step
  const byteNumbers = new Array(byteCharacters.length); // Pre-allocated array

  for (let i = 0; i < byteCharacters.length; i++) {     // Explicit loop for performance
    byteNumbers[i] = byteCharacters.charCodeAt(i);
  }

  const byteArray = new Uint8Array(byteNumbers);        // Final transformation
  return new Blob([byteArray], { type: mimeType });
}
```

## Export Patterns

- **Always use named exports** for utility functions
- **Export directly from function declaration** (avoid default exports)
- **Use camelCase for function names** following JavaScript conventions

**Template:**
```typescript
// Good
export function utilityFunctionName(): ReturnType { /* ... */ }

// Avoid
export default function(): ReturnType { /* ... */ }
const utilityFunction = () => { /* ... */ };
export default utilityFunction;
```

## Error Handling

- **Handle edge cases** appropriate to the utility's purpose
- **Use type guards** when working with uncertain input types
- **Provide meaningful error messages** when validation fails

**Pattern:**
```typescript
export function processData(input: string): ProcessedData {
  if (!input || typeof input !== 'string') {
    throw new Error('Input must be a non-empty string');
  }

  // process data
  return result;
}
```

## Testing Considerations

- Design utilities to be **pure functions** when possible (no side effects)
- **Avoid dependencies on external state** to improve testability
- **Use predictable return types** that are easy to assert against

## Performance Guidelines

- **Pre-allocate arrays** when size is known (`new Array(length)`)
- **Use appropriate data structures** (`Uint8Array` for byte operations)
- **Prefer explicit loops** over array methods for large data transformations
- **Minimize object creation** in performance-critical paths

Extra tips and larger codebases

The beautiful thing about this approach is that it works generically. You can use it for:

  • API routes: Analyze your route handlers for consistent patterns
  • Database models: Extract schema and query patterns
  • CSS files: Identify styling conventions and class naming
  • Configuration files: Document setup patterns
  • Test files: Standardize testing approaches

The process is always the same:

  1. Attach the relevant file(s)
  2. /Generate Cursor Rules
  3. Describe what you want analyzed

When generating rules, always use your best, most well-written files as examples. The AI will extract patterns and write them a lot better than you can. And they'll be a lot better than what you find online too, because they will match your codebase conventions and structure.

Bonus tips for better Cursor rules

For even better results, instead of "analyze this file," you can be more specific:

  • "Focus on the error handling patterns"
  • "Extract the TypeScript conventions"
  • "Identify the testing patterns"
  • "Look at the styling approach"

Reference other Cursor rules, files or folders

You can make rules reference each other. At the bottom of a rule file, you might see:

Follow @cursor-rules.mdc for proper rule formatting and structure.

If you open a rule file in TextEdit/Notepad, you can see that Cursor references the cursor-rules.mdc with some sort of internal link:

Follow [cursor-rules.mdc](mdc:.cursor/rules/cursor-rules.mdc) for proper rule formatting and structure.

You can also add these internal links yourself, but there's a catch. It seems like typing them in Cursor doesn't create the link. You can either ask in chat to create the link for you, or you can open the rule outside of Cursor to manually add the link.

Scaling to large codebases and monorepos

In larger codebases or monorepos, you might want to group these rules under directories representing a certain domain.
You should also change the rules from Always (attach) to Auto attached and pass a glob pattern that matches e.g. your backend files.

For example, you might have these directories:

.cursor/rules/
β”œβ”€β”€β”€ frontend-components
β”‚   β”œβ”€β”€β”€ landing-components.mdc
β”‚   β”œβ”€β”€β”€ newsletter-components.mdc
β”‚   β”œβ”€β”€β”€ pricing-components.mdc
β”‚   β”œβ”€β”€β”€ ...
β”œβ”€β”€β”€ backend-services
β”‚   β”œβ”€β”€β”€ api-routes.mdc
β”‚   β”œβ”€β”€β”€ database-queries.mdc
β”‚   β”œβ”€β”€β”€ ...
│─── self-improvement.mdc
│─── project-structure.mdc
│─── cursor-rules.mdc

By the way, absolutely share these rules when working with a larger team on the same codebase.

Since they're based on actual code patterns, they serve as living documentation of your team's coding standards.

Common mistakes when generating Cursor rules

Over-generating rules

Don't create a rule for every single file. Focus on:

  • Patterns that repeat across multiple files
  • Common sources of bugs or confusion
  • Framework-specific best practices
  • Team coding standards

Rules that are too specific

Avoid rules that are so specific they only apply to one file. Good rules should be general enough to apply to multiple similar situations.

FAQ about Cursor rules

What's the best way to generate Cursor rules?

The /Generate Cursor Rules command can handle 90% of your rule creation. You might occasionally need to tweak or combine rules, but the manual writing days are over.


How many rules should I have?

Start with 5-10 core rules covering your main patterns. You can always add more as your project grows. Quality over quantityβ€”better to have 5 excellent rules than 20 mediocre ones.


Can I use this approach with other AI coding tools?

The specific /Generate Cursor Rules command is Cursor-specific, but the generated rules should work everywhere. You can copy and paste them into your favorite AI coding tool.


Should I commit rules to Git?

Absolutely! Cursor rules are part of your project's development infrastructure. Treat them like any other configuration file.

Conclusion

And that's it! This approach is short and sweet, but incredibly powerful. You now have a systematic way to generate Cursor rules for any project file, language, or framework without spending hours writing them manually.

The key takeaways:

  1. Set up foundational rules first (cursor-rules.mdc and self-improvement.mdc)
  2. Document your project structure automatically
  3. Analyze your tech stack and dependencies
  4. Use /Generate Cursor Rules for any file type
  5. Double check that the rules have captured the patterns you want, not more, not less

I hope this helps you generate a bunch of beautiful Cursor rules and dramatically improve your AI coding experience.

For now, thank you for reading, and I'll see you in the next one! πŸš€