"use client"; import { useCallback, useEffect, useRef, useState } from "react"; import { TypingCursor } from "./typing-cursor"; const wordCloud = [ { text: "Resize", x: 5, y: 14, size: 16, opacity: 0.15 }, { text: "Crop", x: 28, y: 11, size: 14, opacity: 0.12 }, { text: "Optimize", x: 48, y: 12, size: 13, opacity: 0.1 }, { text: "Meme", x: 62, y: 10, size: 12, opacity: 0.08 }, { text: "Rotate", x: 75, y: 14, size: 15, opacity: 0.14 }, { text: "Sharpen", x: 88, y: 11, size: 13, opacity: 0.11 }, { text: "Compress", x: 8, y: 22, size: 15, opacity: 0.13 }, { text: "OCR", x: 25, y: 20, size: 18, opacity: 0.16 }, { text: "Convert", x: 42, y: 18, size: 13, opacity: 0.1 }, { text: "Enhance", x: 82, y: 19, size: 14, opacity: 0.12 }, { text: "Upscale", x: 68, y: 22, size: 16, opacity: 0.15 }, { text: "Watermark", x: 85, y: 26, size: 14, opacity: 0.11 }, { text: "Remove BG", x: 3, y: 32, size: 14, opacity: 0.12 }, { text: "Denoise", x: 18, y: 29, size: 12, opacity: 0.08 }, { text: "Passport", x: 8, y: 38, size: 13, opacity: 0.1 }, { text: "Face Blur", x: 2, y: 48, size: 13, opacity: 0.1 }, { text: "Colorize", x: 85, y: 32, size: 14, opacity: 0.12 }, { text: "Red Eye", x: 78, y: 28, size: 12, opacity: 0.08 }, { text: "Restore", x: 90, y: 42, size: 14, opacity: 0.13 }, { text: "Smart Crop", x: 82, y: 50, size: 13, opacity: 0.1 }, { text: "Collage", x: 3, y: 58, size: 14, opacity: 0.12 }, { text: "QR Code", x: 85, y: 58, size: 14, opacity: 0.11 }, { text: "Erase Object", x: 86, y: 68, size: 13, opacity: 0.1 }, { text: "Border", x: 5, y: 68, size: 13, opacity: 0.1 }, { text: "SVG", x: 3, y: 78, size: 16, opacity: 0.14 }, { text: "Compare", x: 15, y: 73, size: 12, opacity: 0.08 }, { text: "Palette", x: 78, y: 75, size: 13, opacity: 0.1 }, { text: "GIF", x: 90, y: 78, size: 17, opacity: 0.15 }, { text: "Batch", x: 6, y: 88, size: 14, opacity: 0.12 }, { text: "Pipeline", x: 20, y: 90, size: 13, opacity: 0.09 }, { text: "Favicon", x: 35, y: 92, size: 12, opacity: 0.08 }, { text: "PDF", x: 22, y: 82, size: 16, opacity: 0.14 }, { text: "Text Overlay", x: 45, y: 88, size: 12, opacity: 0.07 }, { text: "Base64", x: 82, y: 88, size: 13, opacity: 0.09 }, { text: "Barcode", x: 72, y: 85, size: 12, opacity: 0.08 }, { text: "Metadata", x: 10, y: 95, size: 12, opacity: 0.07 }, { text: "AI Expand", x: 48, y: 95, size: 13, opacity: 0.1 }, { text: "Duplicates", x: 88, y: 95, size: 12, opacity: 0.07 }, { text: "Vectorize", x: 65, y: 92, size: 12, opacity: 0.08 }, { text: "Compose", x: 38, y: 6, size: 12, opacity: 0.08 }, { text: "Split", x: 58, y: 6, size: 12, opacity: 0.08 }, { text: "Enhance Faces", x: 15, y: 44, size: 12, opacity: 0.09 }, { text: "Replace Color", x: 75, y: 64, size: 12, opacity: 0.08 }, { text: "Stitch", x: 18, y: 62, size: 13, opacity: 0.1 }, { text: "Beautify", x: 42, y: 4, size: 12, opacity: 0.07 }, { text: "Closeup", x: 72, y: 6, size: 12, opacity: 0.08 }, ]; function useMouseParallax(strength = 30) { const [offset, setOffset] = useState({ x: 0, y: 0 }); const rafRef = useRef(0); const handleMouseMove = useCallback( (e: MouseEvent) => { cancelAnimationFrame(rafRef.current); rafRef.current = requestAnimationFrame(() => { const cx = window.innerWidth / 2; const cy = window.innerHeight / 2; setOffset({ x: ((e.clientX - cx) / cx) * strength, y: ((e.clientY - cy) / cy) * strength, }); }); }, [strength], ); useEffect(() => { window.addEventListener("mousemove", handleMouseMove); return () => { window.removeEventListener("mousemove", handleMouseMove); cancelAnimationFrame(rafRef.current); }; }, [handleMouseMove]); return offset; } export function Hero() { const mouse = useMouseParallax(25); return (
{/* Gradient mesh background - follows mouse */}
{/* Word cloud background - follows mouse in opposite direction */}
{wordCloud.map((word) => ( {word.text} ))}

50+ image tools.
One Docker container.

Resize, compress, convert, remove backgrounds, upscale, OCR, and more.

Open source. Fully offline. Runs on your network.

Get it for free

No sign-ups. No credit card.

); }