You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, titleText = "THE ALGORITHM", subtitleText = "COMING SOON", animationSpeed = 1) {
// Determine cinematic 21:9 aspect ratio based on original image
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// We base the canvas size on the original image, cropping it to a cinematic 21:9 format
canvas.width = originalImg.width;
canvas.height = originalImg.width * (9 / 21);
// If the image is extremely narrow, cap the height to the original
if (canvas.height > originalImg.height) {
canvas.height = originalImg.height;
canvas.width = canvas.height * (21 / 9);
}
// Dynamically load Google Font "Cinzel" for an epic movie trailer look
const fontId = 'font-cinzel-trailer';
if (!document.getElementById(fontId)) {
const link = document.createElement('link');
link.id = fontId;
link.rel = 'stylesheet';
link.href = 'https://fonts.googleapis.com/css2?family=Cinzel:wght@700&display=swap';
document.head.appendChild(link);
}
const texts = [
"GENERATED BY AI",
"A VISION OF THE FUTURE",
titleText.toUpperCase(),
subtitleText.toUpperCase()
];
const startTime = Date.now();
function drawFrame() {
const now = Date.now();
// Speed up or slow down based on parameter
const elapsed = (now - startTime) * parseFloat(animationSpeed);
// Loop text every 12 seconds (3 seconds per text)
const totalLoopTime = texts.length * 3000;
const currentLoopTime = elapsed % totalLoopTime;
const textIndex = Math.floor(currentLoopTime / 3000);
const text = texts[textIndex];
// Text fade logic (fade in 500ms, hold 2000ms, fade out 500ms)
const timeInPhase = currentLoopTime % 3000;
let textAlpha = 1;
if (timeInPhase < 500) {
textAlpha = timeInPhase / 500;
} else if (timeInPhase > 2500) {
textAlpha = (3000 - timeInPhase) / 500;
}
// Ken Burns effect: sine wave zooming in and out seamlessly
const zoomCycle = elapsed % 24000; // 24 second full cycle
const scale = 1.05 + (Math.sin((zoomCycle / 24000) * Math.PI) * 0.15);
// Fill base background
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Apply Ken burns zoom and pan
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.scale(scale, scale);
// Calculate bounds to "cover" the canvas while maintaining aspect ratio
const imgRatio = originalImg.width / originalImg.height;
const canvasRatio = canvas.width / canvas.height;
let drawWidth = canvas.width;
let drawHeight = canvas.height;
if (imgRatio > canvasRatio) {
drawWidth = canvas.height * imgRatio;
} else {
drawHeight = canvas.width / imgRatio;
}
ctx.drawImage(
originalImg,
-drawWidth / 2,
-drawHeight / 2,
drawWidth,
drawHeight
);
ctx.restore();
// Draw dramatic vignette (darken edges)
const gradient = ctx.createRadialGradient(
canvas.width / 2, canvas.height / 2, 0,
canvas.width / 2, canvas.height / 2, Math.max(canvas.width, canvas.height) / 1.2
);
gradient.addColorStop(0, 'rgba(0,0,0,0)');
gradient.addColorStop(0.5, 'rgba(0,10,20,0.3)');
gradient.addColorStop(1, 'rgba(0,0,0,0.9)');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Top and Bottom Cinematic Letterbox (Black Bars)
const barHeight = canvas.height * 0.1;
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, barHeight);
ctx.fillRect(0, canvas.height - barHeight, canvas.width, barHeight);
// Draw Trailer Text
ctx.save();
const fontSize = Math.max(16, canvas.height * 0.08);
ctx.font = `bold ${fontSize}px "Cinzel", serif`;
ctx.fillStyle = `rgba(255, 255, 255, ${textAlpha})`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Shadow for cinematic glow
ctx.shadowColor = 'rgba(0, 0, 0, 0.9)';
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 3;
ctx.shadowOffsetY = 3;
// Fallback for letter spacing if supported
if ('letterSpacing' in ctx) {
ctx.letterSpacing = `${fontSize * 0.15}px`;
} else {
// Emulate slight spacing for old browsers
ctx.scale(1.05, 1);
}
ctx.fillText(text, canvas.width / 2, canvas.height / 2);
ctx.restore();
// Keep animating directly onto this canvas
requestAnimationFrame(drawFrame);
}
// Begin rendering trailer loop
drawFrame();
return canvas;
}
Apply Changes