How to Create City Boy Meme
How to Create City Boy Meme with Next.js 16 & Fabric.js
Ever wondered how to build a web app that goes viral? I recently launched city boy meme – a free, lightning-fast meme maker that’s been creating 2,000+ memes daily. Here’s how I built it and the lessons I learned along the way.
🎯 The Problem
Existing meme generators are slow, bloated with ads, add watermarks, or require signups. I wanted to build something different:
- ⚡ Instant loading – No waiting, no spinners
- 🎨 Full customization – Fonts, colors, text styles
- 💯 Zero friction – No signup, no watermarks, no BS
- 📱 Mobile-first – Works perfectly on all devices
🛠️ Tech Stack
After evaluating several options, I settled on:
"framework": "Next.js 16",
"styling": "Tailwind CSS 4",
"canvas": "Fabric.js 5.3",
"language": "TypeScript",
"deployment": "Vercel"
Why Next.js 16?
Next.js 16 brings some game-changing features:
- App Router – Better performance and SEO
- Server Components – Reduced JavaScript bundle
- Image Optimization – Automatic WebP conversion
- Built-in SEO – Metadata API for perfect SEO
Why Fabric.js?
I initially tried HTML Canvas API directly, but Fabric.js saved me weeks:
- Object-based canvas manipulation
- Built-in text editing and dragging
- Easy export to PNG/JPEG
- Great TypeScript support
🏗️ Architecture Overview
cityboymeme/
├── app/
│ ├── layout.tsx # Root layout with SEO
│ ├── page.tsx # Home page
│ ├── sitemap.ts # Dynamic sitemap
│ └── globals.css # Global styles
├── components/
│ ├── MemeEditor.tsx # Main editor component
│ └── FabricCanvas.tsx # Canvas wrapper
└── public/
├── logo.png # Meme template
└── robots.txt # SEO config
💻 Building the Meme Editor
1. Canvas Component with Fabric.js
The core of the app is a custom canvas component that wraps Fabric.js:
// components/FabricCanvas.tsx
'use client'
import useEffect, useRef, forwardRef, useImperativeHandle from 'react'
import fabric from 'fabric'
export interface TextElement
id: string
text: string
color: string
font: string
style: 'bold'
export interface FabricCanvasRef
addText: (element: TextElement) => void
updateText: (id: string, updates: Partial<TextElement>) => void
removeText: (id: string) => void
exportAsDataURL: () => string
interface Props null) => void
onCanvasReady: () => void
const FabricCanvas = forwardRef<FabricCanvasRef, Props>(
( backgroundImage, width, height, onTextSelect, onCanvasReady , ref) =>
const canvasRef = useRef<HTMLCanvasElement>(null)
const fabricRef = useRef<fabric.Canvas
)
FabricCanvas.displayName = 'FabricCanvas'
export default FabricCanvas
2. Main Editor Component
The editor manages state and provides the UI:
// components/MemeEditor.tsx (simplified)
'use client'
import useState, useRef from 'react'
import FabricCanvas, FabricCanvasRef, TextElement from './FabricCanvas'
export default function MemeEditor()
const [textElements, setTextElements] = useState<TextElement[]>([
id: '1',
text: 'City Boys Be Like',
color: '#FFFFFF',
font: 'Impact',
style: 'outlined',
size: 48
])
const [selectedTextId, setSelectedTextId] = useState<string
🚀 Performance Optimizations
1. Image Optimization
Next.js Image component automatically optimizes images:
import Image from 'next/image'
<Image
src="/logo.png"
alt="City Boy Meme template"
width=600
height=600
priority // Load immediately for LCP
/>
2. Code Splitting
Fabric.js is large (~500KB), so I lazy-load it:
'use client'
import dynamic from 'next/dynamic'
const FabricCanvas = dynamic(() => import('./FabricCanvas'),
ssr: false, // Fabric.js requires window object
loading: () => <div>Loading canvas...</div>
)
3. Lighthouse Score: 95+
After optimizations:
- Performance: 98
- Accessibility: 100
- Best Practices: 100
- SEO: 100
🔍 SEO Strategy
SEO was crucial for organic growth. Here’s what worked:
1. Perfect Metadata
// app/layout.tsx
export const metadata: Metadata =
title: 'City Boy Meme - Free Online Meme Maker',
description: 'Create hilarious City Boy memes instantly with our free online generator. Add custom text, choose fonts and colors. Download high-quality memes. No signup!',
keywords: [
'city boy meme',
'meme generator',
'free meme maker',
'online meme creator',
],
openGraph:
type: 'website',
url: 'https://cityboymeme.com',
title: 'City Boy Meme - Free Online Meme Maker',
description: 'Create viral City Boy memes instantly',
images: ['/logo.png'],
,
2. Structured Data (Schema.org)
// FAQPage Schema for Featured Snippets
const faqSchema =
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: [
'@type': 'Question',
name: 'What is a City Boy Meme?',
acceptedAnswer:
'@type': 'Answer',
text: 'The City Boy Meme is a viral internet format featuring a character with an exaggerated shocked expression...'
,
// More questions...
]
This helped me get Featured Snippets on Google!
3. Dynamic Sitemap
// app/sitemap.ts
import MetadataRoute from 'next'
export default function sitemap(): MetadataRoute.Sitemap
return [
url: 'https://cityboymeme.com',
lastModified: new Date(),
changeFrequency: 'daily',
priority: 1,
,
url: 'https://cityboymeme.com/what-is-city-boy-meme',
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.9,
,
]
📊 Results After 2 Weeks
The results exceeded my expectations:
- 📈 2,000+ memes created daily
- 🔍 Ranking #3 for “city boy meme” on Google
- ⚡ Page load time: <1 second
- 📱 Mobile traffic: 65%
- 💯 Zero complaints about performance
🎓 Lessons Learned
1. Start with SEO from Day 1
Don’t treat SEO as an afterthought. I spent 30% of development time on SEO, and it paid off massively.
2. Mobile-First is Non-Negotiable
65% of my users are on mobile. The app works perfectly on phones because I designed for mobile first.
3. Performance = User Retention
Users expect instant loading. Every 100ms delay costs you users. Optimize ruthlessly.
4. Fabric.js > Raw Canvas
I initially tried raw Canvas API. Switching to Fabric.js saved me 2 weeks and resulted in better UX.
5. TypeScript Saves Time
TypeScript caught dozens of bugs before they reached production. The upfront cost is worth it.
🔮 What’s Next?
I’m planning to add:
- 🎨 More meme templates
- 📤 Direct social media sharing
- 🎥 GIF/Video meme support
- 🌍 Internationalization (i18n)
- 🤖 AI-powered text suggestions
💡 Key Takeaways
If you’re building a viral web app:
- Choose the right tools – Next.js 16 + Fabric.js was perfect for this
- Optimize for performance – Users expect instant loading
- SEO from day 1 – Organic traffic is the best traffic
- Mobile-first design – Most users are on mobile
- Keep it simple – No signup, no friction, just value
🔗 Links
🙏 Thanks for Reading!
If you found this helpful, please:
- ⭐ Star the repo on GitHub
- 💬 Leave a comment with your questions
- 🔄 Share with your network
- 🚀 Try building your own viral app!
What would you build with Next.js 16 and Fabric.js? Drop your ideas in the comments! 👇
📚 Resources
Built with ❤️ using Next.js 16, Fabric.js, and lots of coffee ☕
