بلا عنوان

Anime Meme Generator | Create Epic Manga Memes
/** * THEME CONFIGURATION — Tailwind v4 */ @theme { /* Anime Color Palette */ --color-primary: #FF2D95; --color-primary-foreground: #FFFFFF; --color-secondary: #00D4FF; --color-secondary-foreground: #0D0D0D; --color-destructive: #FF4757; --color-destructive-foreground: #FFFFFF; --color-muted: #1A1A2E; --color-muted-foreground: #A0A0B0; --color-accent: #9D4EDD; --color-accent-foreground: #FFFFFF; --color-surface: #16162A; --color-surface-foreground: #FFFFFF; --color-border: #2D2D4A; --color-input: #1A1A2E; --color-ring: #FF2D95; --color-neon-pink: #FF2D95; --color-neon-cyan: #00D4FF; --color-neon-purple: #9D4EDD; --color-dark-bg: #0D0D1A; --color-card-bg: #16162A; /* Radius */ --radius-sm: 0.5rem; --radius-md: 0.75rem; --radius-lg: 1rem; --radius-xl: 1.5rem; /* Fonts */ --font-display: 'Bangers', cursive; --font-sans: 'Inter', system-ui, sans-serif; } import { useState, useRef, useEffect, useCallback } from 'react'; import { Download, Upload, Sparkles, Image as ImageIcon, Type, Palette, RefreshCw } from 'lucide-react'; // Import your anime template images import animeShocked from '@/assets/generated/anime-shocked.png'; import animeSmug from '@/assets/generated/anime-smug.png'; import animeCrying from '@/assets/generated/anime-crying.png'; import animeDetermined from '@/assets/generated/anime-determined.png'; import animeConfused from '@/assets/generated/anime-confused.png'; import animeVictory from '@/assets/generated/anime-victory.png'; const templates = [ { id: 'shocked', name: 'Shocked', src: animeShocked }, { id: 'smug', name: 'Smug', src: animeSmug }, { id: 'crying', name: 'Crying', src: animeCrying }, { id: 'determined', name: 'Determined', src: animeDetermined }, { id: 'confused', name: 'Confused', src: animeConfused }, { id: 'victory', name: 'Victory', src: animeVictory }, ]; const textColors = [ { name: 'White', value: '#FFFFFF' }, { name: 'Pink', value: '#FF2D95' }, { name: 'Cyan', value: '#00D4FF' }, { name: 'Yellow', value: '#FFE66D' }, { name: 'Black', value: '#000000' }, ]; export default function Index() { const [selectedTemplate, setSelectedTemplate] = useState(templates[0]); const [customImage, setCustomImage] = useState(null); const [topText, setTopText] = useState('When you realize'); const [bottomText, setBottomText] = useState('The anime was better'); const [fontSize, setFontSize] = useState(32); const [textColor, setTextColor] = useState('#FFFFFF'); const [strokeColor, setStrokeColor] = useState('#000000'); const canvasRef = useRef(null); const fileInputRef = useRef(null); const currentImage = customImage || selectedTemplate.src; const renderMeme = useCallback(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = () => { canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); // Text settings ctx.font = `bold ${fontSize}px Bangers, Impact, sans-serif`; ctx.textAlign = 'center'; ctx.lineWidth = fontSize / 8; ctx.strokeStyle = strokeColor; ctx.fillStyle = textColor; // Draw top text if (topText) { const topLines = wrapText(ctx, topText.toUpperCase(), canvas.width - 40); topLines.forEach((line, i) => { const y = fontSize + 10 + i * (fontSize + 5); ctx.strokeText(line, canvas.width / 2, y); ctx.fillText(line, canvas.width / 2, y); }); } // Draw bottom text if (bottomText) { const bottomLines = wrapText(ctx, bottomText.toUpperCase(), canvas.width - 40); bottomLines.forEach((line, i) => { const y = canvas.height - (bottomLines.length - i - 1) * (fontSize + 5) - 20; ctx.strokeText(line, canvas.width / 2, y); ctx.fillText(line, canvas.width / 2, y); }); } }; img.src = currentImage; }, [currentImage, topText, bottomText, fontSize, textColor, strokeColor]); useEffect(() => { renderMeme(); }, [renderMeme]); const wrapText = (ctx: CanvasRenderingContext2D, text: string, maxWidth: number): string[] => { const words = text.split(' '); const lines: string[] = []; let currentLine = ''; for (const word of words) { const testLine = currentLine + (currentLine ? ' ' : '') + word; const metrics = ctx.measureText(testLine); if (metrics.width > maxWidth && currentLine) { lines.push(currentLine); currentLine = word; } else { currentLine = testLine; } } if (currentLine) lines.push(currentLine); return lines; }; const handleImageUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (event) => { setCustomImage(event.target?.result as string); }; reader.readAsDataURL(file); } }; const downloadMeme = () => { const canvas = canvasRef.current; if (!canvas) return; const link = document.createElement('a'); link.download = 'anime-meme.png'; link.href = canvas.toDataURL('image/png'); link.click(); }; const resetToTemplate = () => { setCustomImage(null); }; return (
{/* Header */}

ANIME{' '} MEME{' '} GENERATOR

Create epic manga memes for your blog in seconds! ⚡

{/* Left Column - Controls */}
{/* Template Selection */}

Choose Template

{templates.map((template) => ( ))}
{/* Upload Custom Image */}
{customImage && ( )}
{/* Text Controls */}

Add Text

setTopText(e.target.value)} placeholder="Enter top text..." className="w-full rounded-lg border border-border bg-input px-4 py-3 text-white placeholder:text-muted-foreground focus:border-neon-pink focus:outline-none focus:ring-1 focus:ring-neon-pink" />
setBottomText(e.target.value)} placeholder="Enter bottom text..." className="w-full rounded-lg border border-border bg-input px-4 py-3 text-white placeholder:text-muted-foreground focus:border-neon-pink focus:outline-none focus:ring-1 focus:ring-neon-pink" />
{/* Style Controls */}

Style

setFontSize(Number(e.target.value))} className="w-full accent-neon-pink" />
{textColors.map((color) => (
{textColors.map((color) => (
{/* Right Column - Preview & Download */}

Preview

Live Preview
{/* Download Button */} {/* Tips */}

💡 Pro Tips for Bloggers

  • • Use short, punchy text for maximum impact
  • • Upload your own screenshots for custom memes
  • • High contrast colors work best for readability
  • • Downloaded memes are saved as PNG for best quality
{/* Footer */}

Made with ❤️ for anime lovers & bloggers

Create • Download • Share • Repeat

); } import { Routes, Route } from 'react-router'; import Index from '@/pages/Index'; export default function App() { return ( } /> ); } import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router'; import App from './App'; import { AppProviders } from './providers'; import './index.css'; createRoot(document.getElementById('root')!).render( , );

إرسال تعليق

أحدث أقدم