piclets / sample_animations.html
Fraser's picture
better battle
94e4b64
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pokemon Sprite Expression Animator</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
padding: 30px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
color: #333;
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}
.subtitle {
text-align: center;
color: #666;
margin-bottom: 30px;
font-size: 1.1em;
}
.upload-section {
background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
padding: 25px;
border-radius: 15px;
margin-bottom: 30px;
text-align: center;
border: 3px dashed #ff6b35;
}
.file-input {
margin: 15px 0;
}
.file-input input[type="file"] {
display: none;
}
.file-label {
display: inline-block;
padding: 12px 25px;
background: #ff6b35;
color: white;
border-radius: 25px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: bold;
}
.file-label:hover {
background: #e55a2b;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(229, 90, 43, 0.3);
}
.animation-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 25px;
margin-top: 30px;
}
.animation-card {
background: white;
border-radius: 15px;
padding: 20px;
text-align: center;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
border: 2px solid transparent;
}
.animation-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15);
border-color: #667eea;
}
.animation-title {
font-size: 1.2em;
color: #333;
margin-bottom: 15px;
font-weight: bold;
}
.sprite-container {
width: 120px;
height: 120px;
margin: 0 auto 20px;
background: #f0f0f0;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
overflow: visible;
border: 2px solid #ddd;
position: relative;
}
.sprite {
max-width: 100%;
max-height: 100%;
image-rendering: pixelated;
}
.demo-sprite {
width: 80px;
height: 80px;
background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
border-radius: 50%;
position: relative;
}
.demo-sprite::before {
content: '🎮';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 2em;
}
.apply-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 10px 20px;
border-radius: 25px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s ease;
width: 100%;
}
.apply-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
}
.apply-btn:disabled {
background: #ccc;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
/* Animation Classes */
.idle-bounce {
animation: idleBounce 2s ease-in-out infinite;
}
.happy-bounce {
animation: happyBounce 0.6s ease-in-out infinite;
}
.excited-shake {
animation: excitedShake 0.5s ease-in-out infinite;
}
.sad-droop {
animation: sadDroop 3s ease-in-out infinite;
}
.angry-shake {
animation: angryShake 0.3s ease-in-out infinite;
}
.confused-tilt {
animation: confusedTilt 2s ease-in-out infinite;
}
.sleepy-sway {
animation: sleepySway 4s ease-in-out infinite;
}
.alert-pulse {
animation: alertPulse 1s ease-in-out infinite;
}
.hurt-flash {
animation: hurtFlash 0.8s ease-in-out infinite;
}
.victory-spin {
animation: victorySpin 1.5s ease-in-out infinite;
}
.charging-glow {
animation: chargingGlow 1.2s ease-in-out infinite;
}
.dizzy-wobble {
animation: dizzyWobble 1s ease-in-out infinite;
}
.attack-lunge {
animation: attackLunge 1.5s ease-in-out infinite;
}
.defend-crouch {
animation: defendCrouch 2s ease-in-out infinite;
}
.love-hearts {
animation: loveHearts 2s ease-in-out infinite;
}
.fear-tremble {
animation: fearTremble 0.4s ease-in-out infinite;
}
.evolving-glow {
animation: evolvingGlow 2s ease-in-out infinite;
}
.fainting-fall {
animation: faintingFall 3s ease-in-out infinite;
}
.turn-left {
animation: turnLeft 2s ease-in-out infinite;
}
.turn-right {
animation: turnRight 2s ease-in-out infinite;
}
.look-around {
animation: lookAround 4s ease-in-out infinite;
}
.confetti-effect {
animation: confettiSpin 2s ease-in-out infinite;
}
.hearts-float {
animation: heartsFloat 3s ease-in-out infinite;
}
.lightning-strike {
animation: lightningStrike 1.5s ease-in-out infinite;
}
.sparkle-magic {
animation: sparkleMagic 2s ease-in-out infinite;
}
.fire-burst {
animation: fireBurst 1.8s ease-in-out infinite;
}
.ice-crystals {
animation: iceCrystals 2.5s ease-in-out infinite;
}
.poison-bubbles {
animation: poisonBubbles 3s ease-in-out infinite;
}
.healing-aura {
animation: healingAura 2.8s ease-in-out infinite;
}
/* Particle Systems */
.particles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: visible;
}
.particle {
position: absolute;
border-radius: 50%;
}
.confetti-particle {
width: 6px;
height: 6px;
animation: confettifall 2s linear infinite;
}
.heart-particle {
width: 12px;
height: 12px;
animation: heartFloat 3s ease-in-out infinite;
color: #ff69b4;
}
.heart-particle::before {
content: '💖';
font-size: 12px;
}
.lightning-particle {
width: 2px;
height: 20px;
background: linear-gradient(to bottom, #ffff00, #4169e1);
animation: lightningFlash 0.3s ease-in-out infinite;
border-radius: 1px;
}
.sparkle-particle {
width: 4px;
height: 4px;
background: #ffd700;
animation: sparkleShine 1.5s ease-in-out infinite;
box-shadow: 0 0 6px #ffd700;
}
.fire-particle {
width: 8px;
height: 8px;
background: radial-gradient(circle, #ff4500, #ff8c00);
animation: fireRise 1.8s ease-out infinite;
}
.ice-particle {
width: 6px;
height: 6px;
background: linear-gradient(45deg, #00bfff, #87ceeb);
animation: iceFall 2.5s linear infinite;
transform: rotate(45deg);
}
.poison-particle {
width: 10px;
height: 10px;
background: radial-gradient(circle, #9932cc, #8b008b);
animation: poisonBubble 3s ease-in-out infinite;
}
.heal-particle {
width: 5px;
height: 5px;
background: radial-gradient(circle, #32cd32, #90ee90);
animation: healFloat 2.8s ease-in-out infinite;
box-shadow: 0 0 8px #32cd32;
}
/* Keyframes */
@keyframes idleBounce {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-8px); }
}
@keyframes happyBounce {
0%, 100% { transform: translateY(0px) scale(1); }
50% { transform: translateY(-15px) scale(1.1); }
}
@keyframes excitedShake {
0%, 100% { transform: translateX(0px); }
25% { transform: translateX(-5px) rotate(-2deg); }
75% { transform: translateX(5px) rotate(2deg); }
}
@keyframes sadDroop {
0%, 100% { transform: translateY(0px) scaleY(1); }
50% { transform: translateY(10px) scaleY(0.9); }
}
@keyframes angryShake {
0%, 100% { transform: translateX(0px); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-3px); }
20%, 40%, 60%, 80% { transform: translateX(3px); }
}
@keyframes confusedTilt {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(-10deg); }
75% { transform: rotate(10deg); }
}
@keyframes sleepySway {
0%, 100% { transform: rotate(0deg) translateY(0px); }
25% { transform: rotate(-5deg) translateY(5px); }
75% { transform: rotate(5deg) translateY(5px); }
}
@keyframes alertPulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.15); }
}
@keyframes hurtFlash {
0%, 100% { opacity: 1; filter: brightness(1); }
50% { opacity: 0.7; filter: brightness(1.5) hue-rotate(0deg); }
}
@keyframes victorySpin {
0% { transform: rotate(0deg) scale(1); }
50% { transform: rotate(180deg) scale(1.2); }
100% { transform: rotate(360deg) scale(1); }
}
@keyframes chargingGlow {
0%, 100% { filter: brightness(1) saturate(1); transform: scale(1); }
50% { filter: brightness(1.3) saturate(1.5); transform: scale(1.05); }
}
@keyframes dizzyWobble {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(-15deg) translateX(-5px); }
50% { transform: rotate(0deg) translateX(0px); }
75% { transform: rotate(15deg) translateX(5px); }
}
@keyframes attackLunge {
0%, 100% { transform: translateX(0px) scaleX(1); }
30% { transform: translateX(-10px) scaleX(0.9); }
60% { transform: translateX(15px) scaleX(1.1); }
}
@keyframes defendCrouch {
0%, 100% { transform: scaleY(1) translateY(0px); }
50% { transform: scaleY(0.8) translateY(10px); }
}
@keyframes loveHearts {
0%, 100% { transform: scale(1); filter: hue-rotate(0deg); }
50% { transform: scale(1.1); filter: hue-rotate(20deg); }
}
@keyframes fearTremble {
0%, 100% { transform: translateX(0px) translateY(0px); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-2px) translateY(-1px); }
20%, 40%, 60%, 80% { transform: translateX(2px) translateY(1px); }
}
@keyframes evolvingGlow {
0%, 100% {
filter: brightness(1) contrast(1);
transform: scale(1);
}
50% {
filter: brightness(1.5) contrast(1.2);
transform: scale(1.1);
}
}
@keyframes faintingFall {
0%, 70% { transform: rotate(0deg) translateY(0px); opacity: 1; }
100% { transform: rotate(90deg) translateY(20px); opacity: 0.3; }
}
/* New Turning Animations */
@keyframes turnLeft {
0%, 100% { transform: scaleX(1); }
50% { transform: scaleX(-1); }
}
@keyframes turnRight {
0%, 100% { transform: scaleX(-1); }
50% { transform: scaleX(1); }
}
@keyframes lookAround {
0%, 100% { transform: scaleX(1); }
25% { transform: scaleX(-1); }
50% { transform: scaleX(1); }
75% { transform: scaleX(-1); }
}
/* Particle Effect Animations */
@keyframes confettiSpin {
0%, 100% { transform: translateY(0px) rotate(0deg) scale(1); }
50% { transform: translateY(-10px) rotate(180deg) scale(1.1); }
}
@keyframes heartsFloat {
0%, 100% { transform: translateY(0px) scale(1); }
50% { transform: translateY(-8px) scale(1.05); }
}
@keyframes lightningStrike {
0%, 90%, 100% { filter: brightness(1) contrast(1); }
10%, 20%, 30% { filter: brightness(2) contrast(1.5) hue-rotate(60deg); }
}
@keyframes sparkleMagic {
0%, 100% { transform: rotate(0deg) scale(1); filter: brightness(1); }
50% { transform: rotate(180deg) scale(1.1); filter: brightness(1.3); }
}
@keyframes fireBurst {
0%, 100% { transform: scale(1); filter: hue-rotate(0deg) brightness(1); }
50% { transform: scale(1.1); filter: hue-rotate(30deg) brightness(1.2); }
}
@keyframes iceCrystals {
0%, 100% { transform: rotate(0deg) scale(1); filter: brightness(1) saturate(1); }
50% { transform: rotate(180deg) scale(1.05); filter: brightness(1.2) saturate(1.3); }
}
@keyframes poisonBubbles {
0%, 100% { transform: translateY(0px) scale(1); filter: hue-rotate(0deg); }
50% { transform: translateY(-5px) scale(1.03); filter: hue-rotate(30deg); }
}
@keyframes healingAura {
0%, 100% { transform: scale(1); filter: brightness(1) saturate(1); }
50% { transform: scale(1.05); filter: brightness(1.2) saturate(1.4); }
}
/* Particle Keyframes */
@keyframes confettifall {
0% {
transform: translateY(-20px) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(140px) rotate(360deg);
opacity: 0;
}
}
@keyframes heartFloat {
0% {
transform: translateY(20px) scale(0.5);
opacity: 0;
}
50% {
opacity: 1;
transform: translateY(-10px) scale(1);
}
100% {
transform: translateY(-40px) scale(0.8);
opacity: 0;
}
}
@keyframes lightningFlash {
0%, 100% { opacity: 0; }
50% { opacity: 1; }
}
@keyframes sparkleShine {
0%, 100% {
transform: scale(0.5) rotate(0deg);
opacity: 0.5;
}
50% {
transform: scale(1.2) rotate(180deg);
opacity: 1;
}
}
@keyframes fireRise {
0% {
transform: translateY(20px) scale(1);
opacity: 1;
}
100% {
transform: translateY(-30px) scale(0.3);
opacity: 0;
}
}
@keyframes iceFall {
0% {
transform: translateY(-20px) rotate(45deg) scale(1);
opacity: 1;
}
100% {
transform: translateY(140px) rotate(405deg) scale(0.5);
opacity: 0;
}
}
@keyframes poisonBubble {
0% {
transform: translateY(20px) scale(0.5);
opacity: 0.7;
}
50% {
transform: translateY(0px) scale(1);
opacity: 1;
}
100% {
transform: translateY(-20px) scale(0.3);
opacity: 0;
}
}
@keyframes healFloat {
0% {
transform: translateY(10px) scale(0.5);
opacity: 0.5;
}
50% {
transform: translateY(-5px) scale(1);
opacity: 1;
}
100% {
transform: translateY(-20px) scale(0.7);
opacity: 0;
}
}
.description {
font-size: 0.9em;
color: #666;
margin-bottom: 15px;
line-height: 1.4;
}
.controls {
display: flex;
gap: 10px;
margin-top: 15px;
}
.speed-control {
flex: 1;
}
.speed-control select {
width: 100%;
padding: 5px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>🎮 Pokemon Sprite Expression Animator</h1>
<p class="subtitle">Upload your sprite and test various Pokemon-style animations</p>
<div class="upload-section">
<h3>Upload Your Sprite</h3>
<div class="file-input">
<label for="sprite-upload" class="file-label">Choose Sprite Image</label>
<input type="file" id="sprite-upload" accept="image/*">
</div>
<p>Supports PNG, JPG, GIF - Best results with square sprites (64x64 to 256x256px)</p>
</div>
<div class="animation-grid" id="animationGrid">
<!-- Animations will be populated by JavaScript -->
</div>
</div>
<script>
const animations = [
{
name: 'Idle Bounce',
class: 'idle-bounce',
description: 'Gentle up-down bounce for idle state'
},
{
name: 'Happy Bounce',
class: 'happy-bounce',
description: 'Excited bouncing with slight scaling'
},
{
name: 'Excited Shake',
class: 'excited-shake',
description: 'Side-to-side shake with rotation'
},
{
name: 'Sad Droop',
class: 'sad-droop',
description: 'Slow drooping motion with vertical squash'
},
{
name: 'Angry Shake',
class: 'angry-shake',
description: 'Rapid horizontal shaking'
},
{
name: 'Confused Tilt',
class: 'confused-tilt',
description: 'Side-to-side head tilting motion'
},
{
name: 'Sleepy Sway',
class: 'sleepy-sway',
description: 'Slow swaying with slight rotation'
},
{
name: 'Alert Pulse',
class: 'alert-pulse',
description: 'Quick scaling pulse for attention'
},
{
name: 'Hurt Flash',
class: 'hurt-flash',
description: 'Opacity and brightness flashing'
},
{
name: 'Victory Spin',
class: 'victory-spin',
description: 'Full rotation with scaling'
},
{
name: 'Charging Glow',
class: 'charging-glow',
description: 'Brightness and saturation increase'
},
{
name: 'Dizzy Wobble',
class: 'dizzy-wobble',
description: 'Unsteady wobbling motion'
},
{
name: 'Attack Lunge',
class: 'attack-lunge',
description: 'Forward lunge motion with stretch'
},
{
name: 'Defend Crouch',
class: 'defend-crouch',
description: 'Defensive crouching animation'
},
{
name: 'Love Hearts',
class: 'love-hearts',
description: 'Gentle scaling with color shift'
},
{
name: 'Fear Tremble',
class: 'fear-tremble',
description: 'Rapid small trembling motion'
},
{
name: 'Evolving Glow',
class: 'evolving-glow',
description: 'Mystical glowing evolution effect'
},
{
name: 'Fainting Fall',
class: 'fainting-fall',
description: 'Rotation and fade for fainting'
},
{
name: 'Turn Left',
class: 'turn-left',
description: 'Smooth horizontal flip to face left'
},
{
name: 'Turn Right',
class: 'turn-right',
description: 'Smooth horizontal flip to face right'
},
{
name: 'Look Around',
class: 'look-around',
description: 'Turn left and right alternately'
},
{
name: 'Confetti Celebration',
class: 'confetti-effect',
description: 'Victory with colorful confetti particles',
hasParticles: true
},
{
name: 'Love Hearts Float',
class: 'hearts-float',
description: 'Floating heart particles around sprite',
hasParticles: true
},
{
name: 'Lightning Strike',
class: 'lightning-strike',
description: 'Electric attack with lightning effects',
hasParticles: true
},
{
name: 'Sparkle Magic',
class: 'sparkle-magic',
description: 'Magical sparkles surrounding sprite',
hasParticles: true
},
{
name: 'Fire Burst',
class: 'fire-burst',
description: 'Fire attack with flame particles',
hasParticles: true
},
{
name: 'Ice Crystals',
class: 'ice-crystals',
description: 'Ice attack with crystal particles',
hasParticles: true
},
{
name: 'Poison Bubbles',
class: 'poison-bubbles',
description: 'Toxic bubbles floating around',
hasParticles: true
},
{
name: 'Healing Aura',
class: 'healing-aura',
description: 'Gentle healing particles',
hasParticles: true
}
];
let uploadedImage = null;
function createAnimationCard(animation) {
const particleHTML = animation.hasParticles ? '<div class="particles" id="particles-' + animation.class + '"></div>' : '';
return `
<div class="animation-card">
<div class="animation-title">${animation.name}</div>
<div class="sprite-container">
${uploadedImage
? `<img src="${uploadedImage}" class="sprite ${animation.class}" alt="Animated sprite">`
: `<div class="demo-sprite ${animation.class}"></div>`
}
${particleHTML}
</div>
<div class="description">${animation.description}</div>
<div class="controls">
<div class="speed-control">
<select onchange="changeSpeed(this, '${animation.class}')">
<option value="0.5">2x Speed</option>
<option value="1" selected>Normal</option>
<option value="1.5">0.75x Speed</option>
<option value="2">0.5x Speed</option>
</select>
</div>
</div>
<button class="apply-btn" onclick="copyCSS('${animation.class}')">
Copy CSS
</button>
</div>
`;
}
function renderAnimations() {
const grid = document.getElementById('animationGrid');
grid.innerHTML = animations.map(createAnimationCard).join('');
// Initialize particle effects for animations that need them
animations.forEach(animation => {
if (animation.hasParticles) {
initializeParticles(animation.class);
}
});
}
function initializeParticles(animationClass) {
const particleContainer = document.getElementById(`particles-${animationClass}`);
if (!particleContainer) return;
// Clear existing particles
particleContainer.innerHTML = '';
const particleConfigs = {
'confetti-effect': {
count: 8,
type: 'confetti',
colors: ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#ffeaa7', '#dda0dd']
},
'hearts-float': {
count: 6,
type: 'heart'
},
'lightning-strike': {
count: 5,
type: 'lightning'
},
'sparkle-magic': {
count: 12,
type: 'sparkle'
},
'fire-burst': {
count: 8,
type: 'fire'
},
'ice-crystals': {
count: 10,
type: 'ice'
},
'poison-bubbles': {
count: 6,
type: 'poison'
},
'healing-aura': {
count: 8,
type: 'heal'
}
};
const config = particleConfigs[animationClass];
if (!config) return;
for (let i = 0; i < config.count; i++) {
const particle = document.createElement('div');
particle.className = `particle ${config.type}-particle`;
// Random positioning
const angle = (360 / config.count) * i + Math.random() * 45;
const radius = 40 + Math.random() * 20;
const x = 50 + Math.cos(angle * Math.PI / 180) * radius;
const y = 50 + Math.sin(angle * Math.PI / 180) * radius;
particle.style.left = x + '%';
particle.style.top = y + '%';
// Random delay for staggered animation
particle.style.animationDelay = Math.random() * 2 + 's';
// Color for confetti
if (config.type === 'confetti' && config.colors) {
particle.style.backgroundColor = config.colors[Math.floor(Math.random() * config.colors.length)];
}
particleContainer.appendChild(particle);
}
}
function changeSpeed(select, animationClass) {
const multiplier = parseFloat(select.value);
const elements = document.querySelectorAll(`.${animationClass}`);
elements.forEach(el => {
el.style.animationDuration = `${getOriginalDuration(animationClass) * multiplier}s`;
});
}
function getOriginalDuration(animationClass) {
const durations = {
'idle-bounce': 2,
'happy-bounce': 0.6,
'excited-shake': 0.5,
'sad-droop': 3,
'angry-shake': 0.3,
'confused-tilt': 2,
'sleepy-sway': 4,
'alert-pulse': 1,
'hurt-flash': 0.8,
'victory-spin': 1.5,
'charging-glow': 1.2,
'dizzy-wobble': 1,
'attack-lunge': 1.5,
'defend-crouch': 2,
'love-hearts': 2,
'fear-tremble': 0.4,
'evolving-glow': 2,
'fainting-fall': 3,
'turn-left': 2,
'turn-right': 2,
'look-around': 4,
'confetti-effect': 2,
'hearts-float': 3,
'lightning-strike': 1.5,
'sparkle-magic': 2,
'fire-burst': 1.8,
'ice-crystals': 2.5,
'poison-bubbles': 3,
'healing-aura': 2.8
};
return durations[animationClass] || 1;
}
function copyCSS(animationClass) {
const cssMap = {
'idle-bounce': `.idle-bounce {
animation: idleBounce 2s ease-in-out infinite;
}
@keyframes idleBounce {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-8px); }
}`,
'happy-bounce': `.happy-bounce {
animation: happyBounce 0.6s ease-in-out infinite;
}
@keyframes happyBounce {
0%, 100% { transform: translateY(0px) scale(1); }
50% { transform: translateY(-15px) scale(1.1); }
}`,
'excited-shake': `.excited-shake {
animation: excitedShake 0.5s ease-in-out infinite;
}
@keyframes excitedShake {
0%, 100% { transform: translateX(0px); }
25% { transform: translateX(-5px) rotate(-2deg); }
75% { transform: translateX(5px) rotate(2deg); }
}`,
'sad-droop': `.sad-droop {
animation: sadDroop 3s ease-in-out infinite;
}
@keyframes sadDroop {
0%, 100% { transform: translateY(0px) scaleY(1); }
50% { transform: translateY(10px) scaleY(0.9); }
}`,
'angry-shake': `.angry-shake {
animation: angryShake 0.3s ease-in-out infinite;
}
@keyframes angryShake {
0%, 100% { transform: translateX(0px); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-3px); }
20%, 40%, 60%, 80% { transform: translateX(3px); }
}`,
'confused-tilt': `.confused-tilt {
animation: confusedTilt 2s ease-in-out infinite;
}
@keyframes confusedTilt {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(-10deg); }
75% { transform: rotate(10deg); }
}`,
'sleepy-sway': `.sleepy-sway {
animation: sleepySway 4s ease-in-out infinite;
}
@keyframes sleepySway {
0%, 100% { transform: rotate(0deg) translateY(0px); }
25% { transform: rotate(-5deg) translateY(5px); }
75% { transform: rotate(5deg) translateY(5px); }
}`,
'alert-pulse': `.alert-pulse {
animation: alertPulse 1s ease-in-out infinite;
}
@keyframes alertPulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.15); }
}`,
'hurt-flash': `.hurt-flash {
animation: hurtFlash 0.8s ease-in-out infinite;
}
@keyframes hurtFlash {
0%, 100% { opacity: 1; filter: brightness(1); }
50% { opacity: 0.7; filter: brightness(1.5); }
}`,
'victory-spin': `.victory-spin {
animation: victorySpin 1.5s ease-in-out infinite;
}
@keyframes victorySpin {
0% { transform: rotate(0deg) scale(1); }
50% { transform: rotate(180deg) scale(1.2); }
100% { transform: rotate(360deg) scale(1); }
}`,
'charging-glow': `.charging-glow {
animation: chargingGlow 1.2s ease-in-out infinite;
}
@keyframes chargingGlow {
0%, 100% { filter: brightness(1) saturate(1); transform: scale(1); }
50% { filter: brightness(1.3) saturate(1.5); transform: scale(1.05); }
}`,
'dizzy-wobble': `.dizzy-wobble {
animation: dizzyWobble 1s ease-in-out infinite;
}
@keyframes dizzyWobble {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(-15deg) translateX(-5px); }
50% { transform: rotate(0deg) translateX(0px); }
75% { transform: rotate(15deg) translateX(5px); }
}`,
'attack-lunge': `.attack-lunge {
animation: attackLunge 1.5s ease-in-out infinite;
}
@keyframes attackLunge {
0%, 100% { transform: translateX(0px) scaleX(1); }
30% { transform: translateX(-10px) scaleX(0.9); }
60% { transform: translateX(15px) scaleX(1.1); }
}`,
'defend-crouch': `.defend-crouch {
animation: defendCrouch 2s ease-in-out infinite;
}
@keyframes defendCrouch {
0%, 100% { transform: scaleY(1) translateY(0px); }
50% { transform: scaleY(0.8) translateY(10px); }
}`,
'love-hearts': `.love-hearts {
animation: loveHearts 2s ease-in-out infinite;
}
@keyframes loveHearts {
0%, 100% { transform: scale(1); filter: hue-rotate(0deg); }
50% { transform: scale(1.1); filter: hue-rotate(20deg); }
}`,
'fear-tremble': `.fear-tremble {
animation: fearTremble 0.4s ease-in-out infinite;
}
@keyframes fearTremble {
0%, 100% { transform: translateX(0px) translateY(0px); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-2px) translateY(-1px); }
20%, 40%, 60%, 80% { transform: translateX(2px) translateY(1px); }
}`,
'evolving-glow': `.evolving-glow {
animation: evolvingGlow 2s ease-in-out infinite;
}
@keyframes evolvingGlow {
0%, 100% {
filter: brightness(1) contrast(1);
transform: scale(1);
}
50% {
filter: brightness(1.5) contrast(1.2);
transform: scale(1.1);
}
}`,
'fainting-fall': `.fainting-fall {
animation: faintingFall 3s ease-in-out infinite;
}
@keyframes faintingFall {
0%, 70% { transform: rotate(0deg) translateY(0px); opacity: 1; }
100% { transform: rotate(90deg) translateY(20px); opacity: 0.3; }
}`
};
const css = cssMap[animationClass];
if (css) {
navigator.clipboard.writeText(css).then(() => {
alert('CSS copied to clipboard!');
}).catch(() => {
const textArea = document.createElement('textarea');
textArea.value = css;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
alert('CSS copied to clipboard!');
});
}
}
// File upload handling
document.getElementById('sprite-upload').addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
uploadedImage = e.target.result;
renderAnimations();
};
reader.readAsDataURL(file);
}
});
// Initial render
renderAnimations();
</script>
</body>
</html>