Added Cursor Rules

This commit is contained in:
Nicholai 2025-10-23 05:11:03 -06:00
parent a2c67c3fb9
commit a76e20e91f
11 changed files with 929 additions and 0 deletions

View File

@ -0,0 +1,159 @@
---
globs: src/components/**/*.tsx
---
# Component Patterns
## Component Structure
### File Organization
- Place reusable components in `src/components/`
- Use PascalCase for component files: `ComponentName.tsx`
- Group related components in subdirectories when needed
### Component Template
```typescript
import { cn } from '@/lib/utils'
interface ComponentProps {
className?: string
children?: React.ReactNode
// Other props
}
export function ComponentName({
className,
children,
...props
}: ComponentProps) {
return (
<div className={cn("base-styles", className)} {...props}>
{children}
</div>
)
}
```
## shadcn/ui Integration
### Using shadcn/ui Components
```typescript
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
export function ProjectCard({ project }: { project: Project }) {
return (
<Card className="bg-black border-gray-800">
<CardHeader>
<CardTitle className="text-white">{project.title}</CardTitle>
</CardHeader>
<CardContent>
<Badge variant="outline">{project.category}</Badge>
</CardContent>
</Card>
)
}
```
### Extending shadcn/ui Components
```typescript
// Create wrapper components for common patterns
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
interface PrimaryButtonProps extends React.ComponentProps<typeof Button> {
loading?: boolean
}
export function PrimaryButton({
loading,
className,
children,
...props
}: PrimaryButtonProps) {
return (
<Button
className={cn("bg-primary hover:bg-primary/90", className)}
disabled={loading}
{...props}
>
{loading ? "Loading..." : children}
</Button>
)
}
```
## Animation Patterns
### Framer Motion Usage
```typescript
import { motion } from 'framer-motion'
export function AnimatedCard({ children }: { children: React.ReactNode }) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
className="card-styles"
>
{children}
</motion.div>
)
}
```
## Component Composition
### Compound Components
```typescript
// Parent component
export function Accordion({ children }: { children: React.ReactNode }) {
return <div className="accordion-container">{children}</div>
}
// Child components
export function AccordionItem({ children }: { children: React.ReactNode }) {
return <div className="accordion-item">{children}</div>
}
export function AccordionTrigger({ children }: { children: React.ReactNode }) {
return <button className="accordion-trigger">{children}</button>
}
// Usage
<Accordion>
<AccordionItem>
<AccordionTrigger>Title</AccordionTrigger>
<AccordionContent>Content</AccordionContent>
</AccordionItem>
</Accordion>
```
## Props and TypeScript
### Interface Patterns
```typescript
// Use descriptive interface names
interface ProjectCardProps {
project: Project
variant?: 'default' | 'featured'
showDescription?: boolean
onSelect?: (project: Project) => void
}
// Use React.ComponentProps for extending HTML elements
interface CustomButtonProps extends React.ComponentProps<'button'> {
variant?: 'primary' | 'secondary'
size?: 'sm' | 'md' | 'lg'
}
```
## Styling Guidelines
1. **Tailwind First**: Use utility classes before custom CSS
2. **Conditional Classes**: Use `cn()` utility for conditional styling
3. **Responsive Design**: Mobile-first approach with responsive utilities
4. **Dark Theme**: Ensure all components work in dark mode
5. **Accessibility**: Include proper ARIA labels and semantic HTML

View File

@ -0,0 +1,97 @@
---
globs: src/data/**/*.ts,src/data/**/*.json
---
# Data and Content Management
## Data Structure
Non-secret content belongs in `src/data/` as TypeScript modules or JSON files. Keep data presentation-agnostic.
## Current Data Files
- [src/data/projects.ts](mdc:src/data/projects.ts) - Project portfolio data
- [src/data/services.ts](mdc:src/data/services.ts) - Service offerings data
## Data Patterns
### TypeScript Data Modules
```typescript
// src/data/projects.ts
export interface Project {
id: string
title: string
description: string
category: string
images: string[]
videoUrl?: string
}
export const projects: Project[] = [
{
id: 'project-1',
title: 'Project Title',
description: 'Project description',
category: 'commercial',
images: ['/image1.jpg', '/image2.jpg']
}
]
```
### JSON Data Files
```json
{
"services": [
{
"id": "vfx",
"name": "Visual Effects",
"description": "High-end VFX services"
}
]
}
```
## Data Usage Rules
1. **Server Components**: Prefer server components for data fetching
2. **File Imports**: Use direct imports instead of client-side fetching for static data
3. **Type Safety**: Define TypeScript interfaces for all data structures
4. **Separation**: Keep data separate from presentation logic
## Content Guidelines
- Use descriptive, SEO-friendly content
- Include proper alt text for images
- Maintain consistent naming conventions
- Keep content up-to-date and accurate
## Data Fetching Patterns
```typescript
// ✅ Good: Server component with direct import
import { projects } from '@/data/projects'
export default function PortfolioPage() {
return (
<div>
{projects.map(project => (
<ProjectCard key={project.id} project={project} />
))}
</div>
)
}
// ❌ Avoid: Client-side fetching of static data
'use client'
import { useEffect, useState } from 'react'
export function PortfolioPage() {
const [projects, setProjects] = useState([])
useEffect(() => {
fetch('/api/projects').then(res => res.json())
}, [])
// ...
}
```

View File

@ -0,0 +1,73 @@
---
alwaysApply: true
---
# Deployment and Build Process
## Cloudflare Workers with OpenNext
This project deploys to Cloudflare Workers using OpenNext for Next.js compatibility.
### Build Process
1. **Quality Gates** (run before build):
```bash
npm run type-check # TypeScript validation
npm run lint # ESLint validation
```
2. **Production Build**:
```bash
npm run build # Next.js build
```
3. **OpenNext Build**:
```bash
npx open-next@latest build # Generate Cloudflare-compatible build
```
4. **Deploy**:
```bash
npx wrangler deploy .open-next/worker
```
### Configuration Files
- [wrangler.toml](mdc:wrangler.toml) - Cloudflare Workers configuration
- [open-next.config.ts](mdc:open-next.config.ts) - OpenNext build configuration
- [next.config.ts](mdc:next.config.ts) - Next.js configuration
### Required wrangler.toml Settings
```toml
name = "site-worker"
main = ".open-next/worker/index.mjs"
compatibility_date = "2024-09-23"
compatibility_flags = ["nodejs_compat"]
assets = { directory = ".open-next/assets" }
```
## Environment Variables
Create `.env.sample` and keep it synchronized. Typical keys:
```
NEXT_PUBLIC_SITE_URL=
RESEND_API_KEY=
CF_PAGES_URL=
```
**Security**: Never commit real secrets. Use `.env` locally and environment variables in production.
## Build Configuration
- ESLint and TypeScript errors are ignored during build for deployment speed
- CI still gates on `lint` and `type-check` before merge
- Always fix errors instead of bypassing checks
## Deployment Checklist
- [ ] Run `npm run type-check` and `npm run lint`
- [ ] Ensure `assets.directory` matches OpenNext output
- [ ] Keep compatibility date at or after 2024-09-23
- [ ] Test build locally with `npm run build`
- [ ] Verify OpenNext build artifacts in `.open-next/`

View File

@ -0,0 +1,74 @@
---
alwaysApply: true
---
# Development Workflow
## Git Workflow
- **Default Branch**: `main` is protected
- **Workflow**: feature branches → PR → required checks → squash merge
- **Commit Format**: Conventional Commits
- `feat: add contact form schema`
- `fix: correct Image remote pattern`
- `chore: bump dependencies`
## Required Checks
Before any merge:
- `npm run lint` - ESLint validation
- `npm run type-check` - TypeScript validation
- `npm run build` - Production build (optional locally, required in CI)
## Development Commands
```bash
# Setup
npm ci # Install dependencies
# Development
npm run dev # Dev server with Turbopack
npm run type-check # TypeScript validation
npm run lint # ESLint validation
# Build & Deploy
npm run build # Production build
npm run start # Preview production build
npx open-next@latest build # OpenNext build
npx wrangler deploy .open-next/worker # Deploy to Cloudflare
```
## Code Quality
### TypeScript
- Use strict mode (enabled in [tsconfig.json](mdc:tsconfig.json))
- Prefer type inference over explicit types
- Use absolute imports with `@` alias
### ESLint
- Follow Next.js ESLint config
- Fix all linting errors before committing
- Don't bypass checks in production builds
## Testing Strategy
- **Unit Tests**: Place close to sources, name with `.test.ts` or `.test.tsx`
- **E2E Tests**: Optional Playwright setup
- **Manual Testing**: Test all user flows before deployment
## Pull Request Guidelines
- Keep PRs small and reviewable
- Include screenshots for UI changes
- Update [AGENTS.md](mdc:AGENTS.md) if conventions change
- Justify new dependencies in PR description
- Never commit secrets or sensitive data
## Common Pitfalls to Avoid
1. Adding remote image domains without updating [next.config.ts](mdc:next.config.ts)
2. Introducing client components unnecessarily
3. Duplicating navigation in nested layouts
4. Bypassing Tailwind utilities for custom CSS
5. Forgetting to update middleware whitelist for new static assets
6. Committing secrets instead of using environment variables

View File

@ -0,0 +1,87 @@
---
globs: **/*form*.tsx,**/*Form*.tsx
---
# Forms and Validation
## Form Library Stack
- **Forms**: react-hook-form for form state management
- **Validation**: Zod schemas for type-safe validation
- **Resolvers**: @hookform/resolvers for integration
## Form Structure
```typescript
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
// Define schema
const formSchema = z.object({
name: z.string().min(1, 'Name is required'),
email: z.string().email('Invalid email address'),
message: z.string().min(10, 'Message must be at least 10 characters')
})
type FormData = z.infer<typeof formSchema>
export function ContactForm() {
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
defaultValues: {
name: '',
email: '',
message: ''
}
})
const onSubmit = (data: FormData) => {
// Handle form submission
}
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
{/* Form fields with error handling */}
</form>
)
}
```
## Error Handling Rules
1. **Field-level errors**: Show validation errors under each field
2. **Generic submit error**: Display general submission errors
3. **Never swallow errors**: Always surface validation and submission errors
4. **Loading states**: Show loading indicators during submission
## Form Components
Use shadcn/ui form components from [src/components/ui/form.tsx](mdc:src/components/ui/form.tsx):
```typescript
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="your@email.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
```
## Validation Patterns
- Use Zod for all form validation
- Provide clear, user-friendly error messages
- Validate on both client and server side
- Handle async validation (e.g., email uniqueness)

View File

@ -0,0 +1,75 @@
---
globs: **/*.tsx,**/*.ts
---
# Images and Assets
## Image Handling
### Next.js Image Component
Always use Next.js Image component for remote images:
```typescript
import Image from 'next/image'
<Image
src="https://images.unsplash.com/photo-123"
alt="Descriptive alt text"
width={800}
height={600}
className="rounded-lg"
/>
```
### Remote Image Domains
Current allowed domains in [next.config.ts](mdc:next.config.ts):
- `images.unsplash.com`
**When adding new external domains:**
1. Add to `remotePatterns` in [next.config.ts](mdc:next.config.ts)
2. Document the change in [AGENTS.md](mdc:AGENTS.md)
## Static Assets
### Public Directory
- Keep `public/` for truly static assets only
- Current assets: favicon files, images (OLIVER.jpeg, etc.), GIFs
### Middleware Whitelist
**CRITICAL**: When adding new static assets to `public/`, update the middleware allowlist in [src/middleware.ts](mdc:src/middleware.ts) line 8:
```typescript
// Add new asset paths here
if (pathname === '/' ||
pathname.startsWith('/_next') ||
pathname.startsWith('/favicon.') ||
pathname === '/OLIVER.jpeg' ||
pathname === '/new-asset.jpg' || // Add new assets here
pathname === '/reel.mp4') {
return NextResponse.next();
}
```
**Common symptom**: If assets return "text/html" Content-Type error, the path isn't whitelisted.
## Asset Optimization
- Use appropriate image formats (WebP when possible)
- Provide proper alt text for accessibility
- Use responsive images with `sizes` prop
- Optimize file sizes for web delivery
## Video Files
Custom headers are configured in [next.config.ts](mdc:next.config.ts) for `.mp4` files:
```typescript
{
source: "/:path*.mp4",
headers: [
{
key: "Content-Type",
value: "video/mp4",
},
],
}
```

View File

@ -0,0 +1,60 @@
---
alwaysApply: true
---
# Biohazard VFX Website - Project Structure
This is a Next.js 15.5.4 VFX studio website built with React 19, TypeScript, Tailwind CSS 4, and shadcn/ui components.
## Core Architecture
- **Framework**: Next.js 15.5.4 with App Router
- **Styling**: Tailwind CSS 4 + shadcn/ui components
- **Animation**: Framer Motion for subtle transitions
- **Forms**: react-hook-form + Zod validation
- **Deployment**: Cloudflare Workers via OpenNext
- **Package Manager**: npm
## Project Layout
```
src/
├─ app/ # App Router pages and layouts
│ ├─ (marketing)/ # Route groups
│ ├─ api/ # Route handlers
│ └─ layout.tsx # Root layout with global providers
├─ components/ # Reusable UI components
│ └─ ui/ # shadcn/ui primitives
├─ data/ # JSON/TS data objects
├─ lib/ # Utilities, hooks, server actions
├─ styles/ # globals.css, Tailwind utilities
└─ types/ # Shared TypeScript types
```
## Key Files
- [AGENTS.md](mdc:AGENTS.md) - Single source of truth for development guidelines
- [package.json](mdc:package.json) - Dependencies and scripts
- [next.config.ts](mdc:next.config.ts) - Next.js configuration
- [tsconfig.json](mdc:tsconfig.json) - TypeScript configuration with @ alias
- [src/middleware.ts](mdc:src/middleware.ts) - Route protection and redirects
- [src/app/layout.tsx](mdc:src/app/layout.tsx) - Root layout with fonts and metadata
## Import Aliases
Always use absolute imports with `@` mapped to `src/`:
```typescript
import { Component } from '@/components/Component'
import { data } from '@/data/projects'
```
## Development Commands
```bash
npm ci # Install dependencies
npm run dev # Development server with Turbopack
npm run type-check # TypeScript validation
npm run lint # ESLint validation
npm run build # Production build
npx open-next@latest build # OpenNext build for Cloudflare
```

View File

@ -0,0 +1,67 @@
---
globs: src/app/**/*.tsx
---
# Routing and Layout Rules
## App Router Structure
- **Pages**: Live in `src/app/` directory
- **Server Components**: Default to server components, promote to client only when needed
- **Layout Hierarchy**: Root layout owns global providers, navigation, and footer
- **Route Groups**: Use `(marketing)` for grouped routes without affecting URL structure
## Layout Rules
### Root Layout ([src/app/layout.tsx](mdc:src/app/layout.tsx))
- Owns global providers and theme class
- Contains `<Navigation />` and `<Footer />` components
- Sets up font variables and metadata
- **DO NOT** duplicate these in child layouts
### Page Layouts
- Keep server components as default
- Add `"use client"` only when necessary for interactivity
- Define unique metadata for each route
## Metadata Requirements
Every page must have:
```typescript
export const metadata: Metadata = {
title: "Unique Page Title",
description: "Unique description for SEO",
// Include Open Graph and Twitter cards
}
```
## Route Protection
The [src/middleware.ts](mdc:src/middleware.ts) currently redirects all routes to `/` except:
- Home page (`/`)
- Next.js internal routes (`/_next/*`)
- Favicon files
- Specific static assets (OLIVER.jpeg, OLIVER_depth.jpeg, etc.)
## Static Assets
When adding new files to `public/`, update the middleware allowlist in [src/middleware.ts](mdc:src/middleware.ts) line 8 to prevent 307 redirects.
## Common Patterns
```typescript
// Page component
export default function PageName() {
return (
<div className="container mx-auto px-4">
{/* Page content */}
</div>
)
}
// With metadata
export const metadata: Metadata = {
title: "Page Title",
description: "Page description"
}
```

View File

@ -0,0 +1,78 @@
---
globs: src/app/**/page.tsx,src/app/**/layout.tsx
---
# SEO and Metadata
## Metadata API Requirements
Every page must define unique metadata using the Next.js Metadata API:
```typescript
import type { Metadata } from "next"
export const metadata: Metadata = {
title: "Unique Page Title | Biohazard VFX",
description: "Unique, descriptive page description for SEO",
metadataBase: new URL("https://biohazardvfx.com"),
openGraph: {
title: "Page Title",
description: "Page description",
type: "website",
locale: "en_US",
siteName: "Biohazard VFX",
},
twitter: {
card: "summary_large_image",
title: "Page Title",
description: "Page description",
},
}
```
## Root Layout Metadata
The root layout in [src/app/layout.tsx](mdc:src/app/layout.tsx) includes:
- Global site metadata
- Open Graph configuration
- Twitter card setup
- JSON-LD structured data
- Canonical URLs
## SEO Best Practices
1. **Unique Titles**: Each page must have a unique, descriptive title
2. **Descriptions**: Write compelling meta descriptions (150-160 characters)
3. **Structured Data**: Use JSON-LD for rich snippets
4. **Canonical URLs**: Set canonical URLs to prevent duplicate content
5. **Open Graph**: Include OG tags for social media sharing
6. **Twitter Cards**: Configure Twitter card metadata
## Structured Data Example
```typescript
const jsonLd = {
"@context": "https://schema.org",
"@type": "Organization",
name: "Biohazard VFX",
description: "Visual effects studio",
url: "https://biohazardvfx.com",
logo: "https://biohazardvfx.com/logo.png",
sameAs: ["https://instagram.com/biohazardvfx"],
}
```
## Page-Specific Metadata
- **Home**: Focus on main services and value proposition
- **Portfolio**: Highlight featured projects and capabilities
- **Services**: Target specific service keywords
- **About**: Include company information and team details
- **Contact**: Include location and contact information
## Image SEO
- Use descriptive alt text for all images
- Optimize image file names
- Include image dimensions
- Use appropriate image formats (WebP when possible)

View File

@ -0,0 +1,60 @@
---
globs: *.tsx,*.ts,*.css
---
# UI System Guidelines
## Theme & Design System
- **Default Theme**: Dark mode only - do not introduce light-first designs
- **Typography**: Use CSS variables for fonts (Geist, Geist Mono, Bebas Neue, Orbitron, etc.)
- **Components**: Use shadcn/ui primitives from [src/components/ui/](mdc:src/components/ui/)
- **Spacing**: Follow Tailwind 4 defaults, prefer utility classes over custom CSS
- **Animation**: Keep Framer Motion subtle and meaningful only
## Component Structure
```typescript
// Use shadcn/ui primitives as base
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
// Extend with local wrappers when needed
export function CustomComponent() {
return (
<Card className="bg-black border-gray-800">
<Button variant="outline" className="text-white">
Action
</Button>
</Card>
)
}
```
## Styling Rules
1. **Dark Theme**: All components must work in dark mode
2. **Tailwind First**: Use utility classes before custom CSS
3. **Component Variants**: Use class-variance-authority for component variants
4. **Responsive**: Mobile-first responsive design
5. **Accessibility**: Include proper ARIA labels and semantic HTML
## Font Usage
Available font variables from [src/app/layout.tsx](mdc:src/app/layout.tsx):
- `--font-geist-sans` (default)
- `--font-geist-mono`
- `--font-bebas`
- `--font-orbitron`
- `--font-inter`
- `--font-jetbrains-mono`
- `--font-space-mono`
- `--font-rajdhani`
- `--font-exo-2`
## Animation Guidelines
- Use Framer Motion sparingly for meaningful transitions
- Prefer CSS transitions for simple hover effects
- Keep animations under 300ms for UI feedback
- Respect `prefers-reduced-motion` for accessibility

View File

@ -0,0 +1,99 @@
---
description: VFX studio specific patterns and requirements
---
# VFX Studio Specific Guidelines
## Media Handling
### Video Components
- Use [src/components/VideoPlayer.tsx](mdc:src/components/VideoPlayer.tsx) for video playback
- Use [src/components/ReelPlayer.tsx](mdc:src/components/ReelPlayer.tsx) for demo reels
- Support multiple video formats (MP4, WebM)
- Include proper video metadata and thumbnails
### Image Components
- Use [src/components/DepthMap.tsx](mdc:src/components/DepthMap.tsx) for depth map visualizations
- Implement lazy loading for portfolio images
- Use Next.js Image optimization for all media
## Portfolio Patterns
### Project Showcase
```typescript
// Use ProjectCard component for consistent project display
import { ProjectCard } from '@/components/ProjectCard'
import { ProjectShowcase } from '@/components/ProjectShowcase'
// Project data structure from src/data/projects.ts
interface Project {
id: string
title: string
description: string
category: 'commercial' | 'music-video' | 'film' | 'animation'
client?: string
year: number
images: string[]
videoUrl?: string
tags: string[]
}
```
### Service Categories
- Visual Effects (VFX)
- Motion Graphics
- 3D Animation
- Compositing
- Color Grading
- Post-Production
## Client Work Patterns
### Client Logo Grid
- Use [src/components/ClientLogoGrid.tsx](mdc:src/components/ClientLogoGrid.tsx)
- Display client logos with proper attribution
- Ensure logos are high-quality and properly sized
### Project Filtering
- Implement category-based filtering
- Support tag-based search
- Include year-based sorting
## Performance Considerations
### Media Optimization
- Compress images and videos for web delivery
- Use appropriate formats (WebP for images, MP4 for videos)
- Implement progressive loading for large media files
- Use CDN for media delivery
### Loading States
- Show skeleton loaders for media content
- Implement progressive image loading
- Use intersection observer for lazy loading
## VFX-Specific UI Elements
### Before/After Comparisons
- Implement split-screen comparisons
- Use slider controls for reveal effects
- Include toggle for before/after views
### Process Showcases
- Show breakdowns of VFX work
- Include wireframe and final render comparisons
- Display technical specifications
## Content Guidelines
### Project Descriptions
- Include technical details (software used, techniques)
- Mention client and project scope
- Highlight challenges and solutions
- Use industry-standard terminology
### Service Descriptions
- Be specific about capabilities
- Include typical project timelines
- Mention software and hardware capabilities
- Provide clear pricing structure (if applicable)