Please bookmark this page to avoid losing your image tool!

Conjuring Style Video Closing Title Sequence AI 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.
async function processImage(
    originalImg, 
    titleText = "THE CONJURING", 
    subtitleText = "BASED ON THE TRUE CASE FILES", 
    durationMs = "15000"
) {
    // Dynamically load the spooky 'Cinzel' font for the title sequence
    const fontName = 'Cinzel';
    const link = document.createElement('link');
    link.href = `https://fonts.googleapis.com/css2?family=${fontName}:wght@400;700&display=swap`;
    link.rel = 'stylesheet';
    document.head.appendChild(link);
    
    try {
        await document.fonts.load(`400 20px "${fontName}"`);
    } catch(e) {
        console.warn("Font failed to load. Using fallback.");
    }

    const duration = Number(durationMs) || 15000;
    
    // Set up main rendering canvas
    const canvas = document.createElement('canvas');
    const width = 800; // Fixed width for performance and consistency
    const height = (originalImg.height / originalImg.width) * width;
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');

    // Create an off-screen canvas to process the input image into the creepy "Conjuring" style
    const bgCanvas = document.createElement('canvas');
    bgCanvas.width = width;
    bgCanvas.height = height;
    const bCtx = bgCanvas.getContext('2d');

    // Filter step 1: Grayscale, high contrast, darkened
    bCtx.filter = 'grayscale(100%) contrast(140%) brightness(35%)';
    bCtx.drawImage(originalImg, 0, 0, width, height);

    // Filter step 2: Greenish/Yellow Erie Tint (Multiply)
    bCtx.filter = 'none';
    bCtx.globalCompositeOperation = 'multiply';
    bCtx.fillStyle = '#4a5440'; 
    bCtx.fillRect(0, 0, width, height);

    // Filter step 3: Blown out, blooming highlights (Overlay/Soft Light)
    bCtx.globalCompositeOperation = 'soft-light';
    bCtx.filter = 'blur(8px)';
    bCtx.drawImage(originalImg, 0, 0, width, height);

    // Filter step 4: Heavy Vignette
    bCtx.filter = 'none';
    bCtx.globalCompositeOperation = 'source-over';
    const cx = width / 2;
    const cy = height / 2;
    const radius = Math.max(width, height) * 0.7;
    const grad = bCtx.createRadialGradient(cx, cy, radius * 0.2, cx, cy, radius);
    grad.addColorStop(0, 'rgba(0,0,0,0)');
    grad.addColorStop(1, 'rgba(0,0,0,0.95)');
    bCtx.fillStyle = grad;
    bCtx.fillRect(0, 0, width, height);

    // Generate floating dust particles
    const particles = [];
    for (let i = 0; i < 80; i++) {
        particles.push({
            x: Math.random() * width,
            y: Math.random() * height,
            vx: (Math.random() - 0.5) * 0.3,
            vy: (Math.random() - 0.5) * 0.3,
            size: Math.random() * 1.5 + 0.5,
            alpha: Math.random() * 0.6
        });
    }

    // Text Drawing Helper function
    function drawText(text, p, startIn, endIn, startOut, endOut, size, yOffset) {
        if (p < startIn || p > endOut) return;
        
        let opacity = 1;
        if (p < endIn) {
            opacity = (p - startIn) / (endIn - startIn); // Fading in
        } else if (p > startOut) {
            opacity = 1 - (p - startOut) / (endOut - startOut); // Fading out
        }
        
        // Very slow text scaling
        let scale = 1 + ((p - startIn) * 0.15); 

        ctx.save();
        ctx.translate(width / 2, height / 2 + yOffset);
        ctx.scale(scale, scale);
        
        ctx.fillStyle = `rgba(230, 225, 200, ${opacity})`;
        ctx.shadowColor = `rgba(0, 0, 0, ${opacity})`;
        ctx.shadowBlur = 12;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.font = `700 ${size}px "${fontName}", serif`;

        // Modern browsers support canvas letterSpacing
        if ('letterSpacing' in ctx) {
            ctx.letterSpacing = '12px';
        }

        ctx.fillText(text, 0, 0);
        ctx.restore();
    }

    const startTime = performance.now();

    // Animation Loop
    function renderFrame(timestamp) {
        const elapsed = timestamp - startTime;
        const p = (elapsed % duration) / duration; // Loops from 0.0 to 1.0
        
        ctx.clearRect(0, 0, width, height);

        // 1. Draw slowly zooming spooky background
        const bgScale = 1 + (p * 0.1);
        ctx.save();
        ctx.translate(width / 2, height / 2);
        ctx.scale(bgScale, bgScale);
        ctx.drawImage(bgCanvas, -width / 2, -height / 2);
        ctx.restore();

        // 2. Draw Dust particles
        ctx.save();
        ctx.fillStyle = 'white';
        particles.forEach(pt => {
            pt.x += pt.vx;
            pt.y += pt.vy;
            // wrap around
            if (pt.x < 0) pt.x = width;
            if (pt.x > width) pt.x = 0;
            if (pt.y < 0) pt.y = height;
            if (pt.y > height) pt.y = 0;

            ctx.globalAlpha = pt.alpha * (p < 0.1 ? p/0.1 : (p > 0.9 ? (1-p)/0.1 : 1));
            ctx.beginPath();
            ctx.arc(pt.x, pt.y, pt.size, 0, Math.PI * 2);
            ctx.fill();
        });
        ctx.restore();

        // 3. Draw Title Sequence Text
        // Main Title (Fades in slightly after start, stays a while, fades out)
        drawText(titleText, p, 0.15, 0.35, 0.75, 0.90, 50, -20);
        
        // Subtitle (Fades in later, fades out with main title)
        drawText(subtitleText, p, 0.45, 0.60, 0.75, 0.90, 18, 50);

        // 4. Global Black Fade In/Out for loop continuity
        let fadeAlpha = 0;
        if (p < 0.05) fadeAlpha = 1 - (p / 0.05); // Fade from black at 0%
        if (p > 0.95) fadeAlpha = (p - 0.95) / 0.05; // Fade to black at 100%
        
        if (fadeAlpha > 0) {
            ctx.fillStyle = `rgba(0, 0, 0, ${fadeAlpha})`;
            ctx.fillRect(0, 0, width, height);
        }

        requestAnimationFrame(renderFrame);
    }

    // Start the animation
    requestAnimationFrame(renderFrame);

    // Return the animated canvas element
    return canvas;
}

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 generates a horror-themed, cinematic video closing title sequence from a static image. It applies stylized visual effects including grayscale high-contrast filtering, an eerie greenish tint, heavy vignetting, and a slow zoom animation to create a spooky atmosphere. The generator also adds floating dust particles and animated typography, allowing users to customize the main title, subtitle, and animation duration. It is ideal for filmmakers, content creators, or hobbyists looking to add a professional, suspenseful end-credit effect to horror-themed videos or social media projects.

Leave a Reply

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