Please bookmark this page to avoid losing your image tool!

Microscopic World 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, zoomLevel = 4, lensRadius = 250, reticleColor = "rgba(50, 255, 100, 0.6)") {
    const zoom = parseFloat(zoomLevel) || 4;
    const radius = parseFloat(lensRadius) || 250;
    
    // Create and configure the canvas
    const canvas = document.createElement('canvas');
    const width = radius * 2 + 120; // Extra padding for the border
    const height = radius * 2 + 120;
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');
    
    // UI Setup
    canvas.style.cursor = 'crosshair';
    canvas.style.maxWidth = '100%';
    canvas.style.height = 'auto';
    canvas.style.display = 'block';
    canvas.style.margin = '0 auto';
    canvas.style.boxShadow = '0 15px 35px rgba(0,0,0,0.8)';
    canvas.style.borderRadius = '15px';
    canvas.style.touchAction = 'none'; // Prevent scrolling on touch
    canvas.style.backgroundColor = '#000';

    // Viewer states
    let currentCX = originalImg.width / 2;
    let currentCY = originalImg.height / 2;
    let targetCX = currentCX;
    let targetCY = currentCY;
    let time = 0;

    // Generate procedural "bacteria" and "floaters" to sell the microscopic effect
    const floaters = [];
    for(let i = 0; i < 30; i++) {
        let angle = Math.random() * Math.PI * 2;
        let rad = Math.random() * radius * 0.95;
        floaters.push({
            x: Math.cos(angle) * rad,
            y: Math.sin(angle) * rad,
            r: Math.random() * 8 + 2,
            length: Math.random() * 15 + 5,
            angle: Math.random() * Math.PI,
            opacity: Math.random() * 0.4 + 0.05,
            speed: Math.random() * 0.05 + 0.01,
            offset: Math.random() * 100
        });
    }

    // Input handlers mapping mouse/touch to original image coordinates
    const updateTarget = (clientX, clientY) => {
        const rect = canvas.getBoundingClientRect();
        const scaleX = canvas.width / (rect.width || 1);
        const scaleY = canvas.height / (rect.height || 1);
        const x = (clientX - rect.left) * scaleX;
        const y = (clientY - rect.top) * scaleY;
        
        targetCX = (x / width) * originalImg.width;
        targetCY = (y / height) * originalImg.height;
    };

    canvas.addEventListener('mousemove', (e) => updateTarget(e.clientX, e.clientY));
    canvas.addEventListener('touchmove', (e) => {
        if (e.touches.length > 0) updateTarget(e.touches[0].clientX, e.touches[0].clientY);
    });

    // Render loop
    function render() {
        time += 0.04;
        
        // Smooth easing camera pan
        currentCX += (targetCX - currentCX) * 0.05;
        currentCY += (targetCY - currentCY) * 0.05;

        // 1. Clear background
        ctx.fillStyle = '#111';
        ctx.fillRect(0, 0, width, height);

        // 2. Open circular mask for the lens
        ctx.save();
        ctx.beginPath();
        ctx.arc(width/2, height/2, radius, 0, Math.PI*2);
        ctx.clip();

        // Dark background for transparent areas of the image
        ctx.fillStyle = '#050505';
        ctx.fill();

        // 3. Draw the scaled and panned original image
        ctx.save();
        ctx.translate(width/2, height/2);
        ctx.scale(zoom, zoom);
        
        // Add a very subtle organic jiggle to the "sample"
        let jx = Math.sin(time) * 1.2;
        let jy = Math.cos(time * 0.7) * 1.2;
        
        // We draw the image so that the focus point is positioned at (0, 0)
        ctx.drawImage(originalImg, -currentCX + jx, -currentCY + jy);
        ctx.restore();

        // 4. Lighting / Vignette
        const vignette = ctx.createRadialGradient(width/2, height/2, radius * 0.1, width/2, height/2, radius);
        vignette.addColorStop(0, 'rgba(255, 255, 255, 0.02)');
        vignette.addColorStop(0.5, 'rgba(10, 50, 40, 0.15)'); // Slight bioluminescent tint
        vignette.addColorStop(0.9, 'rgba(0, 0, 0, 0.6)');
        vignette.addColorStop(1, 'rgba(0, 0, 0, 1)'); 
        ctx.fillStyle = vignette;
        ctx.fill(); // fills inside the clipped circle

        // 5. Draw drifting microscopic floaters (gives depth / lens dirt illusion)
        for(let i = 0; i < floaters.length; i++) {
            let f = floaters[i];
            let dx = Math.sin(time * f.speed + f.offset) * 20;
            let dy = Math.cos(time * f.speed * 0.8 + f.offset) * 20;
            let wobble = Math.sin(time * f.speed) * 0.3;

            ctx.save();
            ctx.translate(width/2 + f.x + dx, height/2 + f.y + dy);
            ctx.rotate(f.angle + wobble);
            
            // Soft blurry shadow to simulate out-of-focus optics
            ctx.shadowColor = `rgba(0, 0, 0, ${f.opacity})`;
            ctx.shadowBlur = f.r * 2.5;
            
            ctx.fillStyle = `rgba(0, 0, 0, ${f.opacity * 0.6})`;
            ctx.beginPath();
            ctx.ellipse(0, 0, f.length, f.r, 0, 0, Math.PI*2);
            ctx.fill();

            // Lighter center membrane
            ctx.fillStyle = `rgba(255, 255, 255, ${f.opacity * 0.3})`;
            ctx.shadowBlur = 0;
            ctx.beginPath();
            ctx.ellipse(0, 0, f.length * 0.5, f.r * 0.5, 0, 0, Math.PI*2);
            ctx.fill();

            ctx.restore();
        }

        // 6. Scientific Measurement Reticle overlay
        ctx.strokeStyle = reticleColor;
        ctx.shadowColor = reticleColor;
        ctx.shadowBlur = 4; // slight glow
        ctx.lineWidth = 1;

        const cross = 15;
        // Central target crosses
        ctx.beginPath();
        ctx.moveTo(width/2 - cross, height/2);
        ctx.lineTo(width/2 + cross, height/2);
        ctx.moveTo(width/2, height/2 - cross);
        ctx.lineTo(width/2, height/2 + cross);
        ctx.stroke();

        // Main axial lines extending outwards
        ctx.beginPath();
        ctx.moveTo(width/2 - radius, height/2);
        ctx.lineTo(width/2 - cross*2, height/2);
        ctx.moveTo(width/2 + cross*2, height/2);
        ctx.lineTo(width/2 + radius, height/2);
        ctx.moveTo(width/2, height/2 - radius);
        ctx.lineTo(width/2, height/2 - cross*2);
        ctx.moveTo(width/2, height/2 + cross*2);
        ctx.lineTo(width/2, height/2 + radius);
        ctx.stroke();

        // Peripheral radial ticks
        for(let i = 0; i < 360; i += 5) {
            let angle = i * Math.PI / 180;
            let tickLength = (i % 90 === 0) ? 25 : ((i % 10 === 0) ? 12 : 5);
            ctx.beginPath();
            ctx.moveTo(width/2 + Math.cos(angle) * (radius - tickLength), height/2 + Math.sin(angle) * (radius - tickLength));
            ctx.lineTo(width/2 + Math.cos(angle) * radius, height/2 + Math.sin(angle) * radius);
            ctx.stroke();
        }

        // Dashed concentric scale
        ctx.setLineDash([4, 6]);
        ctx.beginPath();
        ctx.arc(width/2, height/2, radius * 0.5, 0, Math.PI*2);
        ctx.stroke();
        ctx.setLineDash([]);
        
        ctx.shadowBlur = 0; // reset shadow
        ctx.restore(); // Ends the circular lens clip

        // 7. Outer eyepiece mask covering everything outside the circular lens
        ctx.fillStyle = '#080808';
        ctx.beginPath();
        ctx.rect(0, 0, width, height);
        ctx.arc(width/2, height/2, radius, 0, Math.PI*2, true);
        ctx.fill();

        // 8. Draw physical microscope lens rims
        // Thick metal-looking bezel edge
        const gradientRim = ctx.createLinearGradient(0, 0, width, height);
        gradientRim.addColorStop(0, '#222');
        gradientRim.addColorStop(0.5, '#050505');
        gradientRim.addColorStop(1, '#333');
        ctx.strokeStyle = gradientRim;
        ctx.lineWidth = 18;
        ctx.beginPath();
        ctx.arc(width/2, height/2, radius + 9, 0, Math.PI*2);
        ctx.stroke();
        
        // Inner shiny glass rim
        ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.arc(width/2, height/2, radius, 0, Math.PI*2);
        ctx.stroke();

        // Request next frame
        requestAnimationFrame(render);
    }
    
    // Kickstart recursive render
    render();
    
    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 Microscopic World Image Viewer is an interactive tool that simulates a microscope lens effect on any uploaded image. It creates a circular magnifying viewport that follows your cursor or touch input, featuring high-magnification zoom, a scientific reticle overlay, and dynamic visual effects like drifting microscopic floaters and organic movement to mimic a real biological sample under a lens. This tool can be used for creative digital art, educational demonstrations, or adding immersive, scientific-style visual effects to existing photographs.

Leave a Reply

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