| name | minimalist-portfolio-design |
| description | Minimalist, typography-focused portfolio design system inspired by neo-brutalist and Swiss design principles. Emphasizes bold typography, generous whitespace, monochromatic color schemes, and elegant simplicity for developer/designer portfolios. |
Minimalist Portfolio Design Skill
This skill guides the creation of clean, typography-focused portfolio websites with a minimalist aesthetic. Based on neo-brutalist and Swiss design principles, this approach prioritizes readability, visual hierarchy, and professional presentation over decorative elements.
Core Design Philosophy
Design Principles:
- Typography as the hero: Let type do the heavy lifting
- Radical simplicity: Remove everything that isn't essential
- Generous whitespace: Space is a design element, not emptiness
- Monochromatic palette: Black, white, and shades of gray
- Grid-based precision: Everything aligns to an invisible grid
- No decoration: Form follows function
- Swiss design influence: Clean, asymmetric layouts with clear hierarchy
What This Style IS:
- Bold, confident, professional
- Clean and uncluttered
- Typography-driven
- Timeless and elegant
- Easy to scan and navigate
What This Style IS NOT:
- Colorful or playful (no bright colors)
- Heavily animated (subtle interactions only)
- Cluttered or busy
- Decorative or ornamental
- Trendy or flashy
Typography System
Font Selection
Primary Typeface Options (Neo-Grotesk/Geometric Sans):
- Aeonik (as shown in reference) - Neo-Grotesk, geometric, modern
- Inter - Versatile, excellent screen readability, free
- Satoshi - Geometric, clean, contemporary feel
- Supreme - Bold, geometric, great for large display text
- Space Grotesk - Modern geometric with personality
- Neue Montreal - Swiss-inspired, clean lines
- General Sans - Balanced, professional, versatile
System Font Stack (fallback):
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
Type Scale & Hierarchy
Display/Hero Text (Large greeting like "Hello"):
- Desktop: 8rem-12rem (128px-192px)
- Tablet: 6rem-8rem (96px-128px)
- Mobile: 4rem-6rem (64px-96px)
- Weight: 400-500 (Regular to Medium)
- Line height: 0.9-1.0 (tight)
- Letter spacing: -0.02em to -0.04em (tight)
Section Headers (Like "Colors", "Typography"):
- Desktop: 4rem-6rem (64px-96px)
- Tablet: 3rem-4rem (48px-64px)
- Mobile: 2.5rem-3rem (40px-48px)
- Weight: 400-500
- Line height: 1.1
- Letter spacing: -0.02em
Subheadings/Labels (Like "Primary", "Secondary"):
- Size: 1.25rem-1.5rem (20px-24px)
- Weight: 400-500
- Line height: 1.4
- Letter spacing: 0
Body Text (Like the description under "Colors"):
- Size: 1rem-1.125rem (16px-18px)
- Weight: 400
- Line height: 1.6-1.7
- Letter spacing: 0
- Max width: 65ch (characters) for readability
Small Text/Labels (Like "Scroll down ↓"):
- Size: 0.875rem-1rem (14px-16px)
- Weight: 400
- Line height: 1.5
- Letter spacing: 0.01em
Navigation Links:
- Size: 1rem-1.125rem (16px-18px)
- Weight: 400-500
- Letter spacing: 0
Typography Rules
- One font family for the entire site (consistency over variety)
- Use font weight to create hierarchy, not multiple fonts
- Tight letter spacing for large display text
- Standard spacing for body text
- Generous line height (1.6-1.7) for readable body text
- Tight line height (0.9-1.1) for display text
- Left-aligned text (not centered, except for specific hero elements)
- No all-caps for body text (only for small labels if needed)
Color System
Monochromatic Palette (Primary Approach)
This is the CORE aesthetic - black, white, and grays only.
Color Palette:
--color-black: #222222; /* Primary - rich black, not pure black */
--color-gray-dark: #7B7B7B; /* Secondary - medium gray */
--color-gray-light: #F8F8F8; /* Tertiary - off-white background */
--color-white: #FFFFFF; /* Pure white */
--color-gray-50: #FAFAFA; /* Lightest gray */
--color-gray-100: #F5F5F5; /* Very light gray */
--color-gray-200: #EEEEEE; /* Light gray */
--color-gray-300: #E0E0E0; /* Border gray */
--color-gray-400: #BDBDBD; /* Disabled state */
--color-gray-500: #9E9E9E; /* Mid gray */
--color-gray-600: #757575; /* Text gray */
--color-gray-700: #616161; /* Dark text gray */
--color-gray-800: #424242; /* Almost black */
--color-gray-900: #212121; /* Darkest gray */
Color Usage:
- Background: #F8F8F8 or #FFFFFF (light mode) / #0A0A0A (dark mode)
- Text primary: #222222 (light mode) / #F8F8F8 (dark mode)
- Text secondary: #7B7B7B (both modes)
- Borders: #E0E0E0 (light mode) / #2A2A2A (dark mode)
- Cards/Surfaces: #FFFFFF (light mode) / #1A1A1A (dark mode)
- Hover states: Slight darkening/lightening (10-15% opacity change)
Accent Color Option (Minimal Use)
Only if absolutely necessary - use ONE accent color sparingly:
- For CTAs only (Book A Call button)
- For hover states on key elements
- For active link indicators
- Never for backgrounds or large areas
Suggested Accent Colors (choose ONE):
- Tech Blue: #0066FF (IBM blue, professional)
- Success Green: #00B386 (subtle, trustworthy)
- Warm Red: #FF3B30 (Apple red, attention-grabbing)
- Keep it black: No accent color at all (purest approach)
Color Application Rules
- Light Mode Default: White/off-white background (#F8F8F8 to #FFFFFF)
- Dark Mode Option: Dark gray/black background (#0A0A0A to #121212)
- Text contrast: Minimum 4.5:1 ratio for body text, 3:1 for large text
- No gradients: Solid colors only
- No shadows (or very subtle 1-2px shadows): Use borders instead
- Hover states: Opacity changes (0.7-0.8) or background color shifts
- Photography: Black and white or desaturated (like the reference portrait)
Dark Mode Considerations
If implementing dark mode:
- Background: #0A0A0A to #121212 (not pure black)
- Surfaces: #1A1A1A to #222222
- Text: #F8F8F8 to #FFFFFF
- Borders: #2A2A2A to #333333
- Keep the same monochromatic approach
- Avoid pure white on pure black (causes eye strain)
Layout & Spacing System
Grid System
Container Widths:
- Max content width: 1440px-1600px
- Content padding: 5-10% on sides (responsive)
- Mobile padding: 24px-32px on sides
Grid Structure:
- 12-column grid for flexibility
- For hero: Asymmetric 60/40 or 50/50 split (text/image)
- Generous gutters: 32px-48px between columns
Spacing Scale (8pt Grid)
All spacing in multiples of 8:
4px (0.25rem) - Minimal gap
8px (0.5rem) - Tight spacing
16px (1rem) - Small spacing
24px (1.5rem) - Medium spacing
32px (2rem) - Standard spacing
48px (3rem) - Large spacing
64px (4rem) - XL spacing
96px (6rem) - Section spacing (mobile)
128px (8rem) - Section spacing (tablet)
160px (10rem) - Section spacing (desktop)
192px (12rem) - Hero spacing
Vertical Rhythm
Between sections:
- Mobile: 96px-128px
- Tablet: 128px-160px
- Desktop: 160px-192px
Within sections:
- Between heading and content: 32px-48px
- Between paragraphs: 24px-32px
- Between list items: 16px-24px
Component spacing:
- Navigation padding: 24px-32px vertical
- Card padding: 32px-48px internal
- Button padding: 16px-32px horizontal, 12px-16px vertical
Responsive Breakpoints
/* Mobile-first approach */
mobile: 320px-640px
tablet: 641px-1024px
desktop: 1025px-1440px
xl: 1441px+
/* Tailwind equivalent */
sm: 640px
md: 768px
lg: 1024px
xl: 1280px
2xl: 1536px
Layout Patterns for Portfolio
Hero Section (Full Viewport)
Layout: 50/50 split (text left, image right)
Height: 100vh (full viewport)
Vertical alignment: center
Left side:
- Large greeting text: "Hello"
- Subtitle: "— It's [Name] a [role]"
- Stats (optional): "+200 Project completed"
- Scroll indicator: "Scroll down ↓"
- Vertical text (optional): "Product designer"
Right side:
- Large portrait photo
- Black and white or desaturated
- Professional, confident pose
- No background (or subtle gradient)
Navigation:
- Position: Absolute top or fixed top
- Height: 80px-100px
- Logo: Top left (24px-32px from edges)
- Links: Top center or right
- CTA: Top right ("Book A Call" with arrow)
- Background: Transparent or subtle backdrop-blur on scroll
- Border: None or 1px bottom border (#E0E0E0)
About/Info Sections
Layout: Single column, centered content
Max width: 800px-900px for readability
Heading: Left-aligned, large
Body: Left-aligned, comfortable line length
Portfolio Grid
Desktop: 3 columns
Tablet: 2 columns
Mobile: 1 column
Gap: 32px-48px
Card aspect ratio: 4:3 or 16:9
Whitespace Philosophy
More space = More premium
- Empty space is a design element
- Don't fill every pixel
- Let content breathe
- Use whitespace to guide the eye
- Balance is key: Not too sparse, not too crowded
Whitespace Checklist:
- Is there breathing room around all elements?
- Can the eye easily identify sections?
- Does the layout feel calm and organized?
- Are related items grouped with less space?
- Are unrelated items separated with more space?
Component Design Patterns
Navigation Bar
Structure:
[Logo] [About Me] [Portfolio] [Services] [Blog] [Book A Call →]
Specifications:
- Height: 80px-100px
- Position: Fixed top with backdrop-filter blur OR absolute
- Background: Transparent → Semi-transparent on scroll
- Logo: Simple wordmark or icon (24px-32px size)
- Links: 16px-18px, Medium weight
- Link spacing: 32px-48px apart
- CTA button: Outlined or filled, right-aligned
- Hover: Opacity 0.7 or subtle underline (1-2px)
Mobile Navigation:
- Hamburger menu: Simple 3-line icon (24px)
- Menu: Full-screen overlay OR slide-in drawer
- Links: Larger text (24px-32px), vertical stack
- Animation: Smooth 200-300ms ease
Buttons
Primary Button (CTA):
padding: 14px-16px vertical, 28px-32px horizontal
border-radius: 4px-8px (subtle, not pill)
font-size: 16px-18px
font-weight: 500
background: #222222 (or accent color)
color: #FFFFFF
border: none OR 1-2px solid
hover: opacity: 0.9 or transform: translateY(-2px)
Secondary Button:
Same sizing as primary
background: transparent
color: #222222
border: 1-2px solid #222222
hover: background: #222222, color: #FFFFFF
Text Link:
No background, no border
Underline: 1px solid (only on hover) OR always present
Hover: opacity: 0.7
Cards (Project Cards)
Structure:
┌──────────────────────────┐
│ │
│ Project Image │
│ (16:9 ratio) │
│ │
├──────────────────────────┤
│ Project Title │
│ Brief description... │
│ [Tag] [Tag] [Tag] │
└──────────────────────────┘
Specifications:
- Background: #FFFFFF or #FAFAFA
- Border: 1px solid #E0E0E0 OR subtle shadow
- Border-radius: 8px-12px (subtle)
- Padding: 0 (image edge-to-edge) + 24px-32px bottom
- Image: Fill width, fixed aspect ratio
- Hover: Scale 1.02 OR lift with shadow OR border color change
- Transition: 200-300ms ease
Card Content:
- Title: 20px-24px, Medium weight
- Description: 16px, Regular, 2-3 lines max
- Tags: 12px-14px, padding 6px-12px, rounded-full, border 1px
Stats Display ("+200 Project completed")
Style:
Number: 3rem-4rem (48px-64px), Medium weight
Label: 1rem (16px), Regular weight, gray color
Layout: Vertical stack
Spacing: 8px between number and label
Positioning:
- Near hero text
- Subtle, not competing with main message
- Can be multiple stats side-by-side (32px-48px gap)
Photography/Images
Portrait Photo (Hero):
- Black and white OR heavily desaturated
- Professional, direct gaze
- Clean background (solid color or subtle gradient)
- High quality: Sharp, well-lit
- Aspect ratio: Portrait (3:4) or square (1:1)
- Size: Large, fills 40-50% of viewport
Project Images:
- High quality: Mockups or screenshots
- Consistent aspect ratio across all projects
- Consider: 16:9 (landscape) or 4:3
- Hover: Slight zoom (scale 1.05) or no effect
- Alt text: Always include for accessibility
Iconography
Icon Style:
- Minimal: Line icons only (no filled icons)
- Stroke weight: 1.5px-2px
- Size: 20px-24px standard, 32px-40px for featured
- Color: Match text color (#222222 or #7B7B7B)
- Examples: Arrow (→), Menu (≡), Close (×), Social icons
Icon Usage:
- Navigation: Hamburger menu, arrow for CTA
- Social links: GitHub, LinkedIn, Twitter/X, Email
- Arrows: For links, buttons, scroll indicators
- Keep it minimal: Don't overuse icons
Forms (Contact Forms)
Input Fields:
padding: 16px
border: 1px solid #E0E0E0
border-radius: 4px-8px
background: #FFFFFF or #FAFAFA
font-size: 16px
focus: border-color: #222222, outline: none
Label:
font-size: 14px-16px
font-weight: 500
margin-bottom: 8px
color: #222222
Layout:
- Single column, full width
- Fields: Name, Email, Message (3 fields max)
- Spacing: 24px between fields
- Submit button: Full width or right-aligned
Scroll Indicator
Text Style:
"Scroll down ↓"
font-size: 14px-16px
color: #7B7B7B
position: bottom center or bottom left
animation: subtle bounce (optional)
Alternative:
- Animated line/arrow
- Mouse icon with wheel animation
- Keep it subtle and minimal
Portfolio Page Structure
1. Hero Section (Above the Fold)
Purpose: Immediate impact, clear identity
Content:
- Large greeting: "Hello" (or your variation)
- Name and role: "— It's [Name] a [role]"
- Optional stats: "+200 Project completed" "+50 Startup raised"
- Scroll indicator: "Scroll down ↓"
- Portrait photo: Right side, B&W, professional
Layout:
- Full viewport height (100vh)
- 50/50 split (text left, photo right) OR 60/40
- Vertically centered content
- White or off-white background
- Minimalist navigation at top
Typography:
- "Hello": 10rem-12rem desktop, 6rem mobile
- Subtitle: 1.25rem-1.5rem, gray color (#7B7B7B)
- Stats: 3rem-4rem numbers, 1rem labels
Key Principles:
- Less is more: Don't overcrowd
- Immediate clarity: Who you are, what you do
- Professional confidence: Bold but not aggressive
- Clear next action: Scroll or CTA button
2. About Section
Purpose: Personal connection, your story
Content:
- Section heading: "About" or "Who I Am"
- Your story: 2-3 paragraphs max
- What you do currently
- What drives you
- Optional: Skills/tools you use
Layout:
- Single column, centered
- Max width: 800px for readability
- Large section heading: 4rem-6rem
- Body text: 1.125rem, line-height 1.7
- Optional: Photo or no photo
Tone:
- Professional but human
- Authentic, not generic
- Confident without ego
- Clear and concise
3. Portfolio/Work Section
Purpose: Showcase your best work
Content:
- Section heading: "Work", "Projects", or "Selected Work"
- 4-8 projects (quality over quantity)
- Each project: Image, title, description, tech stack
Layout:
- Grid: 3 columns desktop, 2 tablet, 1 mobile
- OR: 2 columns (larger cards)
- OR: Bento grid (varied sizes for featured work)
- Generous gaps: 32px-48px
Project Card:
┌─────────────────────────┐
│ │
│ Project Image │
│ (Full width, 16:9) │
│ │
│ Project Title │
│ Brief description of │
│ what you built and why │
│ [React] [Next.js] [TS] │
│ │
│ [View Project →] │
└─────────────────────────┘
Interaction:
- Hover: Subtle scale or border change
- Click: Link to case study or live site
- Clean, minimal hover states
4. Services Section (Optional)
Purpose: What you offer clients/employers
Content:
- Section heading: "Services" or "What I Do"
- 3-5 service offerings
- Brief description for each
Layout:
- Grid: 2-3 columns OR single column list
- Each service: Icon (optional), title, description
- Clean, scannable
Examples:
- Web Development
- Mobile App Development
- UI/UX Design
- Consulting
- Custom Solutions
5. Skills/Tech Stack Section
Purpose: Quick scan of your technical abilities
Content:
- Section heading: "Skills" or "Tech Stack"
- Technologies you use
- Grouped by category (optional)
Layout Options:
Option A: Simple List
Frontend: React, Next.js, TypeScript, Tailwind
Backend: Node.js, Supabase, PostgreSQL
Mobile: React Native, Expo
Tools: Git, Figma, VS Code
Option B: Icon Grid
[React] [Next.js] [TypeScript] [Tailwind]
[Node] [Supabase] [PostgreSQL] [Git]
[Figma] [React Native] [Expo]
Option C: Categorized Cards
┌──────────────────┐ ┌──────────────────┐
│ Frontend │ │ Backend │
│ • React │ │ • Node.js │
│ • Next.js │ │ • Supabase │
│ • TypeScript │ │ • PostgreSQL │
└──────────────────┘ └──────────────────┘
Styling:
- Monochromatic: Black text on white/gray background
- OR: Subtle gray tags with borders
- Consistent sizing and spacing
- No skill bars or percentage indicators
6. Contact Section
Purpose: Easy way to get in touch
Content:
- Section heading: "Get In Touch" or "Contact"
- Email link OR contact form (prefer simplicity)
- Social links: GitHub, LinkedIn, Twitter
- Optional: Calendar booking link
Layout Options:
Option A: Minimal (Preferred)
Let's work together
email@example.com
[GitHub] [LinkedIn] [Twitter]
Option B: Simple Form
Name: [________________]
Email: [________________]
Message: [____________]
[____________]
[Send Message]
Styling:
- Centered content
- Large, clear email link
- Social icons: Line style, 24px-32px
- Button: Same style as primary CTA
- Generous spacing
7. Footer
Purpose: Supporting information, links
Content:
- Copyright: © 2024 Your Name
- Links: Privacy, Terms (if needed)
- Social links (if not in contact section)
- Optional: Back to top link
Layout:
- Single row, horizontal
- OR: Minimal vertical stack on mobile
- Small text: 14px
- Color: Gray (#7B7B7B)
- Padding: 32px-48px vertical
Styling:
- Clean and minimal
- No background color (or subtle gray)
- Border top: 1px solid #E0E0E0 (optional)
Page Architecture Summary
┌────────────────────────────────────┐
│ Navigation (Fixed/Absolute Top) │
├────────────────────────────────────┤
│ │
│ Hero Section (100vh) │
│ • Large greeting │
│ • Your name + role │
│ • Portrait photo │
│ │
├────────────────────────────────────┤
│ │
│ About Section │
│ • Who you are │
│ • Your story │
│ │
├────────────────────────────────────┤
│ │
│ Work Section │
│ • Project grid │
│ • 4-8 projects │
│ │
├────────────────────────────────────┤
│ │
│ Skills Section │
│ • Tech stack │
│ • Tools │
│ │
├────────────────────────────────────┤
│ │
│ Contact Section │
│ • Email or form │
│ • Social links │
│ │
├────────────────────────────────────┤
│ Footer │
│ • Copyright + links │
└────────────────────────────────────┘
Spacing Between Sections:
- Mobile: 96px-128px
- Desktop: 160px-192px
Technical Implementation
Next.js + TypeScript + Tailwind Setup
Recommended Stack:
- Next.js 14+ (App Router)
- TypeScript
- Tailwind CSS
- Framer Motion (for animations)
- next/font (for font optimization)
Tailwind Configuration
// tailwind.config.ts
import type { Config } from 'tailwindcss'
const config: Config = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
colors: {
black: '#222222',
'gray-dark': '#7B7B7B',
'gray-light': '#F8F8F8',
white: '#FFFFFF',
},
fontFamily: {
sans: ['var(--font-inter)', 'system-ui', 'sans-serif'],
},
fontSize: {
'display': ['10rem', { lineHeight: '0.9', letterSpacing: '-0.02em' }],
'hero': ['6rem', { lineHeight: '1.0', letterSpacing: '-0.02em' }],
},
spacing: {
'128': '32rem',
'144': '36rem',
'160': '40rem',
},
},
},
plugins: [],
}
export default config
Font Setup (next/font)
// app/layout.tsx
import { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
display: 'swap',
})
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={inter.variable}>
<body className="font-sans bg-gray-light text-black antialiased">
{children}
</body>
</html>
)
}
Hero Section Component Example
// components/Hero.tsx
'use client'
import Image from 'next/image'
import { motion } from 'framer-motion'
export default function Hero() {
return (
<section className="h-screen flex items-center px-8 md:px-16 lg:px-20">
<div className="max-w-[1440px] mx-auto w-full">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
{/* Left: Text Content */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="space-y-8"
>
{/* Stats */}
<div className="flex gap-12 text-sm">
<div>
<div className="text-4xl font-medium">+200</div>
<div className="text-gray-dark mt-1">Project completed</div>
</div>
<div>
<div className="text-4xl font-medium">+50</div>
<div className="text-gray-dark mt-1">Startup raised</div>
</div>
</div>
{/* Main Greeting */}
<h1 className="text-hero md:text-display font-medium leading-none tracking-tight">
Hello
</h1>
{/* Subtitle */}
<p className="text-xl text-gray-dark">
— It's Kanji, a web developer
</p>
{/* Scroll Indicator */}
<div className="pt-16">
<p className="text-sm text-gray-dark">Scroll down ↓</p>
</div>
</motion.div>
{/* Right: Portrait Photo */}
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.6, delay: 0.2 }}
className="relative aspect-[3/4] max-w-xl mx-auto"
>
<Image
src="/portrait.jpg"
alt="Kanji - Web Developer"
fill
className="object-cover grayscale"
priority
/>
</motion.div>
</div>
</div>
</section>
)
}
Navigation Component Example
// components/Navigation.tsx
'use client'
import Link from 'next/link'
import { useState, useEffect } from 'react'
export default function Navigation() {
const [scrolled, setScrolled] = useState(false)
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 50)
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [])
return (
<nav
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
scrolled
? 'bg-white/80 backdrop-blur-md border-b border-gray-light'
: 'bg-transparent'
}`}
>
<div className="max-w-[1440px] mx-auto px-8 md:px-16 lg:px-20">
<div className="flex items-center justify-between h-20">
{/* Logo */}
<Link href="/" className="text-xl font-medium hover:opacity-70 transition-opacity">
Kanji
</Link>
{/* Navigation Links */}
<div className="hidden md:flex items-center gap-8">
<Link href="#about" className="text-base hover:opacity-70 transition-opacity">
About Me
</Link>
<Link href="#portfolio" className="text-base hover:opacity-70 transition-opacity">
Portfolio
</Link>
<Link href="#services" className="text-base hover:opacity-70 transition-opacity">
Services
</Link>
<Link href="#blog" className="text-base hover:opacity-70 transition-opacity">
Blog
</Link>
</div>
{/* CTA Button */}
<Link
href="#contact"
className="border border-black px-6 py-2.5 rounded-lg hover:bg-black hover:text-white transition-all duration-300"
>
Book A Call →
</Link>
</div>
</div>
</nav>
)
}
Project Card Component
// components/ProjectCard.tsx
import Image from 'next/image'
import Link from 'next/link'
interface ProjectCardProps {
title: string
description: string
image: string
tags: string[]
link: string
}
export default function ProjectCard({ title, description, image, tags, link }: ProjectCardProps) {
return (
<Link href={link} className="group block">
<div className="border border-gray-300 rounded-xl overflow-hidden transition-all duration-300 hover:border-black">
{/* Image */}
<div className="relative aspect-video bg-gray-light">
<Image
src={image}
alt={title}
fill
className="object-cover transition-transform duration-300 group-hover:scale-105"
/>
</div>
{/* Content */}
<div className="p-6 space-y-4">
<h3 className="text-2xl font-medium">{title}</h3>
<p className="text-gray-dark line-clamp-2">{description}</p>
{/* Tags */}
<div className="flex flex-wrap gap-2">
{tags.map((tag) => (
<span
key={tag}
className="text-sm px-3 py-1 border border-gray-300 rounded-full"
>
{tag}
</span>
))}
</div>
</div>
</div>
</Link>
)
}
Performance Optimizations
Image Optimization:
// Always use Next.js Image component
import Image from 'next/image'
// For external images
<Image
src="/path-to-image.jpg"
alt="Description"
width={1200}
height={800}
quality={85}
priority={false} // true for above-fold images
/>
// For dynamic images
<Image
src={imageUrl}
alt={altText}
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
Font Optimization:
// Use next/font for automatic font optimization
import { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap',
preload: true,
})
Code Splitting:
// Dynamic imports for heavy components
import dynamic from 'next/dynamic'
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <p>Loading...</p>,
ssr: false, // if not needed on server
})
Animations & Interactions
Animation Philosophy
Principles:
- Subtle over flashy
- Purposeful, not decorative
- Fast and smooth (200-400ms)
- Respect prefers-reduced-motion
- Enhance, don't distract
Recommended Animations
Page Load:
// Fade in + slight upward movement
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, ease: 'easeOut' }}
Hover States:
/* Subtle opacity change */
transition: opacity 200ms ease;
hover:opacity-70
/* Slight lift */
transition: transform 200ms ease;
hover:translate-y-[-2px]
/* Border color change */
transition: border-color 200ms ease;
hover:border-black
Scroll Animations:
// Use Framer Motion's scroll-triggered animations
import { motion, useScroll, useTransform } from 'framer-motion'
const { scrollYProgress } = useScroll()
const opacity = useTransform(scrollYProgress, [0, 0.5], [1, 0])
<motion.div style={{ opacity }}>
Content
</motion.div>
Navigation Transitions:
/* Backdrop blur on scroll */
backdrop-filter: blur(8px);
transition: background-color 300ms ease, backdrop-filter 300ms ease;
What NOT to Animate
- Don't animate on every scroll
- No auto-playing carousels
- No excessive parallax (causes motion sickness)
- No animations that delay content visibility
- No animations longer than 600ms
Framer Motion Best Practices
// Stagger children animations
<motion.div
initial="hidden"
animate="visible"
variants={{
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1
}
}
}}
>
{items.map((item) => (
<motion.div
key={item.id}
variants={{
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
}}
>
{item.content}
</motion.div>
))}
</motion.div>
Respecting User Preferences
// Check for reduced motion preference
import { useReducedMotion } from 'framer-motion'
const shouldReduceMotion = useReducedMotion()
const variants = shouldReduceMotion
? { hidden: { opacity: 0 }, visible: { opacity: 1 } }
: { hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0 } }
Accessibility Guidelines
WCAG 2.1 AA Standards (Minimum)
Color Contrast:
- Body text: 4.5:1 minimum contrast ratio
- Large text (24px+): 3:1 minimum
- Use contrast checker tools: WebAIM, Stark
Keyboard Navigation:
// Ensure all interactive elements are keyboard accessible
<button
onClick={handleClick}
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
className="focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2"
>
Click Me
</button>
Focus States:
/* Never remove focus outlines without replacement */
focus:outline-none /* Only if you provide alternative */
focus:ring-2
focus:ring-black
focus:ring-offset-2
/* Or use default browser focus */
/* Don't add: outline: none */
Semantic HTML:
<!-- Use proper heading hierarchy -->
<h1>Main Title</h1>
<h2>Section Title</h2>
<h3>Subsection</h3>
<!-- Use semantic elements -->
<nav>...</nav>
<main>...</main>
<article>...</article>
<footer>...</footer>
<!-- Not divs for everything -->
Alt Text for Images:
// Descriptive alt text
<Image
src="/project-screenshot.jpg"
alt="RCVR inventory management dashboard showing real-time stock levels"
width={1200}
height={800}
/>
// Decorative images
<Image
src="/decorative-pattern.jpg"
alt=""
width={100}
height={100}
aria-hidden="true"
/>
ARIA Labels:
// For icon-only buttons
<button aria-label="Open menu">
<MenuIcon />
</button>
// For links with icons
<a href="https://github.com" aria-label="Visit my GitHub profile">
<GitHubIcon />
</a>
Skip to Content Link:
// Allow keyboard users to skip navigation
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 bg-black text-white px-4 py-2 rounded"
>
Skip to main content
</a>
<main id="main-content">
{/* Main content */}
</main>
Responsive Design Considerations
Mobile-First Approach:
/* Base styles (mobile) */
.heading {
font-size: 2rem;
}
/* Tablet and up */
@media (min-width: 768px) {
.heading {
font-size: 3rem;
}
}
/* Desktop */
@media (min-width: 1024px) {
.heading {
font-size: 4rem;
}
}
Touch Targets:
- Minimum size: 44x44px
- Adequate spacing between interactive elements
- Easy to tap on mobile devices
Tailwind Responsive Classes:
<div class="text-4xl md:text-6xl lg:text-8xl">
Responsive Text
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
Cards
</div>
Design Checklist
Before Launching
Visual Design:
- Typography hierarchy is clear and consistent
- Color contrast meets WCAG AA standards (4.5:1 for text)
- Spacing follows 8pt grid system
- All elements are properly aligned
- Whitespace is generous and balanced
- Photography is high quality and professional
- No pixelated or low-res images
- Consistent border radius (8px-12px)
- Consistent hover states on all interactive elements
Content:
- Typos are fixed (use Grammarly or similar)
- All links work and open correctly
- Contact information is accurate
- Project descriptions are clear and concise
- About section tells your story authentically
- Skills/tech stack is current and accurate
- No lorem ipsum or placeholder text
Technical:
- Images are optimized (WebP format, proper sizing)
- Fonts are properly loaded (using next/font)
- Page loads in under 3 seconds
- All pages are responsive (mobile, tablet, desktop)
- Navigation works on mobile (hamburger menu)
- Forms validate inputs properly
- External links open in new tab (_blank + rel="noopener")
- Console has no errors
- Lighthouse score: 90+ on all metrics
Accessibility:
- All images have alt text
- Focus states are visible
- Keyboard navigation works throughout site
- Color contrast meets standards
- Heading hierarchy is semantic (h1 → h2 → h3)
- Skip to content link exists
- ARIA labels on icon buttons
- Forms have proper labels
SEO:
- Page titles are descriptive and unique
- Meta descriptions are compelling (150-160 chars)
- Open Graph tags for social sharing
- Favicon is present
- sitemap.xml exists
- robots.txt is configured
Performance:
- Images lazy load (except above-fold)
- No layout shift (CLS score low)
- First Contentful Paint under 1.5s
- Largest Contentful Paint under 2.5s
- Animations don't cause jank
- Bundle size is optimized
Common Mistakes to Avoid
Design Mistakes:
- Too much color (stick to monochrome + 1 accent max)
- Small text (minimum 16px for body)
- Poor contrast (especially in dark mode)
- Cluttered layouts (embrace whitespace)
- Inconsistent spacing (use 8pt grid)
- Over-animation (subtle is better)
- Generic stock photos (use real project screenshots)
- Unclear navigation (keep it simple)
- No clear CTA (every section should have purpose)
- Trying too many trends at once
Technical Mistakes:
- Unoptimized images (use Next.js Image)
- No loading states (users see blank screens)
- Forgetting mobile users (test on real devices)
- No error handling (forms, API calls)
- Slow page loads (optimize everything)
- No focus states (accessibility fail)
- Broken links (test all links)
- Missing alt text (bad for SEO and a11y)
- Console errors (shows lack of polish)
- No analytics (can't measure success)
Content Mistakes:
- Too much text (be concise)
- No personality (let your voice show)
- Listing every project ever (quality > quantity)
- Generic descriptions ("Built a website...")
- No context for projects (why you built it)
- Outdated tech stack (remove old skills)
- No contact info (how will they reach you?)
- Broken English (if not native, get help)
- No about section (they want to know you)
- Claiming expertise you don't have
Design Inspiration & References
Portfolio Examples:
- Behance.net - Browse portfolios
- Awwwards.com - Award-winning designs
- Dribbble.com - UI/UX inspiration
- SiteInspire.com - Curated web design
Typography Resources:
- Typewolf.com - Font pairing examples
- Fonts.google.com - Free fonts
- Fontsource - NPM fonts for Next.js
Color Tools:
- Coolors.co - Palette generator
- Contrast-ratio.com - Check WCAG compliance
- Realtime Colors - Visualize palettes on UI
This Reference Style:
- Clean, minimal, typography-focused
- Neo-brutalist influence
- Swiss design principles
- Professional yet approachable
When Redesigning an Existing Portfolio
Assessment Questions:
What feels outdated specifically?
- Colors? (Too many colors, outdated palette)
- Typography? (Small text, poor hierarchy)
- Layout? (Cluttered, old grid systems)
- Content? (Outdated projects, old tech stack)
Who is your target audience?
- Recruiters/hiring managers
- Potential clients
- Fellow developers/designers
What's your primary goal?
- Get hired (full-time or freelance)
- Attract clients
- Build personal brand
What do you want to keep?
- Existing branding/logo
- Color scheme
- Specific sections
- Content/copy
Redesign Approach:
Phase 1: Simplify
- Remove unnecessary elements
- Reduce color palette to monochrome
- Improve typography (larger, clearer)
- Increase whitespace
Phase 2: Restructure
- Optimize page flow
- Improve navigation
- Better section hierarchy
- Mobile-first layout
Phase 3: Polish
- Add subtle animations
- Optimize images
- Improve copy
- Test accessibility
Phase 4: Launch
- Test on devices
- Check performance
- Get feedback
- Deploy
Remember: The goal is to showcase your work in the clearest, most professional way possible. Let your projects speak for themselves with minimal interference from the design.