Please bookmark this page to avoid losing your image tool!

Photo To AI Trailer Video Generator

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, durationSeconds = "5", titleText = "CINEMATIC TRAILER", subtitleText = "A MASTERPIECE BY AI") {
    const duration = parseFloat(durationSeconds) || 5;
    const width = 800;
    const height = 450; // 16:9 cinematic aspect ratio

    // Create the container
    const container = document.createElement('div');
    container.style.position = 'relative';
    container.style.width = '100%';
    container.style.maxWidth = width + 'px';
    container.style.aspectRatio = '16 / 9';
    container.style.backgroundColor = '#050505';
    container.style.color = '#fff';
    container.style.display = 'flex';
    container.style.alignItems = 'center';
    container.style.justifyContent = 'center';
    container.style.overflow = 'hidden';
    container.style.borderRadius = '8px';
    container.style.boxShadow = '0 4px 15px rgba(0,0,0,0.5)';
    container.style.fontFamily = "'Montserrat', sans-serif";

    // Status message while generating
    const statusMsg = document.createElement('div');
    statusMsg.innerText = "🎬 Generating AI Trailer... Please wait.";
    statusMsg.style.fontSize = '1.2rem';
    statusMsg.style.textAlign = 'center';
    statusMsg.style.zIndex = '1';
    container.appendChild(statusMsg);

    // Inject Cinematic Font
    const fontUrl = 'https://fonts.googleapis.com/css2?family=Montserrat:wght@900&display=swap';
    if (!document.querySelector(`link[href="${fontUrl}"]`)) {
        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.href = fontUrl;
        document.head.appendChild(link);
    }

    // Wait for the font to be ready, then begin processing
    document.fonts.ready.then(() => {
        const canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        const ctx = canvas.getContext('2d');

        // Setup MediaRecorder
        if (typeof MediaRecorder === 'undefined') {
            statusMsg.innerText = '⚠️ MediaRecorder is not supported in this browser. Try Chrome, Firefox, or Safari 14+';
            return;
        }

        const stream = canvas.captureStream(30); // Capture at 30 fps
        let options = { mimeType: 'video/webm; codecs=vp9' };
        if (!MediaRecorder.isTypeSupported(options.mimeType)) {
            options = { mimeType: 'video/webm' };
            if (!MediaRecorder.isTypeSupported(options.mimeType)) {
                options = { mimeType: 'video/mp4' };
                if (!MediaRecorder.isTypeSupported(options.mimeType)) {
                    options = {}; // Let browser choose the format
                }
            }
        }

        const recorder = new MediaRecorder(stream, options);
        const chunks = [];

        recorder.ondataavailable = e => {
            if (e.data && e.data.size > 0) chunks.push(e.data);
        };

        recorder.onstop = () => {
            const blob = new Blob(chunks, { type: chunks[0] ? chunks[0].type : 'video/mp4' });
            const videoUrl = URL.createObjectURL(blob);

            // Replace status with generated video element
            const video = document.createElement('video');
            video.src = videoUrl;
            video.controls = true;
            video.autoplay = true;
            video.loop = true;
            video.style.width = '100%';
            video.style.height = '100%';
            video.style.objectFit = 'cover';
            video.style.backgroundColor = '#000';

            container.innerHTML = ''; // Clear container
            container.appendChild(video);

            // Add an overlay Download button
            const dlBtn = document.createElement('a');
            dlBtn.href = videoUrl;
            
            // Determine video extension based on actual mimetype generated
            const ext = blob.type.includes('mp4') ? 'mp4' : 'webm';
            dlBtn.download = `ai_trailer.${ext}`;
            dlBtn.innerText = '📥 Download Video';
            dlBtn.style.position = 'absolute';
            dlBtn.style.bottom = '15px';
            dlBtn.style.right = '15px';
            dlBtn.style.padding = '10px 15px';
            dlBtn.style.backgroundColor = '#ffffff';
            dlBtn.style.color = '#000000';
            dlBtn.style.textDecoration = 'none';
            dlBtn.style.borderRadius = '6px';
            dlBtn.style.fontWeight = 'bold';
            dlBtn.style.fontSize = '14px';
            dlBtn.style.zIndex = '10';
            dlBtn.style.boxShadow = '0 2px 10px rgba(0,0,0,0.5)';
            dlBtn.style.transition = 'background-color 0.2s';
            dlBtn.onmouseenter = () => dlBtn.style.backgroundColor = '#e0e0e0';
            dlBtn.onmouseleave = () => dlBtn.style.backgroundColor = '#ffffff';
            container.appendChild(dlBtn);
        };

        // Start recording with 250ms timeslices
        recorder.start(250);

        let startTime = null;

        // Render animation frames
        function drawFrame(now) {
            if (!startTime) startTime = now;
            const elapsed = (now - startTime) / 1000;
            const progress = elapsed / duration;

            if (elapsed > duration) {
                recorder.stop();
                return; // Stop animation loop
            }

            // 1. Draw Background
            ctx.fillStyle = '#000';
            ctx.fillRect(0, 0, width, height);

            // 2. Compute Ken Burns effect (zoom out and slight pan)
            const imgAspect = originalImg.width / originalImg.height;
            const canvasAspect = width / height;
            let drawW, drawH;
            
            if (imgAspect > canvasAspect) {
                drawH = height;
                drawW = height * imgAspect;
            } else {
                drawW = width;
                drawH = width / imgAspect;
            }

            const scale = 1.3 - (0.15 * progress); // Zoom out smoothly
            const curW = drawW * scale;
            const curH = drawH * scale;
            const panX = (width - curW) / 2 + (80 * progress); // Pan slightly right over time
            const panY = (height - curH) / 2;

            // 3. Render and Apply Cinematic Grading
            ctx.save();
            ctx.globalCompositeOperation = 'source-over';
            ctx.drawImage(originalImg, panX, panY, curW, curH);

            // Cinematic "Teal & Orange" tint
            ctx.globalCompositeOperation = 'multiply';
            ctx.fillStyle = '#14212e'; // Dark moody teal
            ctx.fillRect(0, 0, width, height);

            ctx.globalCompositeOperation = 'overlay';
            // Pulsing warm highlights
            const pulse = Math.sin(progress * Math.PI) * 0.15;
            ctx.fillStyle = `rgba(255, 120, 40, ${0.1 + pulse})`; 
            ctx.fillRect(0, 0, width, height);
            ctx.restore();

            // 4. Heavy Vignette for drama
            const gradient = ctx.createRadialGradient(width/2, height/2, height/4, width/2, height/2, width*0.8);
            gradient.addColorStop(0, 'rgba(0,0,0,0)');
            gradient.addColorStop(1, 'rgba(0,0,0,0.95)');
            ctx.fillStyle = gradient;
            ctx.fillRect(0, 0, width, height);

            // 5. Simulate floating cinematic ash/sparks
            ctx.fillStyle = 'rgba(255, 180, 100, 0.4)';
            for (let i = 0; i < 45; i++) {
                const px = (Math.sin(i * 12.34 + elapsed * 0.8) * 0.5 + 0.5) * width;
                const py = ((i * 43.21 - elapsed * 60) % height + height) % height; // Float upwards
                const radius = (i % 3) + 1;
                ctx.beginPath();
                ctx.arc(px, py, radius, 0, Math.PI * 2);
                ctx.fill();
            }

            // 6. Letterbox (Black Cinema Bars)
            const barHeight = height * 0.11;
            ctx.fillStyle = '#000';
            ctx.fillRect(0, 0, width, barHeight);
            ctx.fillRect(0, height - barHeight, width, barHeight);

            // 7. Dramatic Text Overlay Sequence
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.font = `900 ${height * 0.11}px 'Montserrat', sans-serif`;
            ctx.shadowColor = '#000';
            ctx.shadowBlur = 20;
            ctx.shadowOffsetX = 3;
            ctx.shadowOffsetY = 3;

            let txt = "";
            let alpha = 0;
            const isGlitching = Math.random() > 0.94; // Random frame glitch

            if (progress < 0.33) {
                txt = "IN A WORLD...";
                alpha = Math.sin((progress / 0.33) * Math.PI); // Fade in/out
            } else if (progress < 0.66) {
                txt = subtitleText.toUpperCase();
                alpha = Math.sin(((progress - 0.33) / 0.33) * Math.PI);
            } else {
                txt = titleText.toUpperCase();
                alpha = Math.min((progress - 0.66) / 0.1, 1); // Fade in and stay
            }

            // Draw Text with Glitch RGB Split effect
            if (alpha > 0) {
                let rx = width / 2;
                let ry = height / 2;
                
                // Position jitter during glitch
                if (isGlitching && alpha > 0.4) {
                    rx += (Math.random() - 0.5) * 15;
                    ry += (Math.random() - 0.5) * 5;
                }

                // RGB channels
                if (isGlitching && alpha > 0.4) {
                    ctx.fillStyle = `rgba(255, 0, 80, ${alpha})`;
                    ctx.fillText(txt, rx - 8, ry);
                    ctx.fillStyle = `rgba(0, 255, 255, ${alpha})`;
                    ctx.fillText(txt, rx + 8, ry);
                }
                
                // Base white text
                ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`;
                ctx.fillText(txt, rx, ry);
            }

            // 8. Overall Master Fade In/Out
            if (progress < 0.05) {
                ctx.fillStyle = `rgba(0,0,0,${1 - progress/0.05})`;
                ctx.fillRect(0,0,width,height);
            } else if (progress > 0.95) {
                ctx.fillStyle = `rgba(0,0,0,${(progress-0.95)/0.05})`;
                ctx.fillRect(0,0,width,height);
            }

            requestAnimationFrame(drawFrame);
        }

        // Start drawing sequence
        requestAnimationFrame(drawFrame);

    }).catch(err => {
        statusMsg.innerText = "Error initializing fonts or rendering: " + err.message;
    });

    return container;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

This tool transforms a static image into a cinematic AI-style video trailer. It applies professional visual effects including the Ken Burns effect (smooth zooming and panning), dramatic teal and orange color grading, a heavy vignette, and floating particle overlays to create a high-production feel. The generator also adds dramatic text overlays with cinematic letterboxing and glitch effects, allowing users to customize the title and subtitle text. It is ideal for social media creators, filmmakers, or anyone looking to add a professional, movie-like atmosphere to their photography for presentations or promotional content.

Leave a Reply

Your email address will not be published. Required fields are marked *