You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Image Surprise Generator for Boys (Сюрприз для мальчиков)
* Transforms an image into an "Action Figure / Toy Box" graphic.
*
* @param {HTMLImageElement} originalImg - The input image.
* @param {string} titleText - The main title text.
* @param {string} themePrefix - The text above the title.
* @param {string} themeColor - The background color of the box.
* @param {string} badgeAge - The text for the age recommendation badge.
* @param {string} stickers - Comma-separated list of emojis to use as stickers.
*/
function processImage(
originalImg,
titleText = "МЕГА СЮРПРИЗ!",
themePrefix = "СУПЕР ГЕРОЙ",
themeColor = "#e62e00",
badgeAge = "5+",
stickers = "⚡,💥,🚀,⚽"
) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// Polyfill for roundRect if it doesn't exist in older browsers
if (!ctx.roundRect) {
ctx.roundRect = function (x, y, width, height, radius) {
this.beginPath();
this.moveTo(x + radius, y);
this.lineTo(x + width - radius, y);
this.quadraticCurveTo(x + width, y, x + width, y + radius);
this.lineTo(x + width, y + height - radius);
this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
this.lineTo(x + radius, y + height);
this.quadraticCurveTo(x, y + height, x, y + height - radius);
this.lineTo(x, y + radius);
this.quadraticCurveTo(x, y, x + radius, y);
this.closePath();
return this;
};
}
// Determine dimensions responsive to the uploaded image resolution
const imgW = originalImg.width;
const imgH = originalImg.height;
const maxDim = Math.max(imgW, imgH);
// Dynamic padding calculations
const padX = maxDim * 0.18;
const padTop = maxDim * 0.35;
const padBot = maxDim * 0.25;
const w = imgW + padX * 2;
const h = imgH + padTop + padBot;
canvas.width = w;
canvas.height = h;
// 1. Draw Box Base Background
ctx.fillStyle = themeColor;
ctx.fillRect(0, 0, w, h);
// Apply a black-and-white gradient overlay to add depth/shading
const shadeGrad = ctx.createLinearGradient(0, 0, 0, h);
shadeGrad.addColorStop(0, "rgba(255, 255, 255, 0.25)");
shadeGrad.addColorStop(0.5, "rgba(0, 0, 0, 0)");
shadeGrad.addColorStop(1, "rgba(0, 0, 0, 0.6)");
ctx.fillStyle = shadeGrad;
ctx.fillRect(0, 0, w, h);
// 2. Draw Sunburst / Action Lines for that "Comic/Toy" feel
ctx.save();
ctx.translate(w / 2, h / 2);
ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
const rays = 24;
for (let i = 0; i < rays; i++) {
ctx.beginPath();
ctx.moveTo(0, 0);
const a1 = (i * Math.PI * 2) / rays;
const a2 = ((i + 0.5) * Math.PI * 2) / rays;
// Extend rays beyond the borders
const rayLen = w + h;
ctx.lineTo(Math.cos(a1) * rayLen, Math.sin(a1) * rayLen);
ctx.lineTo(Math.cos(a2) * rayLen, Math.sin(a2) * rayLen);
ctx.closePath();
ctx.fill();
}
ctx.restore();
// 3. Draw Peg Hole (the hanger hole at the top of action figure boxes)
const pegWidth = w * 0.15;
const pegHeight = maxDim * 0.04;
const pegY = padTop * 0.25;
const pegRad = pegHeight / 2;
ctx.fillStyle = "#ffffff";
ctx.roundRect((w - pegWidth) / 2, pegY, pegWidth, pegHeight, pegRad);
ctx.fill();
// Cut out the inner part to simulate a hole
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "black";
ctx.roundRect((w - pegWidth) / 2 + pegHeight/2, pegY + pegHeight/4, pegWidth - pegHeight, pegHeight/2, pegHeight/4);
ctx.fill();
ctx.globalCompositeOperation = 'source-over';
// 4. Draw the Blister Pack dark cardboard background outline
const blisterPad = maxDim * 0.05;
const blisterX = padX - blisterPad;
const blisterY = padTop - blisterPad;
const blisterW = imgW + blisterPad * 2;
const blisterH = imgH + blisterPad * 2;
ctx.fillStyle = "#111111";
ctx.shadowColor = "rgba(0,0,0,0.8)";
ctx.shadowBlur = maxDim * 0.02;
ctx.shadowOffsetY = maxDim * 0.015;
ctx.roundRect(blisterX, blisterY, blisterW, blisterH, blisterPad);
ctx.fill();
ctx.shadowColor = "transparent"; // Reset shadow
// 5. Draw the Actual Original Image
ctx.drawImage(originalImg, padX, padTop, imgW, imgH);
// Apply a white border directly around the image (resembles a card cut inside)
ctx.lineWidth = maxDim * 0.01;
ctx.strokeStyle = "#ffffff";
ctx.strokeRect(padX, padTop, imgW, imgH);
// 6. Draw Plastic Blister Glare/Highlights (makes it look like a toy window)
ctx.save();
ctx.beginPath();
ctx.roundRect(blisterX, blisterY, blisterW, blisterH, blisterPad);
ctx.clip(); // Ensure reflections stay inside the blister bounds
// Main volume glare
const pGrad = ctx.createLinearGradient(blisterX, blisterY, blisterX + blisterW, blisterY + blisterH);
pGrad.addColorStop(0, "rgba(255, 255, 255, 0.4)");
pGrad.addColorStop(0.3, "rgba(255, 255, 255, 0.05)");
pGrad.addColorStop(0.7, "rgba(255, 255, 255, 0.0)");
pGrad.addColorStop(1, "rgba(255, 255, 255, 0.2)");
ctx.fillStyle = pGrad;
ctx.fill();
// Sharp diagonal window reflections
ctx.beginPath();
ctx.moveTo(blisterX - blisterW, blisterY - blisterH);
ctx.lineTo(blisterX + blisterW * 2, blisterY + blisterH * 2 - blisterH * 0.4);
ctx.lineTo(blisterX + blisterW * 2, blisterY + blisterH * 2);
ctx.lineTo(blisterX - blisterW, blisterY - blisterH + blisterH * 0.4);
ctx.fillStyle = "rgba(255, 255, 255, 0.12)";
ctx.fill();
ctx.restore();
// 7. Draw Typography / Branding Titles
const fontSizeTop = maxDim * 0.14;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.save();
// Position titles in the header padded area
ctx.translate(w / 2, padTop * 0.6);
ctx.rotate(-0.04); // Give it a dynamic, youthful tilt
// Draw Theme Prefix (e.g. "СУПЕР ГЕРОЙ")
const subFontSize = fontSizeTop * 0.4;
ctx.font = `italic 900 ${subFontSize}px Impact, sans-serif`;
ctx.fillStyle = "#ffffff";
ctx.shadowColor = "rgba(0,0,0,0.8)";
ctx.shadowBlur = maxDim * 0.01;
ctx.fillText(themePrefix, -w * 0.1, -fontSizeTop * 0.4);
// Draw Main Title
ctx.font = `italic 900 ${fontSizeTop}px Impact, sans-serif`;
ctx.shadowColor = "transparent";
// Thick black outline
ctx.lineWidth = maxDim * 0.02;
ctx.strokeStyle = "#000000";
ctx.strokeText(titleText, 0, 0);
// Text Inner Gradient
const textGrad = ctx.createLinearGradient(0, -fontSizeTop / 2, 0, fontSizeTop / 2);
textGrad.addColorStop(0, "#ffff00");
textGrad.addColorStop(1, "#ff8800");
ctx.fillStyle = textGrad;
ctx.fillText(titleText, 0, 0);
// White highlight stroke
ctx.lineWidth = maxDim * 0.006;
ctx.strokeStyle = "#ffffff";
ctx.strokeText(titleText, 0, 0);
ctx.restore();
// 8. Draw "Ages 5+" circular badge
ctx.save();
ctx.translate(w - padX * 0.8, padTop + imgH + padBot * 0.45);
ctx.rotate(-0.1);
const r1 = maxDim * 0.08;
// Badge Background
ctx.beginPath();
ctx.arc(0, 0, r1, 0, Math.PI * 2);
ctx.fillStyle = "#ff0000";
ctx.shadowColor = "rgba(0,0,0,0.6)";
ctx.shadowBlur = maxDim * 0.01;
ctx.shadowOffsetY = maxDim * 0.01;
ctx.fill();
ctx.shadowColor = "transparent";
// Badge Border
ctx.lineWidth = maxDim * 0.01;
ctx.strokeStyle = "#ffffff";
ctx.stroke();
// Badge Text
ctx.fillStyle = "#ffffff";
ctx.font = `bold ${r1 * 0.35}px Arial, sans-serif`;
ctx.fillText("AGES", 0, -r1 * 0.2);
ctx.font = `900 ${r1 * 0.65}px Arial, sans-serif`;
ctx.fillText(badgeAge, 0, r1 * 0.35);
ctx.restore();
// Small Warning Footer Text
ctx.font = `bold ${maxDim * 0.03}px Arial, sans-serif`;
ctx.fillStyle = "rgba(255,255,255,0.9)";
ctx.textAlign = "center";
ctx.fillText("ВНИМАНИЕ: Зашкаливающий уровень крутости!", w / 2, h - padBot * 0.25);
// 9. Draw Dynamic Cool Stickers!
const stickerArr = stickers.split(",").map(s => s.trim()).filter(s => s);
const s1 = stickerArr[0] || "💥";
const s2 = stickerArr[1] || "🚀";
const s3 = stickerArr[2] || "⚡";
const s4 = stickerArr[3] || "⚽";
// Helper to draw a sticker circle with emoji
const drawEmojiSticker = (emoji, x, y, size, rot) => {
ctx.save();
ctx.translate(x, y);
ctx.rotate(rot);
// White background of the sticker
ctx.beginPath();
ctx.arc(0, 0, size * 0.55, 0, Math.PI * 2);
ctx.fillStyle = "#ffffff";
ctx.shadowColor = "rgba(0,0,0,0.5)";
ctx.shadowBlur = size * 0.15;
ctx.shadowOffsetY = size * 0.1;
ctx.fill();
ctx.shadowColor = "transparent";
ctx.lineWidth = size * 0.04;
ctx.strokeStyle = "#000000";
ctx.stroke();
// Emoji drawing
ctx.font = `${size * 0.65}px sans-serif`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(emoji, 0, size * 0.04);
ctx.restore();
};
// Distribute stickers around the packaging
drawEmojiSticker(s1, padX * 0.45, padTop * 0.8, maxDim * 0.16, -0.2);
drawEmojiSticker(s2, w - padX * 0.45, padTop * 0.6, maxDim * 0.14, 0.25);
drawEmojiSticker(s3, padX * 0.5, h - padBot * 0.6, maxDim * 0.15, -0.3);
drawEmojiSticker(s4, w - padX * 0.35, h - padBot * 0.5, maxDim * 0.13, 0.15);
return canvas;
}
Apply Changes