Please bookmark this page to avoid losing your image tool!

Image To Motion Vector Art 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, gridSize = "15", style = "Trails", colorTheme = "Original", lengthScale = "2", backgroundColor = "#0b0b1a") {
    // Parse parameters
    const d = parseInt(gridSize, 10) || 15;
    const lenMult = parseFloat(lengthScale) || 2;
    const styleMode = (style || 'Trails').toLowerCase();
    const theme = (colorTheme || 'Original').toLowerCase();
    const bgColor = backgroundColor || '#0b0b1a';

    const w = originalImg.width;
    const h = originalImg.height;

    // Source canvas to extract pixel data
    const srcCanvas = document.createElement('canvas');
    srcCanvas.width = w;
    srcCanvas.height = h;
    const srcCtx = srcCanvas.getContext('2d', { willReadFrequently: true });
    srcCtx.drawImage(originalImg, 0, 0);
    const imgData = srcCtx.getImageData(0, 0, w, h);
    const data = imgData.data;

    // Output canvas
    const outCanvas = document.createElement('canvas');
    outCanvas.width = w;
    outCanvas.height = h;
    const outCtx = outCanvas.getContext('2d');

    // Fill background
    outCtx.fillStyle = bgColor;
    outCtx.fillRect(0, 0, w, h);

    // Helper to get brightness at a pixel coordinate out of the linear image data array
    const getBrightness = (x, y) => {
        // Clamp coordinates to image boundaries
        const cx = x < 0 ? 0 : (x >= w ? w - 1 : x);
        const cy = y < 0 ? 0 : (y >= h ? h - 1 : y);
        const i = (cy * w + cx) * 4;
        // Standard relative luminance formula
        return 0.299 * data[i] + 0.587 * data[i+1] + 0.114 * data[i+2];
    };

    // 'Span' adds spatial smoothing to the gradient calculation based on the grid spacing
    const span = Math.max(1, Math.floor(d / 4));

    // Calculate angular direction & magnitude based on pixel gradients
    const getAngleAndMag = (x, y) => {
        const ix = Math.floor(x);
        const iy = Math.floor(y);
        const dx = getBrightness(ix + span, iy) - getBrightness(ix - span, iy);
        const dy = getBrightness(ix, iy + span) - getBrightness(ix, iy - span);
        return {
            angle: Math.atan2(dy, dx) + Math.PI / 2, // Add 90 degrees (PI/2) to flow vectors along the contours/edges
            mag: Math.sqrt(dx*dx + dy*dy)
        };
    };

    const getColor = (x, y, angle) => {
        const cx = Math.floor(x < 0 ? 0 : (x >= w ? w - 1 : x));
        const cy = Math.floor(y < 0 ? 0 : (y >= h ? h - 1 : y));
        const i = (cy * w + cx) * 4;

        if (theme === 'monochrome') {
            return '#ffffff';
        } else if (theme === 'neon' || theme === 'rainbow') {
            const hue = (((angle * 180 / Math.PI) % 360) + 360) % 360; // Normalize the angle to be strictly 0-360
            return `hsl(${hue}, 80%, 65%)`;
        } else {
            // Original colors
            return `rgb(${data[i]}, ${data[i+1]}, ${data[i+2]})`;
        }
    };

    const step = Math.max(2, d);
    const baseLen = step * lenMult;

    // Output stroke settings
    outCtx.lineWidth = Math.max(0.5, step * 0.15);
    outCtx.lineCap = 'round';
    outCtx.lineJoin = 'round';

    // Set global alpha to make overlapping sections blend fluidly
    outCtx.globalAlpha = styleMode === 'trails' ? 0.6 : 0.85;

    for (let y = step / 2; y < h; y += step) {
        for (let x = step / 2; x < w; x += step) {
            const { angle, mag } = getAngleAndMag(x, y);

            // Skip drawing in extremely flat areas to preserve structural contrast of the picture,
            // but keep it if rendering pure neon fields.
            if (mag < 2 && theme !== 'neon') continue;

            const color = getColor(x, y, angle);
            const halfLen = baseLen / 2;

            outCtx.strokeStyle = color;
            outCtx.fillStyle = color;

            if (styleMode === 'trails') {
                let px = x;
                let py = y;
                
                outCtx.beginPath();
                outCtx.moveTo(px, py);
                
                // Generate fluid trail (continuous vector curves)
                const maxSteps = Math.min(150, Math.floor(baseLen * 2));
                for (let s = 0; s < maxSteps; s++) {
                    const localParams = getAngleAndMag(px, py);
                    // Trace forward per step
                    px += Math.cos(localParams.angle) * 1.5;
                    py += Math.sin(localParams.angle) * 1.5;
                    outCtx.lineTo(px, py);
                    
                    if (px < 0 || px >= w || py < 0 || py >= h) break;
                }
                outCtx.stroke();
            } else {
                // Render singular geometric elements per cell
                outCtx.save();
                outCtx.translate(x, y);
                outCtx.rotate(angle);

                if (styleMode === 'arrows') {
                    outCtx.beginPath();
                    outCtx.moveTo(-halfLen, 0);
                    outCtx.lineTo(halfLen, 0);
                    // Arrow head calculation
                    const headSize = Math.max(2, halfLen * 0.35);
                    outCtx.lineTo(halfLen - headSize, -headSize * 0.6);
                    outCtx.moveTo(halfLen, 0);
                    outCtx.lineTo(halfLen - headSize, headSize * 0.6);
                    outCtx.stroke();
                } else if (styleMode === 'particles' || styleMode === 'dots') {
                    outCtx.beginPath();
                    // Directional particle streak
                    outCtx.ellipse(0, 0, halfLen, Math.max(1, step * 0.1), 0, 0, Math.PI * 2);
                    outCtx.fill();
                } else {
                    // Default behavior (styleMode === 'lines' or undefined)
                    outCtx.beginPath();
                    outCtx.moveTo(-halfLen, 0);
                    outCtx.lineTo(halfLen, 0);
                    outCtx.stroke();
                }

                outCtx.restore();
            }
        }
    }

    return outCanvas;
}

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 standard images into artistic motion vector graphics by analyzing pixel gradients to create fluid, directional patterns. Users can convert images into various visual styles such as flowing trails, geometric arrows, particles, or dots, which follow the contours and edges of the original subject. With customizable options for grid density, line length, and color themes—including original colors, monochrome, neon, or rainbow modes—it is an ideal tool for graphic designers and digital artists looking to create abstract backgrounds, dynamic textures, or unique stylistic interpretations of photographs.

Leave a Reply

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