import React, { useState, useEffect, useRef } from 'react'; const EffectGenerator = () => { // State for the app const [startColor, setStartColor] = useState('#ff0000'); const [endColor, setEndColor] = useState('#0000ff'); const [effectType, setEffectType] = useState('expandingCircle'); const [parameter, setParameter] = useState(50); const [frames, setFrames] = useState([]); const [spriteWidth, setSpriteWidth] = useState(100); const [spriteHeight, setSpriteHeight] = useState(100); const [fps, setFps] = useState(12); const [isPlaying, setIsPlaying] = useState(false); const [currentFrameIndex, setCurrentFrameIndex] = useState(0); const previewCanvasRef = useRef(null); const animationRef = useRef(null); // Generate frames whenever inputs change useEffect(() => { generateFrames(); }, [startColor, endColor, effectType, parameter, spriteWidth, spriteHeight]); // Handle animation preview useEffect(() => { if (isPlaying) { const interval = setInterval(() => { setCurrentFrameIndex((prev) => (prev + 1) % 12); }, 1000 / fps); return () => clearInterval(interval); } }, [isPlaying, fps]); // Draw current frame in preview useEffect(() => { if (frames.length > 0 && previewCanvasRef.current) { const ctx = previewCanvasRef.current.getContext('2d'); ctx.clearRect(0, 0, spriteWidth, spriteHeight); const img = new Image(); img.onload = () => { ctx.drawImage(img, 0, 0, spriteWidth, spriteHeight); }; img.src = frames[currentFrameIndex]; } }, [frames, currentFrameIndex, spriteWidth, spriteHeight]); // Interpolate between two colors const interpolateColor = (color1, color2, factor) => { const r1 = parseInt(color1.slice(1, 3), 16); const g1 = parseInt(color1.slice(3, 5), 16); const b1 = parseInt(color1.slice(5, 7), 16); const r2 = parseInt(color2.slice(1, 3), 16); const g2 = parseInt(color2.slice(3, 5), 16); const b2 = parseInt(color2.slice(5, 7), 16); const r = Math.round(r1 + factor * (r2 - r1)); const g = Math.round(g1 + factor * (g2 - g1)); const b = Math.round(b1 + factor * (b2 - b1)); return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`; }; // Draw a circle on canvas const drawCircle = (ctx, x, y, radius, color) => { ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2); ctx.fillStyle = color; ctx.fill(); }; // Draw a star shape on canvas const drawStar = (ctx, x, y, outerRadius, innerRadius, points, color) => { ctx.beginPath(); for (let i = 0; i < points * 2; i++) { const radius = i % 2 === 0 ? outerRadius : innerRadius; const angle = (Math.PI * i) / points; const pointX = x + radius * Math.sin(angle); const pointY = y + radius * Math.cos(angle); if (i === 0) { ctx.moveTo(pointX, pointY); } else { ctx.lineTo(pointX, pointY); } } ctx.closePath(); ctx.fillStyle = color; ctx.fill(); }; // Draw rays/beams from center const drawRays = (ctx, x, y, length, count, width, color) => { const angleStep = (Math.PI * 2) / count; for (let i = 0; i < count; i++) { const angle = i * angleStep; ctx.save(); ctx.translate(x, y); ctx.rotate(angle); ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(length, 0); ctx.lineWidth = width; ctx.strokeStyle = color; ctx.stroke(); ctx.restore(); } }; // Draw a spiral const drawSpiral = (ctx, x, y, radius, turns, thickness, color) => { const angleStep = 0.1; let angle = 0; ctx.beginPath(); ctx.lineWidth = thickness; ctx.strokeStyle = color; for (angle = 0; angle < Math.PI * 2 * turns; angle += angleStep) { const radiusAtAngle = (radius * angle) / (Math.PI * 2 * turns); const pointX = x + radiusAtAngle * Math.cos(angle); const pointY = y + radiusAtAngle * Math.sin(angle); if (angle === 0) { ctx.moveTo(pointX, pointY); } else { ctx.lineTo(pointX, pointY); } } ctx.stroke(); }; // Generate frames const generateFrames = () => { const totalFrames = 12; const newFrames = []; for (let i = 0; i < totalFrames; i++) { const canvas = document.createElement('canvas'); canvas.width = spriteWidth; canvas.height = spriteHeight; const ctx = canvas.getContext('2d'); // Clear canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Calculate interpolation factor const factor = i / (totalFrames - 1); const currentColor = interpolateColor(startColor, endColor, factor); // Center coordinates const centerX = canvas.width / 2; const centerY = canvas.height / 2; // Draw effect based on selected type switch (effectType) { case 'expandingCircle': const radius = (parameter * factor * canvas.width) / 200; drawCircle(ctx, centerX, centerY, radius, currentColor); break; case 'star': const outerRadius = (parameter * factor * canvas.width) / 200; const innerRadius = outerRadius * 0.4; drawStar(ctx, centerX, centerY, outerRadius, innerRadius, 5, currentColor); break; case 'rays': const rayLength = (parameter * factor * canvas.width) / 100; const rayCount = 8; const rayWidth = 3; drawRays(ctx, centerX, centerY, rayLength, rayCount, rayWidth, currentColor); break; case 'spiral': const spiralRadius = (parameter * canvas.width) / 200; const spiralTurns = 2 + factor * 3; const spiralThickness = 2; drawSpiral(ctx, centerX, centerY, spiralRadius, spiralTurns, spiralThickness, currentColor); break; default: drawCircle(ctx, centerX, centerY, 20, currentColor); } // Add frame newFrames.push(canvas.toDataURL()); } setFrames(newFrames); }; // Toggle animation preview const togglePlay = () => { setIsPlaying(!isPlaying); }; // Handle parameter change with validation const handleParameterChange = (e) => { const value = parseInt(e.target.value); if (!isNaN(value) && value >= 1 && value <= 100) { setParameter(value); } }; // Download sprite sheet const downloadSpriteSheet = () => { const canvas = document.createElement('canvas'); canvas.width = spriteWidth * 4; // 4 columns canvas.height = spriteHeight * 3; // 3 rows const ctx = canvas.getContext('2d'); frames.forEach((frameDataURL, index) => { const img = new Image(); img.onload = () => { const row = Math.floor(index / 4); const col = index % 4; ctx.drawImage(img, col * spriteWidth, row * spriteHeight, spriteWidth, spriteHeight); // If this is the last frame, trigger download if (index === frames.length - 1) { const link = document.createElement('a'); link.download = `sprite-sheet-${effectType}.png`; link.href = canvas.toDataURL('image/png'); link.click(); } }; img.src = frameDataURL; }); }; return (