You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, speed = "0.3", catScale = "50") {
// Parse user parameters securely
const s = parseFloat(speed) > 0 ? parseFloat(speed) : 0.3;
const catScaleVal = parseFloat(catScale) > 0 ? parseFloat(catScale) : 50;
const bopSpeed = s / 2;
// Unique ID for CSS animations to prevent cross-contamination if multiple instances are generated
const idSuffix = Math.random().toString(36).substring(2, 8);
const flapL = `flapL_${idSuffix}`;
const flapR = `flapR_${idSuffix}`;
const bop = `bodyBop_${idSuffix}`;
// Create a rich DOM container wrapper to host the tool's interaction visually
const container = document.createElement('div');
container.style.position = 'relative';
container.style.display = 'inline-flex';
container.style.justifyContent = 'center';
container.style.alignItems = 'flex-end'; // aligns the SVG perfectly with the bottom
container.style.overflow = 'hidden';
container.style.borderRadius = '12px';
container.style.boxShadow = '0 8px 30px rgba(0,0,0,0.2)';
container.style.backgroundColor = '#e0e0e0';
container.style.transform = 'translateZ(0)'; // trick to ensure strictly clipped border-radius
// Fallback checkerboard for transparency situations
container.style.backgroundImage = 'linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(-45deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(-45deg, transparent 75%, #ccc 75%)';
container.style.backgroundSize = '20px 20px';
container.style.backgroundPosition = '0 0, 0 10px, 10px -10px, -10px 0px';
// Base original image serving as the "table/drums" to be hit
const img = document.createElement('img');
img.src = originalImg.src;
img.style.display = 'block';
img.style.maxWidth = '100%';
img.style.height = 'auto';
img.style.zIndex = '1';
// Bongo Cat SVG Overlay container
const overlay = document.createElement('div');
overlay.style.position = 'absolute';
overlay.style.bottom = '-4px'; // Slightly sinks the bottom edge to hide the lower stroke smartly
overlay.style.left = '50%';
overlay.style.transform = 'translateX(-50%)';
overlay.style.width = `${catScaleVal}%`;
overlay.style.minWidth = '150px';
overlay.style.maxWidth = '600px';
overlay.style.pointerEvents = 'none'; // so user can still right-click the instrument image
overlay.style.zIndex = '2';
// Self-contained dynamic SVG (fully utilizing SMIL & CSS Keyframes)
// Coordinated carefully using nested groups for reliable rotation origin anchoring across browsers
const svgCode = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 310" preserveAspectRatio="xMidYMax meet">
<style>
.pawL_${idSuffix} { animation: ${flapL} ${s}s infinite; }
.pawR_${idSuffix} { animation: ${flapR} ${s}s infinite; }
.bodyGroup_${idSuffix} { animation: ${bop} ${bopSpeed}s infinite; }
/* Down stroke on alternating rhythms! */
@keyframes ${flapL} {
0%, 49% { transform: rotate(0deg); }
50%, 100% { transform: rotate(-35deg); }
}
@keyframes ${flapR} {
0%, 49% { transform: rotate(35deg); }
50%, 100% { transform: rotate(0deg); }
}
/* Gentle rhythmic squish corresponding dynamically to BOTH hits */
@keyframes ${bop} {
0%, 15% { transform: scale(1.02, 0.96) translateY(2px); }
45%, 100% { transform: scale(1, 1) translateY(0); }
}
</style>
<!-- Floating music notes layer -->
<g font-size="35" fill="#222" font-family="Arial, sans-serif">
<text x="70" y="100" opacity="0">♪
<animate attributeName="y" values="100; 10" dur="1.5s" repeatCount="indefinite" begin="0s" />
<animate attributeName="opacity" values="0; 1; 0" keyTimes="0; 0.2; 1" dur="1.5s" repeatCount="indefinite" begin="0s" />
</text>
<text x="420" y="120" opacity="0">♫
<animate attributeName="y" values="120; 30" dur="1.6s" repeatCount="indefinite" begin="0.5s" />
<animate attributeName="opacity" values="0; 1; 0" keyTimes="0; 0.2; 1" dur="1.6s" repeatCount="indefinite" begin="0.5s" />
</text>
<text x="130" y="70" opacity="0">♪
<animate attributeName="y" values="70; -10" dur="1.7s" repeatCount="indefinite" begin="1s" />
<animate attributeName="opacity" values="0; 1; 0" keyTimes="0; 0.2; 1" dur="1.7s" repeatCount="indefinite" begin="1s" />
</text>
</g>
<!-- Nested architecture cleanly standardizes the origin to the center bottom -->
<g transform="translate(250, 300)">
<g class="bodyGroup_${idSuffix}">
<g transform="translate(-250, -300)">
<!-- Cat Blob Body (Built in with standard meme proportions + ears!) -->
<path d="M 50,300 Q 50,150 110,100 L 125,40 L 165,80 Q 250,55 335,80 L 375,40 L 390,100 Q 450,150 450,300 Z" fill="#fff" stroke="#222" stroke-width="8" stroke-linejoin="round" />
<!-- Pink Cheeks -->
<circle cx="150" cy="180" r="20" fill="#ffaec9" opacity="0.6" />
<circle cx="350" cy="180" r="20" fill="#ffaec9" opacity="0.6" />
<!-- Adorable Dots -->
<circle cx="200" cy="150" r="10" fill="#222" />
<circle cx="300" cy="150" r="10" fill="#222" />
<!-- Bongo Cat 'W' Mouth -->
<path d="M 230,170 Q 240,185 250,170 Q 260,185 270,170" fill="none" stroke="#222" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" />
<!-- Left Paw hitting mechanism locked cleanly to Left Anchor Points -->
<g transform="translate(60, 260)">
<g class="pawL_${idSuffix}">
<g transform="translate(-60, -260)">
<ellipse cx="95" cy="260" rx="45" ry="25" fill="#fff" stroke="#222" stroke-width="8" />
</g>
</g>
</g>
<!-- Right Paw hitting mechanism locked cleanly to Right Anchor Points -->
<g transform="translate(440, 260)">
<g class="pawR_${idSuffix}">
<g transform="translate(-440, -260)">
<ellipse cx="405" cy="260" rx="45" ry="25" fill="#fff" stroke="#222" stroke-width="8" />
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
`;
overlay.innerHTML = svgCode.trim();
// Pack together DOM
container.appendChild(img);
container.appendChild(overlay);
return container;
}
Apply Changes