Building an AI-Powered Design Tool: A Complete Tutorial
Learn how to build a modern AI design tool with Next.js, TypeScript, and OpenAI API. Complete step-by-step guide with code examples and best practices.
Building an AI-Powered Design Tool: A Complete Tutorial
In this comprehensive tutorial, I'll walk you through building a modern AI-powered design tool from scratch. We'll create a full-stack application that generates logos, color palettes, and design suggestions using artificial intelligence.
Table of Contents
Project Overview
Our AI Design Tool will feature:
- Logo Generation: AI-powered logo creation using text prompts
- Color Palette Generator: Smart color scheme suggestions
- Design Suggestions: AI-driven design tips and trends
- Export Functionality: Download generated designs
- Modern UI: Glassmorphism design with smooth animations
Tech Stack
- Frontend: Next.js 14, TypeScript, TailwindCSS
- AI Integration: OpenAI API (DALL-E, GPT-4)
- Animations: Framer Motion
- Icons: Lucide React
- Styling: Custom CSS with glassmorphism effects
Setting Up the Project
1. Initialize Next.js Project
npx create-next-app@latest ai-design-tool --typescript --tailwind --eslint --app
cd ai-design-tool
2. Install Dependencies
npm install framer-motion openai lucide-react clsx tailwind-merge
3. Configure TailwindCSS
// tailwind.config.js
module.exports = {
content: [
'./src/pages//*.{js,ts,jsx,tsx,mdx}',
'./src/components//*.{js,ts,jsx,tsx,mdx}',
'./src/app//*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
animation: {
'gradient': 'gradient 15s ease infinite',
'float': 'float 6s ease-in-out infinite',
},
keyframes: {
gradient: {
'0%, 100%': {
'background-size': '200% 200%',
'background-position': 'left center'
},
'50%': {
'background-size': '200% 200%',
'background-position': 'right center'
},
},
float: {
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-20px)' },
},
},
},
},
plugins: [],
}
Building the UI Components
1. Main Layout Component
// src/app/layout.tsx
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
const inter = Inter({ subsets: ['latin'] })
export const metadata: Metadata = {
title: 'AI Design Tool - Create Amazing Designs with AI',
description: 'Generate logos, color palettes, and design suggestions using AI.',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
{children}
)
}
2. Logo Generator Component
// src/components/LogoGenerator.tsx
'use client'
import { useState } from 'react'
import { motion } from 'framer-motion'
import { Download, RefreshCw, Sparkles, Copy } from 'lucide-react'
export default function LogoGenerator() {
const [prompt, setPrompt] = useState('')
const [isGenerating, setIsGenerating] = useState(false)
const [generatedLogos, setGeneratedLogos] = useState([])
const generateLogo = async () => {
if (!prompt.trim()) return
setIsGenerating(true)
try {
// In production, this would call OpenAI API
await new Promise(resolve => setTimeout(resolve, 2000))
// Mock generated logos
const mockLogos = [
'https://via.placeholder.com/400x400/6366f1/ffffff?text=Logo+1',
'https://via.placeholder.com/400x400/8b5cf6/ffffff?text=Logo+2',
'https://via.placeholder.com/400x400/06b6d4/ffffff?text=Logo+3',
'https://via.placeholder.com/400x400/10b981/ffffff?text=Logo+4',
]
setGeneratedLogos(mockLogos)
} catch (error) {
console.error('Error generating logo:', error)
} finally {
setIsGenerating(false)
}
}
return (
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="glass-morphism p-8 rounded-2xl"
>
AI Logo Generator
type="text"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="e.g., Modern tech company logo with geometric shapes"
className="w-full px-4 py-3 rounded-lg bg-white/10 border border-white/20 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-purple-500"
/>
onClick={generateLogo}
disabled={!prompt.trim() || isGenerating}
className="w-full bg-gradient-to-r from-purple-600 to-pink-600 text-white py-3 px-6 rounded-lg font-medium hover:from-purple-700 hover:to-pink-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300 flex items-center justify-center gap-2"
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
{isGenerating ? (
<>
Generating...
>
) : (
<>
Generate Logo
>
)}
{/ Generated Logos Display /}
{generatedLogos.length > 0 && (
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="space-y-6"
>
Generated Logos ({generatedLogos.length})
{generatedLogos.map((logo, index) => (
key={index}
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: index * 0.1 }}
className="glass-morphism p-6 rounded-2xl card-hover"
>
src={logo}
alt={Generated logo ${index + 1}}
className="w-full h-full object-cover"
/>
))}
)}
)
}
Integrating AI APIs
1. OpenAI API Integration
// src/lib/openai.ts
import OpenAI from 'openai'
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
})
export async function generateLogo(prompt: string) {
try {
const response = await openai.images.generate({
model: "dall-e-3",
prompt: Create a professional logo: ${prompt},
n: 4,
size: "1024x1024",
quality: "standard",
})
return response.data.map(img => img.url).filter(Boolean)
} catch (error) {
console.error('Error generating logo:', error)
throw new Error('Failed to generate logo')
}
}
export async function generateColorPalette(mood: string) {
try {
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [
{
role: "system",
content: "You are a color theory expert. Generate 5 complementary colors for the given mood or style. Return only hex codes separated by commas."
},
{
role: "user",
content: Generate a color palette for: ${mood}
}
],
max_tokens: 100,
})
const colors = response.choices[0].message.content?.split(',').map(c => c.trim()) || []
return colors
} catch (error) {
console.error('Error generating color palette:', error)
throw new Error('Failed to generate color palette')
}
}
2. API Route for Logo Generation
// src/app/api/generate-logo/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { generateLogo } from '@/lib/openai'
export async function POST(request: NextRequest) {
try {
const { prompt } = await request.json()
if (!prompt) {
return NextResponse.json(
{ error: 'Prompt is required' },
{ status: 400 }
)
}
const logos = await generateLogo(prompt)
return NextResponse.json({ logos })
} catch (error) {
console.error('Error in generate-logo API:', error)
return NextResponse.json(
{ error: 'Failed to generate logo' },
{ status: 500 }
)
}
}
Adding Advanced Features
1. Color Palette Generator
// src/components/ColorPaletteGenerator.tsx
export default function ColorPaletteGenerator() {
const [mood, setMood] = useState('')
const [isGenerating, setIsGenerating] = useState(false)
const [generatedPalettes, setGeneratedPalettes] = useState id: string
colors: string[]
name: string
}>>([])
const generatePalette = async () => {
if (!mood.trim()) return
setIsGenerating(true)
try {
const response = await fetch('/api/generate-colors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ mood })
})
const data = await response.json()
setGeneratedPalettes(data.palettes)
} catch (error) {
console.error('Error generating palette:', error)
} finally {
setIsGenerating(false)
}
}
const copyColor = (color: string) => {
navigator.clipboard.writeText(color)
}
return (
{/ Input and generation logic /}
{/ Component implementation /}
)
}
2. Design Suggestions Component
// src/components/DesignSuggestions.tsx
export default function DesignSuggestions() {
const [selectedCategory, setSelectedCategory] = useState('trends')
const [suggestions, setSuggestions] = useState([])
const categories = [
{ id: 'trends', label: 'Design Trends', icon: TrendingUp },
{ id: 'colors', label: 'Color Theory', icon: Palette },
{ id: 'typography', label: 'Typography', icon: Type },
{ id: 'layout', label: 'Layout Tips', icon: Layout },
]
const generateSuggestions = async (category: string) => {
setSelectedCategory(category)
try {
const response = await fetch('/api/design-suggestions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ category })
})
const data = await response.json()
setSuggestions(data.suggestions)
} catch (error) {
console.error('Error generating suggestions:', error)
}
}
return (
{/ Category selection and suggestions display /}
)
}
Styling with Glassmorphism
/ src/app/globals.css /
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.gradient-bg {
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
background-size: 400% 400%;
animation: gradient 15s ease infinite;
}
.glass-morphism {
@apply bg-white/10 backdrop-blur-md border border-white/20;
}
.card-hover {
@apply transition-all duration-300 hover:scale-105 hover:shadow-xl;
}
}
@keyframes gradient {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
Deployment
1. Environment Variables
.env.local
OPENAI_API_KEY=your_openai_api_key_here
NEXT_PUBLIC_APP_URL=https://your-domain.com
2. Vercel Deployment
Install Vercel CLI
npm i -g vercel
Deploy
vercel --prod
3. Vercel Configuration
// vercel.json
{
"functions": {
"src/app/api//*.ts": {
"maxDuration": 30
}
},
"env": {
"OPENAI_API_KEY": "@openai_api_key"
}
}
Best Practices
1. Error Handling
Always implement proper error handling for API calls:
try {
const response = await fetch('/api/generate-logo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt })
})
if (!response.ok) {
throw new Error('Failed to generate logo')
}
const data = await response.json()
return data
} catch (error) {
console.error('Error:', error)
throw error
}
2. Loading States
Implement loading states for better UX:
const [isGenerating, setIsGenerating] = useState(false)// In your component
{isGenerating ? (
Generating...
) : (
)}
3. Type Safety
Use TypeScript interfaces for better type safety:
interface GeneratedLogo {
id: string
url: string
prompt: string
createdAt: Date
}
interface ColorPalette {
id: string
name: string
colors: string[]
mood: string
}
Performance Optimization
1. Image Optimization
import Image from 'next/image' src={logo.url}
alt="Generated logo"
width={400}
height={400}
className="object-cover"
priority={index < 2} // Prioritize first two images
/>
2. Code Splitting
import dynamic from 'next/dynamic'const LogoGenerator = dynamic(() => import('./LogoGenerator'), {
loading: () =>
Loading...
})
Conclusion
Building an AI-powered design tool is an excellent way to showcase modern web development skills. This tutorial covered:
- Setting up a Next.js project with TypeScript
- Creating reusable UI components
- Integrating AI APIs (OpenAI)
- Implementing glassmorphism design
- Adding animations with Framer Motion
- Deploying to Vercel
The key to success is focusing on user experience, proper error handling, and clean, maintainable code. This project demonstrates skills in:
- Frontend Development: React, Next.js, TypeScript
- AI Integration: OpenAI API, prompt engineering
- UI/UX Design: Modern design patterns, animations
- Full-Stack Development: API routes, database integration
- Deployment: Vercel, environment configuration
Next Steps
To extend this project further, consider adding:
- User authentication and saved designs
- More AI models (Stable Diffusion, Midjourney)
- Advanced export options (SVG, PDF)
- Real-time collaboration features
- Mobile app version
Resources
---
This tutorial is part of my ongoing series on building modern web applications. Follow me for more tutorials and project breakdowns!
GitHub Repository: ai-design-tool
Live Demo: ai-design-tool.vercel.app
About Mayank
Full-stack developer passionate about creating amazing web experiences. I write about modern web technologies, best practices, and my coding journey.
