Please bookmark this page to avoid losing your image tool!

New Year Movie Company Studio Overview Image Viewer

(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, titleText = "ОБЗОР СТУДИИ: КИНОКОМПАНИЯ НОВОГО ГОДА", zoomAmount = "1.2", snowDensity = "60") {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    
    // Set standard cinematic 16:9 aspect ratio for the viewer based on original image width
    const viewerWidth = Math.max(originalImg.width, 1280);
    const viewerHeight = viewerWidth * (9 / 16);
    
    canvas.width = viewerWidth;
    canvas.height = viewerHeight;
    canvas.style.maxWidth = "100%";
    canvas.style.height = "auto";
    canvas.style.display = "block";
    canvas.style.boxShadow = "0 8px 32px rgba(0,0,0,0.5)";
    canvas.style.cursor = "grab";
    
    const zoom = Math.max(1, parseFloat(zoomAmount) || 1.2);
    const particlesCount = parseInt(snowDensity) || 60;
    
    let panX = (viewerWidth - originalImg.width * zoom) / 2;
    let panY = (viewerHeight - originalImg.height * zoom) / 2;
    
    let isDragging = false;
    let startX = 0;
    let startY = 0;
    
    const initTime = Date.now();
    let blinkRec = false;
    
    function draw() {
        ctx.clearRect(0, 0, viewerWidth, viewerHeight);
        
        // Base dark background
        ctx.fillStyle = "#050505";
        ctx.fillRect(0, 0, viewerWidth, viewerHeight);
        
        // Dynamic panning bounds logic
        const iw = originalImg.width * zoom;
        const ih = originalImg.height * zoom;
        
        const minX = Math.min(0, viewerWidth - iw);
        const maxX = Math.max(0, (viewerWidth - iw) / 2);
        const minY = Math.min(0, viewerHeight - ih);
        const maxY = Math.max(0, (viewerHeight - ih) / 2);
        
        if (iw >= viewerWidth) {
            panX = Math.max(minX, Math.min(0, panX));
        } else {
            panX = (viewerWidth - iw) / 2;
        }
        if (ih >= viewerHeight) {
            panY = Math.max(minY, Math.min(0, panY));
        } else {
            panY = (viewerHeight - ih) / 2;
        }
        
        // Draw the main panning image
        ctx.drawImage(originalImg, panX, panY, iw, ih);
        
        // Adding Cinematic Cold Grade
        const gradient = ctx.createRadialGradient(
            viewerWidth / 2, viewerHeight / 2, viewerWidth * 0.2, 
            viewerWidth / 2, viewerHeight / 2, viewerWidth * 0.8
        );
        gradient.addColorStop(0, "rgba(0, 20, 50, 0.05)");
        gradient.addColorStop(1, "rgba(0, 10, 25, 0.6)");
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, viewerWidth, viewerHeight);
        
        // "New Year" Studio Snow / Bokeh Overlay logic (Parallax)
        ctx.fillStyle = "rgba(255, 255, 255, 0.65)";
        for(let i = 0; i < particlesCount; i++) {
            const sx = ((i * 137 + panX * (0.2 + (i % 3) * 0.15)) % viewerWidth + viewerWidth) % viewerWidth;
            const sy = ((i * 313 + panY * (0.2 + (i % 3) * 0.15)) % viewerHeight + viewerHeight) % viewerHeight;
            const radius = (i % 4) + 1;
            ctx.beginPath();
            ctx.arc(sx, sy, radius, 0, Math.PI * 2);
            ctx.fill();
        }
        
        // Top and Bottom Letterboxing UI Blocks
        const barHeight = viewerHeight * 0.1;
        ctx.fillStyle = "rgba(0, 0, 0, 0.85)";
        ctx.fillRect(0, 0, viewerWidth, barHeight);
        ctx.fillRect(0, viewerHeight - barHeight, viewerWidth, barHeight);
        
        // --- Central Viewfinder UI ---
        const safeX = viewerWidth * 0.15;
        const safeY = viewerHeight * 0.15;
        const safeW = viewerWidth * 0.7;
        const safeH = viewerHeight * 0.7;
        const bracketLen = viewerWidth * 0.03;
        
        ctx.strokeStyle = "rgba(255, 255, 255, 0.4)";
        ctx.lineWidth = 3;
        
        // Top Left Bracket
        ctx.beginPath();
        ctx.moveTo(safeX, safeY + bracketLen);
        ctx.lineTo(safeX, safeY);
        ctx.lineTo(safeX + bracketLen, safeY);
        ctx.stroke();
        // Top Right Bracket
        ctx.beginPath();
        ctx.moveTo(safeX + safeW - bracketLen, safeY);
        ctx.lineTo(safeX + safeW, safeY);
        ctx.lineTo(safeX + safeW, safeY + bracketLen);
        ctx.stroke();
        // Bottom Right Bracket
        ctx.beginPath();
        ctx.moveTo(safeX + safeW, safeY + safeH - bracketLen);
        ctx.lineTo(safeX + safeW, safeY + safeH);
        ctx.lineTo(safeX + safeW - bracketLen, safeY + safeH);
        ctx.stroke();
        // Bottom Left Bracket
        ctx.beginPath();
        ctx.moveTo(safeX + bracketLen, safeY + safeH);
        ctx.lineTo(safeX, safeY + safeH);
        ctx.lineTo(safeX, safeY + safeH - bracketLen);
        ctx.stroke();
        
        // Center Crosshair
        ctx.beginPath();
        ctx.moveTo(viewerWidth / 2 - 20, viewerHeight / 2);
        ctx.lineTo(viewerWidth / 2 + 20, viewerHeight / 2);
        ctx.moveTo(viewerWidth / 2, viewerHeight / 2 - 20);
        ctx.lineTo(viewerWidth / 2, viewerHeight / 2 + 20);
        ctx.stroke();

        // --- Texts and HUD overlays ---
        ctx.fillStyle = "#ffffff";
        ctx.font = `bold ${Math.max(14, barHeight * 0.35)}px "Courier New", Courier, monospace`;
        ctx.textBaseline = "middle";
        
        // Title Text
        ctx.textAlign = "left";
        ctx.fillText(titleText, viewerWidth * 0.02, barHeight / 2);
        
        // Timecode and REC logic
        const elapsedTime = Date.now() - initTime;
        const totalSecs = Math.floor(elapsedTime / 1000);
        const hh = Math.floor(totalSecs / 3600);
        const mm = Math.floor(totalSecs / 60) % 60;
        const ss = totalSecs % 60;
        // simulating frames at 24fps
        const ff = Math.floor((elapsedTime % 1000) / (1000/24)); 
        
        const pad = (n) => String(n).padStart(2, "0");
        const timecode = `REC  ${pad(hh)}:${pad(mm)}:${pad(ss)}:${pad(ff)}`;
        
        ctx.textAlign = "right";
        ctx.fillText(timecode, viewerWidth * 0.98, barHeight / 2);
        
        // Blinking REC dot
        if (blinkRec) {
            ctx.fillStyle = "#ff0000";
            const textWidth = ctx.measureText(timecode).width;
            const dotSize = barHeight * 0.12;
            ctx.beginPath();
            ctx.arc(viewerWidth * 0.98 - textWidth - dotSize * 2, barHeight / 2, dotSize, 0, Math.PI * 2);
            ctx.fill();
        }
        
        // Footer Details Info
        ctx.fillStyle = "#999999";
        ctx.textAlign = "center";
        ctx.font = `bold ${Math.max(12, barHeight * 0.25)}px "Courier New", Courier, monospace`;
        ctx.fillText(`CAM A   [ FOV: ${(zoom * 100).toFixed(0)}% ]   STUDIO LENS   ISO 800   NEW YEAR PREVIEW COMP`, viewerWidth / 2, viewerHeight - barHeight / 2);
    }
    
    // Core interactivity & animation logic
    // We use an interval to drive timecode without spinning an endless heavy requestAnimationFrame
    const clockInterval = setInterval(() => {
        // Discard gracefully if DOM node dies and passes ~5s lifecycle buffer
        if (!canvas.isConnected && (Date.now() - initTime > 5000)) {
            clearInterval(clockInterval);
            return;
        }
        blinkRec = !blinkRec;
        draw();
    }, 500);

    // Initial draw
    draw();

    // Mapping mouse events to pan original source gracefully over viewport
    canvas.addEventListener("mousedown", (e) => {
        isDragging = true;
        canvas.style.cursor = "grabbing";
        const rect = canvas.getBoundingClientRect();
        const scaleX = canvas.width / rect.width;
        const scaleY = canvas.height / rect.height;
        startX = (e.clientX - rect.left) * scaleX - panX;
        startY = (e.clientY - rect.top) * scaleY - panY;
    });
    
    canvas.addEventListener("mousemove", (e) => {
        if (!isDragging) return;
        const rect = canvas.getBoundingClientRect();
        const scaleX = canvas.width / rect.width;
        const scaleY = canvas.height / rect.height;
        panX = (e.clientX - rect.left) * scaleX - startX;
        panY = (e.clientY - rect.top) * scaleY - startY;
        draw();
    });
    
    canvas.addEventListener("mouseup", () => {
        isDragging = false;
        canvas.style.cursor = "grab";
    });
    
    canvas.addEventListener("mouseleave", () => {
        isDragging = false;
        canvas.style.cursor = "grab";
    });
    
    // Add graceful touch gestures support
    canvas.addEventListener("touchstart", (e) => {
        e.preventDefault();
        isDragging = true;
        const rect = canvas.getBoundingClientRect();
        const scaleX = canvas.width / rect.width;
        const scaleY = canvas.height / rect.height;
        startX = (e.touches[0].clientX - rect.left) * scaleX - panX;
        startY = (e.touches[0].clientY - rect.top) * scaleY - panY;
    }, {passive: false});

    canvas.addEventListener("touchmove", (e) => {
        e.preventDefault();
        if (!isDragging) return;
        const rect = canvas.getBoundingClientRect();
        const scaleX = canvas.width / rect.width;
        const scaleY = canvas.height / rect.height;
        panX = (e.touches[0].clientX - rect.left) * scaleX - startX;
        panY = (e.touches[0].clientY - rect.top) * scaleY - startY;
        draw();
    }, {passive: false});

    canvas.addEventListener("touchend", () => {
        isDragging = false;
    });
    
    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

The New Year Movie Company Studio Overview Image Viewer is an interactive tool designed to transform static images into a cinematic studio preview experience. It applies a professional 16:9 cinematic aspect ratio, a cold color grade, and a dynamic snow/bokeh overlay to create a festive, high-production atmosphere. The viewer features an immersive camera HUD (Heads-Up Display) including a blinking ‘REC’ indicator, a running timecode, viewfinder brackets, and technical metadata overlays. Users can interact with the image through panning and zooming gestures, making it ideal for presentation purposes, creative storytelling, or adding a themed, cinematic flair to studio concept art and photography.

Leave a Reply

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