Please bookmark this page to avoid losing your image tool!

Vita-Boy Major Image Effect 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, style = "gameboy", pixelSize = 4, crtDistortion = 0.05) {
    const canvas = document.createElement('canvas');
    const w = originalImg.width;
    const h = originalImg.height;
    canvas.width = w;
    canvas.height = h;

    // Use WebGL for a high-performance, single-pass CRT & Pixelation effect
    const gl = canvas.getContext('webgl', { preserveDrawingBuffer: true }) || 
               canvas.getContext('experimental-webgl', { preserveDrawingBuffer: true });

    if (!gl) {
        // Graceful fallback if WebGL is unavailable
        const ctx = canvas.getContext('2d');
        ctx.drawImage(originalImg, 0, 0);
        return canvas;
    }

    // Vertex Shader: Standard Fullscreen Quad
    const vsSource = `
        attribute vec2 a_position;
        attribute vec2 a_texCoord;
        varying vec2 v_texCoord;
        void main() {
            gl_Position = vec4(a_position, 0.0, 1.0);
            v_texCoord = a_texCoord;
        }
    `;

    // Fragment Shader: Applies Vita-Boy / Retro CRT / Pixel Effects in a single pass
    const fsSource = `
        precision mediump float;
        varying vec2 v_texCoord;
        uniform sampler2D u_image;
        
        uniform float u_pixelSize;
        uniform float u_distortion;
        uniform float u_style; // 0=Color, 1=PipBoy, 2=VirtualBoy, 3=GameBoy
        uniform vec2 u_resolution;

        // Barrel Distortion to simulate curved CRT screens
        vec2 crtDistortion(vec2 coord, float bend) {
            vec2 cc = coord * 2.0 - 1.0;
            float r2 = cc.x*cc.x + cc.y*cc.y;
            cc *= 1.0 + bend * r2;
            return cc * 0.5 + 0.5;
        }

        void main() {
            vec2 coord = crtDistortion(v_texCoord, u_distortion);

            // Black out pixels outside the distorted curvature edges
            if (coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0) {
                gl_FragColor = vec4(0.04, 0.05, 0.04, 1.0);
                return;
            }

            // Downsample simulation (Pixelation)
            vec2 pxSize = max(vec2(1.0), vec2(u_pixelSize));
            vec2 screenPx = coord * u_resolution;
            // Snap to block centers for perfectly sharp retro pixels
            vec2 snappedPx = floor(screenPx / pxSize) * pxSize + (pxSize * 0.5);
            vec2 pixelatedCoord = snappedPx / u_resolution;

            vec4 texColor = texture2D(u_image, pixelatedCoord);
            float lum = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));
            vec3 finalColor;

            // Apply selected retro console style aesthetics
            if (u_style < 0.5) { 
                // 0: Color (Retro 8-bit System Vibrant)
                float levels = 6.0;
                finalColor = floor(texColor.rgb * levels + 0.5) / levels;
                // Vibrance boost
                finalColor = mix(vec3(lum), finalColor, 1.4);
            } else if (u_style < 1.5) { 
                // 1: Pip-Boy (Amber/Green Glowing Terminals)
                lum = clamp((lum - 0.05) * 1.3, 0.0, 1.0);
                vec3 tint = vec3(0.2, 1.0, 0.2); // Green Phosphor
                finalColor = tint * lum + tint * (lum * lum * 0.5); // Add CRT glow
            } else if (u_style < 2.5) { 
                // 2: Virtual-Boy (Red Glowing Terminals)
                lum = clamp((lum - 0.05) * 1.3, 0.0, 1.0);
                vec3 tint = vec3(1.0, 0.1, 0.15); // Red Phosphor
                finalColor = tint * lum + tint * (lum * lum * 0.5);
            } else { 
                // 3: Vita-/Game-Boy (Classic 4-Shade Green LCD)
                if (lum < 0.25) finalColor = vec3(15.0, 56.0, 15.0) / 255.0; // Darkest
                else if (lum < 0.5) finalColor = vec3(48.0, 98.0, 48.0) / 255.0;  // Dark
                else if (lum < 0.75) finalColor = vec3(139.0, 172.0, 15.0) / 255.0; // Light
                else finalColor = vec3(155.0, 188.0, 15.0) / 255.0; // Lightest
            }

            // High-resolution scanline simulation mapped precisely over retro pixels
            float py = coord.y * u_resolution.y;
            float sSize = max(2.0, pxSize.y * 2.0); // Scanline width matches retro block height
            float scanline = sin(py * 3.14159265 * 2.0 / sSize);
            
            float darken = 1.0;
            if (u_style < 2.5) { 
                // Heavy scanlines for CRT-based devices/systems
                darken = scanline > 0.0 ? 1.0 : 0.6;
            } else { 
                // Very subtle scanlines mimicking LCD pixel grid gaps
                darken = scanline > 0.0 ? 1.0 : 0.85;
            }

            // Screen edge vignette
            vec2 cc = v_texCoord * 2.0 - 1.0;
            float dist = length(cc);
            float vignette = 1.0 - smoothstep(0.6, 1.4, dist);

            finalColor *= darken * vignette;

            gl_FragColor = vec4(clamp(finalColor, 0.0, 1.0), 1.0);
        }
    `;

    function compileShader(glContext, type, source) {
        const shader = glContext.createShader(type);
        glContext.shaderSource(shader, source);
        glContext.compileShader(shader);
        if (!glContext.getShaderParameter(shader, glContext.COMPILE_STATUS)) {
            console.error('Shader compilation failed:', glContext.getShaderInfoLog(shader));
            glContext.deleteShader(shader);
            return null;
        }
        return shader;
    }

    const vs = compileShader(gl, gl.VERTEX_SHADER, vsSource);
    const fs = compileShader(gl, gl.FRAGMENT_SHADER, fsSource);
    const program = gl.createProgram();
    
    gl.attachShader(program, vs);
    gl.attachShader(program, fs);
    gl.linkProgram(program);

    // Buffers layout: Triangles spanning -1 to 1 perfectly covering the viewport
    const positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        -1.0, -1.0,   1.0, -1.0,  -1.0,  1.0,
        -1.0,  1.0,   1.0, -1.0,   1.0,  1.0,
    ]), gl.STATIC_DRAW);

    const texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
         0.0,  0.0,   1.0,  0.0,   0.0,  1.0,
         0.0,  1.0,   1.0,  0.0,   1.0,  1.0,
    ]), gl.STATIC_DRAW);

    // Original Image ingestion as Texture
    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    
    // Load texture data, wrapped in try-catch in case of CORS security errors
    try {
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, originalImg);
    } catch (err) {
        console.error("Could not load image onto webgl texture", err);
        return canvas;
    }

    gl.viewport(0, 0, w, h);
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.useProgram(program);

    // Attribute Pointers
    const posLoc = gl.getAttribLocation(program, "a_position");
    gl.enableVertexAttribArray(posLoc);
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);

    const texLoc = gl.getAttribLocation(program, "a_texCoord");
    gl.enableVertexAttribArray(texLoc);
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.vertexAttribPointer(texLoc, 2, gl.FLOAT, false, 0, 0);

    // Resolve Style Setting
    let styleNum = 3; 
    const sStr = String(style).toLowerCase();
    if (sStr === 'color') styleNum = 0;
    else if (sStr === 'pipboy' || sStr === 'green') styleNum = 1;
    else if (sStr === 'virtualboy' || sStr === 'red') styleNum = 2;
    else if (sStr === 'gameboy') styleNum = 3;

    // Send Uniforms
    gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), w, h);
    gl.uniform1f(gl.getUniformLocation(program, "u_style"), styleNum);
    
    let pSize = parseFloat(pixelSize);
    if (isNaN(pSize) || pSize < 1) pSize = 4.0;
    gl.uniform1f(gl.getUniformLocation(program, "u_pixelSize"), pSize);
    
    let distort = parseFloat(crtDistortion);
    if (isNaN(distort)) distort = 0.05;
    gl.uniform1f(gl.getUniformLocation(program, "u_distortion"), distort);

    // Execute Pass
    gl.drawArrays(gl.TRIANGLES, 0, 6);

    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 Vita-Boy Major Image Effect Generator is a specialized tool designed to transform standard images into retro-style graphics reminiscent of classic gaming consoles. It allows users to apply various nostalgic aesthetics, including vibrant 8-bit color modes, green phosphor terminal effects (Pip-Boy style), red monochrome displays (VirtualBoy style), and classic four-shade green LCD looks (GameBoy style). The tool enhances the retro feel by incorporating pixelation, CRT-style barrel distortion, scanlines, and vignette effects. This tool is ideal for digital artists, game developers, or anyone looking to create themed social media content, retro-inspired assets, or stylized nostalgic artwork.

Leave a Reply

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

Other Image Tools:

Cringle Major Image Effect Generator

Batch Chroma Key Background Remover and Green Spill Eliminator

Photo Background and Green Particle Remover While Preserving Hair

Photorealistic California Driver License Generator

California Driver’s License Photorealistic Image Generator

California Driver License Photorealistic Image Generator

Photorealistic California Driver’s License Image Generator

California Driver’s License Security Template Generator

Blank California Driver License Security Background Template Creator

California State Driver License Image Creator

California Driver License Realism Enhancer

California State ID Card Generator Tool

California State ID Card Generator for Ronald Sanchez

Image To Mp3 Audio Player

Android Ringtone MP3 Audio Player

Android Ringtone MP3 Audio Track Recorder and Player

AI Werewolf Transformation Image Generator

Photo To Werewolf Transformer

Image To Werewolf Transformation Tool

Television Icon Image

Expired Film Effect Photo Filter

Image To Realistic iPhone Style JPEG Converter With Custom Metadata

Explosive Apocalypse Image Generator

Unknown Description Tool

Unknown Cartoon Character Identifier

Image Crazy TV Channel Mania Filter

Image Mad TV Channel Mania Effect Generator

Image To Konekts TV Branding Tool

Unrecognizable TV Channel Image Generator

Autumn Leaves Image Generator

Unknown Tool Description

Video First Frame Extractor and Image Resizer

Google Image Search Tool

Google Search Topic Web Interface Image Tool

Image Aspect Ratio 2.55:1 Stretch Version Converter

Video Aspect Ratio Changer To 2.55:1

See All →