Image Handling Guide¶
Navigation: Documentation Home > Content Management > Image Handling
Table of Contents¶
- Introduction
- Directory Structure
- Image Formats
- Image Optimization
- Naming Conventions
- Path Formats
- Alt Text Guidelines
- Responsive Images
- Image Processing Tools
- Best Practices
- Common Issues
- Performance Optimization
- See Also
- Next Steps
Introduction¶
Proper image handling is crucial for portfolio performance and user experience. This guide covers organization, optimization, and best practices for all images in the portfolio.
Image Categories¶
- Project Images: Screenshots, demos, architecture diagrams
- Project Videos: Demo videos, tutorials
- Achievement Logos: Organization and issuer logos
- Other Assets: Favicons, OG images, profile photos
Key Principles¶
- Optimize First: Always optimize before committing
- Use WebP: Preferred format for web images
- Descriptive Names: Use clear, descriptive filenames
- Proper Paths: Use absolute paths starting with
/images/ - Alt Text: Always provide descriptive alt text
Directory Structure¶
Complete Structure¶
public/images/
├── projects/
│ ├── signapse/
│ │ ├── demo.webp
│ │ ├── stack.webp
│ │ ├── tablet-home-1-2527x1422.webp
│ │ └── video-demo.mp4
│ ├── pop-a-loon/
│ │ ├── small.webp
│ │ ├── screenshot-1.webp
│ │ ├── screenshot-2.webp
│ │ └── screenshot-3.webp
│ └── [other-projects]/
│
├── logos/
│ ├── rotary-international.webp
│ ├── cisco.webp
│ ├── aws.webp
│ └── erasmus-plus.webp
│
└── [other-assets]/
├── favicon.ico
├── og-image.png
└── profile.webp
Project Images¶
Location: public/images/projects/{project-slug}/
Each project has its own directory matching the project slug:
public/images/projects/
├── my-project/ ← Directory name matches slug
│ ├── hero.webp
│ ├── screenshot-1.webp
│ ├── screenshot-2.webp
│ └── demo-video.mp4
Rules:
- Directory name MUST match project slug
- One directory per project
- All project media in same directory
Achievement Logos¶
Location: public/images/logos/
All achievement/organization logos in a single shared directory:
public/images/logos/
├── aws.webp
├── cisco.webp
├── rotary-international.webp
└── google-cloud.webp
Rules:
- Shared directory for all logos
- Use descriptive filenames (organization name)
- kebab-case names preferred
Image Formats¶
Supported Formats¶
| Format | Use Case | Pros | Cons |
|---|---|---|---|
| WebP | General use (recommended) | Best compression, good quality | Older browser support |
| JPEG | Photos | Wide support | Lossy compression, no transparency |
| PNG | Screenshots with transparency | Lossless, transparency | Larger file size |
| SVG | Logos, icons (simple graphics) | Scalable, small | Not for photos |
| GIF | Avoid for new content | Wide support | Poor compression, limited colors |
Format Recommendations¶
Project Screenshots:
- Use WebP (best choice)
- Fallback to PNG if transparency needed
- JPEG for photos without transparency
Achievement Logos:
- Use WebP (best choice)
- SVG for simple logos
- PNG if transparency required
Profile/Hero Images:
- Use WebP
- Provide JPEG fallback for critical images
WebP Benefits¶
Conversion:
# Convert PNG to WebP
cwebp -q 80 input.png -o output.webp
# Batch conversion
for file in *.png; do
cwebp -q 80 "$file" -o "${file%.png}.webp"
done
Image Optimization¶
Before Committing¶
Always optimize images before committing to repository.
Optimization Workflow¶
flowchart LR
A[Source Image] --> B[Resize if Needed]
B --> C[Convert to WebP]
C --> D[Compress]
D --> E[Verify Quality]
E --> F{Quality OK?}
F -->|Yes| G[Add to Repo]
F -->|No| H[Adjust Quality]
H --> C
style A fill:#e3f2fd
style G fill:#c8e6c9
style F fill:#fff9c4
Size Guidelines¶
Max Dimensions:
- Screenshots: 2000px width
- Logos: 400px width
- Hero images: 2400px width
- Thumbnails: 800px width
File Sizes:
- Screenshots: Target < 500KB
- Logos: Target < 100KB
- Videos: Target < 50MB
Optimization Commands¶
Resize Images¶
# Using ImageMagick
convert input.png -resize 2000x output.png
# Maintain aspect ratio
convert input.png -resize 2000x -quality 85 output.png
# Batch resize
mogrify -resize 2000x *.png
Convert to WebP¶
# High quality (q=80)
cwebp -q 80 input.png -o output.webp
# Balanced (q=75)
cwebp -q 75 input.png -o output.webp
# Smaller size (q=70)
cwebp -q 70 input.png -o output.webp
# With progress
cwebp -q 80 -progress input.png -o output.webp
Optimize Existing WebP¶
Optimize PNG¶
# Using optipng
optipng -o7 image.png
# Using pngquant (lossy but better compression)
pngquant --quality=70-85 image.png -o output.png
Optimize JPEG¶
# Using ImageMagick
convert input.jpg -quality 85 -sampling-factor 4:2:0 -strip output.jpg
# Using jpegoptim
jpegoptim --size=500k image.jpg
Naming Conventions¶
Project Images¶
Use descriptive, kebab-case names:
# ✅ Good names
hero.webp
dashboard.webp
user-profile.webp
settings-page.webp
mobile-view.webp
architecture-diagram.webp
demo-video.mp4
# ✅ Good with numbers
screenshot-1.webp
screenshot-2.webp
screenshot-3.webp
# ✅ Good with dimensions (optional)
hero-2400x1350.webp
thumbnail-800x600.webp
# ❌ Bad names
IMG_1234.webp
screen shot 1.webp
Untitled.webp
image.webp
pic.webp
Logo Names¶
Use organization name in kebab-case:
# ✅ Good names
aws.webp
amazon-web-services.webp
cisco.webp
rotary-international.webp
google-cloud.webp
microsoft.webp
# ❌ Bad names
logo1.webp
org-logo.webp
badge.webp
cert.webp
General Rules¶
- Lowercase: All lowercase letters
- Hyphens: Use hyphens for spaces
- No Spaces: Never use spaces
- Descriptive: Name describes content
- No Special Chars: Avoid except hyphens and dots
- Extension: Include proper extension
Path Formats¶
Absolute Paths¶
Always use absolute paths starting with /images/:
// ✅ Correct - absolute path
{
"src": "/images/projects/my-project/screenshot.webp"
}
// ❌ Wrong - relative path
{
"src": "screenshot.webp"
}
// ❌ Wrong - includes 'public'
{
"src": "/public/images/projects/my-project/screenshot.webp"
}
// ❌ Wrong - relative with ./
{
"src": "./images/projects/my-project/screenshot.webp"
}
Path Structure¶
/images/{category}/{subcategory}/{filename}
Examples:
/images/projects/signapse/demo.webp
/images/logos/aws.webp
Path Validation¶
# Check all project image paths
jq -r '.images[].src' content/projects/*.json | sort -u
# Verify paths start with /images/
jq -r '.images[].src' content/projects/*.json | grep -v '^/images/'
# Should return nothing
# Check for common mistakes
jq -r '.images[].src' content/projects/*.json | grep -E '(public|\.\.|\./)'
# Should return nothing
Alt Text Guidelines¶
Purpose of Alt Text¶
Alt text serves multiple purposes:
- Accessibility: Screen readers for visually impaired users
- SEO: Search engines index alt text
- Fallback: Displayed if image fails to load
Writing Good Alt Text¶
Rules:
- Be descriptive and specific
- Describe what's visible and important
- Include context relevant to the content
- Keep concise (typically < 125 characters)
- Don't start with "image of" or "picture of"
- Don't repeat nearby text
Examples¶
Project Screenshots¶
// ✅ Good - specific and descriptive
{
"alt": "Task Manager dashboard showing active tasks, team members, and progress charts"
}
// ✅ Good - describes key elements
{
"alt": "User profile page with editable bio, profile picture, and activity history"
}
// ✅ Good - technical diagram
{
"alt": "System architecture diagram showing React frontend, Node.js backend, and PostgreSQL database"
}
// ❌ Bad - too generic
{
"alt": "Screenshot"
}
// ❌ Bad - redundant
{
"alt": "Picture of the Task Manager application"
}
// ❌ Bad - too vague
{
"alt": "Application interface"
}
Achievement Logos¶
// ✅ Good - logo description
{
"alt": "AWS certification badge - orange smile arrow on dark blue background"
}
// ✅ Good - simple org name
{
"alt": "Cisco Networking Academy logo"
}
// ✅ Good - descriptive
{
"alt": "Rotary International logo - gold wheel with 24 cogs"
}
// ❌ Bad - too simple
{
"alt": "Logo"
}
// ❌ Bad - not descriptive
{
"alt": "Organization badge"
}
Alt Text Templates¶
Screenshots:
"{Page/Feature name} {showing/displaying} {key elements}"
Examples:
"Dashboard showing user analytics and recent activity"
"Settings page displaying notification preferences and account options"
"Mobile app home screen with navigation menu and featured content"
Diagrams:
"{Diagram type} {showing} {components and relationships}"
Examples:
"Architecture diagram showing microservices connected via API gateway"
"Data flow diagram from user input through processing to database storage"
"Network topology showing routers, switches, and end devices"
Logos:
"{Organization name} logo - {visual description}"
Examples:
"Google Cloud logo - multicolored cloud icon"
"AWS logo - orange smile arrow on dark background"
"Microsoft logo - four colored squares"
Responsive Images¶
Next.js Image Component¶
The portfolio uses Next.js <Image> component which handles:
- Automatic optimization
- Responsive sizes
- Lazy loading
- Format selection (WebP when supported)
Usage in Components:
import Image from "next/image";
<Image
src={project.images[0].src}
alt={project.images[0].alt}
width={1200}
height={800}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
priority={false}
/>;
Sizes Attribute¶
Define which image sizes to load at different breakpoints:
// Full width on mobile, 50% on tablet, 33% on desktop
sizes = "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw";
// Fixed size
sizes = "800px";
// Common patterns
sizes = "100vw"; // Always full width
sizes = "(max-width: 640px) 100vw, 800px"; // Full width on mobile, fixed on desktop
Image Processing Tools¶
Command Line Tools¶
cwebp (WebP Conversion)¶
# Install (macOS)
brew install webp
# Install (Ubuntu/Debian)
sudo apt install webp
# Basic usage
cwebp -q 80 input.png -o output.webp
# Options
cwebp -q 75 -m 6 -af -progress input.png -o output.webp
# -q: quality (0-100)
# -m: compression method (0-6, 6 is slowest/best)
# -af: auto-adjust filter strength
# -progress: show progress
ImageMagick¶
# Install (macOS)
brew install imagemagick
# Install (Ubuntu/Debian)
sudo apt install imagemagick
# Resize
convert input.png -resize 2000x output.png
# Convert format
convert input.png output.webp
# Compress JPEG
convert input.jpg -quality 85 output.jpg
# Batch process
mogrify -resize 2000x -quality 85 *.png
optipng (PNG Optimization)¶
# Install
brew install optipng # macOS
sudo apt install optipng # Ubuntu/Debian
# Optimize
optipng -o7 image.png
# Batch optimize
optipng -o7 *.png
Online Tools¶
For Occasional Use:
- Squoosh - Google's image optimizer
- TinyPNG - PNG and JPEG compression
- Compressor.io - Multi-format compression
- WebP Converter - Format conversion
Automated Optimization¶
Git Pre-Commit Hook (optional):
# .husky/pre-commit
#!/bin/sh
# Optimize images before commit
for file in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(png|jpg|jpeg)$'); do
if [ -f "$file" ]; then
echo "Optimizing $file..."
cwebp -q 80 "$file" -o "${file%.*}.webp"
git add "${file%.*}.webp"
fi
done
Best Practices¶
1. Optimize Before Commit¶
# Never commit unoptimized images
# Always run optimization first
# Before
ls -lh screenshot.png
# 2.5M screenshot.png
# Optimize
cwebp -q 80 screenshot.png -o screenshot.webp
# After
ls -lh screenshot.webp
# 450K screenshot.webp
# Commit optimized version
git add screenshot.webp
2. Use Descriptive Names¶
# ✅ Good
dashboard-with-analytics.webp
user-profile-mobile-view.webp
architecture-diagram-v2.webp
# ❌ Bad
IMG_1234.webp
untitled.webp
screen1.webp
3. Consistent Dimensions¶
Keep similar images at similar dimensions:
# Project screenshots
screenshot-1.webp # 2000x1250
screenshot-2.webp # 2000x1400
screenshot-3.webp # 2000x1100
# All approximately 2000px wide
4. Version Control¶
Don't commit:
- Original unoptimized images
- Multiple versions of same image
- Temporary/test images
# .gitignore
*.psd # Photoshop files
*.ai # Illustrator files
*-original.* # Original versions
*-temp.* # Temporary files
5. Alt Text Standards¶
Create alt text before adding image:
// Plan alt text while creating image
{
"src": "/images/projects/my-app/dashboard.webp",
"alt": "Dashboard displaying real-time metrics, user activity, and system alerts"
}
6. Check Image Load¶
Always test images load correctly:
# Start dev server
npm run dev
# Check browser console for errors
# Check Network tab for 404s
# Verify images display correctly
Common Issues¶
Issue 1: Image Not Loading¶
Symptoms: Broken image icon
Causes:
- Incorrect path
- File doesn't exist
- Wrong directory
Solutions:
# Check file exists
ls -la public/images/projects/my-project/screenshot.webp
# Verify path in JSON
jq '.images[0].src' content/projects/my-project.json
# Check path format
# Should be: /images/projects/my-project/screenshot.webp
Issue 2: Image Too Large¶
Symptoms: Slow page load, large file size
Causes:
- Unoptimized image
- Too high resolution
- Wrong format
Solutions:
# Check file size
ls -lh public/images/projects/my-project/screenshot.webp
# If > 1MB, optimize
cwebp -q 70 input.webp -o output.webp
# If > 2000px wide, resize
convert input.webp -resize 2000x output.webp
Issue 3: Poor Image Quality¶
Symptoms: Blurry, pixelated, or artifact-heavy images
Causes:
- Too much compression
- Quality setting too low
- Scaled up from small source
Solutions:
# Increase quality setting
cwebp -q 85 input.png -o output.webp # Higher quality
# Use better source image
# Start with high-resolution original
# Try lossless
cwebp -lossless input.png -o output.webp
Issue 4: Wrong Image Dimensions¶
Symptoms: Image appears stretched or cropped
Causes:
- Aspect ratio mismatch
- Incorrect width/height props
- CSS conflicts
Solutions:
# Check image dimensions
identify image.webp
# Output: image.webp WEBP 2000x1250
# Verify aspect ratio matches container
# 2000x1250 = 1.6:1 aspect ratio
Performance Optimization¶
Image Optimization Checklist¶
- [ ] Format: Use WebP when possible
- [ ] Size: Under 500KB for screenshots
- [ ] Dimensions: Max 2000px width
- [ ] Compression: Quality 75-85
- [ ] Alt text: Descriptive and concise
- [ ] Path: Absolute path starting with
/images/ - [ ] Loading: Lazy load non-critical images
Next.js Optimization¶
Next.js <Image> component provides:
- Automatic format selection
- Responsive image sizes
- Lazy loading
- Blur placeholder
- Priority loading for above-fold images
Component usage:
<Image
src="/images/projects/my-app/hero.webp"
alt="Application hero image"
width={1200}
height={800}
priority={true} // Load immediately (above fold)
placeholder="blur" // Show blur while loading
/>
Lazy Loading¶
All images lazy load by default except:
- Images with
priority={true} - Images above the fold
// Lazy load (default)
<Image src="..." alt="..." width={800} height={600} />
// Priority load (above fold)
<Image src="..." alt="..." width={800} height={600} priority />
Performance Metrics¶
Target metrics:
- Largest Contentful Paint (LCP): < 2.5s
- Cumulative Layout Shift (CLS): < 0.1
- First Input Delay (FID): < 100ms
Images impact LCP and CLS most significantly.
See Also¶
- Adding Projects Guide - How to add project images
- Adding Achievements Guide - How to add logos
- Video Support Guide - Video handling
- JSON Schema Reference - Image field structure
Next Steps¶
- Install Tools: Set up cwebp and ImageMagick
- Optimize Existing: Review and optimize current images
- Create Guidelines: Document project-specific image standards
- Automate: Set up pre-commit hooks for automatic optimization
- Monitor: Check performance metrics regularly
Last Updated: February 2026
Maintainer: Development Team
Related Tools: cwebp, ImageMagick, Next.js Image component