GITHUB
API
GITHUB
API

VFX-JS is a JavaScript library to add WebGL-powered effects to your website.
You can easily attach it to normal <img>, <video> elements etc.

Usage

Install via npm:

npm i @vfx-js/core

Then create VFX object in your script:


import { VFX } from '@vfx-js/core';

const img = document.querySelector('#img');

const vfx = new VFX();
vfx.add(img, { shader: "glitch", overflow: 100 });
            

This will be rendered as follows:

VFX-JS is also available on CDNs (esm.sh or jsDeliver). So you can use VFX-JS in CodePen etc:


// Load VFX-JS from esm.sh
import { VFX } from "https://esm.sh/@vfx-js/core";

// or jsDeliver
// import { VFX } from 'https://cdn.jsdelivr.net/npm/@vfx-js/core/+esm'

// Then use VFX-JS
const vfx = new VFX();
vfx.add(img { shader: 'rgbShift' });
            

Examples

Image


<img src="example.png" />
                    

vfx.add(img, { shader: "rgbShift" });
                    

Output

GIF


<img src="example.gif" />
                    

vfx.add(gif, { shader: "rainbow" });
                    

Output

Video


<video src="example.mp4" autoplay loop muted/>
                    

vfx.add(video, { shader: "halftone" });
                    

Output:

Div (experimental)


<div id="div">
    <p>You can interact with these inputs.</p>
    <input type="text" value="Edit me" />
    <input type="range" min="0" max="100" value="0" />
    <textarea>Edit me</textarea>
</div>
                        

vfx.add(div, { shader: "rgbShift", overflow: 100 });

// Update on input
input.addEventListener('input', () => vfx.update(div));

// Update on textarea resize
const mo = new MutationObserver(() => vfx.update(div));
mo.observe(textarea, { attributes: true });

                    

Output:

You can interact with these inputs.

Canvas


<!--
  VFX-JS also supports HTMLCanvasElement as the input.
  You can draw 2D graphics and text in canvas,
  then pass it to VFX-JS to add post effects.
-->
<canvas id="canvas"/>
                        

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

function drawCanvas() {
    ...

    // Update texture when the canvas has been updated
    vfx.update(canvas);

    requestAnimationFrame(drawCanvas);
}
drawCanvas();

vfx.add(canvas, { shader });
                    

Output:

Presets


vfx.add(el, { shader: "rainbow" });
                    

vfx.add(el, { shader: "rgbShift" });
                        

// Some shaders require "overflow" property
// so that they can render beyond the original area.
//
// In this example, the "glitch" shader can render
// outside the original element up to 100px.
vfx.add(el, { shader: "glitch", overflow: 100 });
                        

Parameters

Some shaders take parameters (e.g. duotone). You can pass the params to the uniforms property.


vfx.add(el, {
    shader: "duotone",
    uniforms: {
        color1: [0, 0, 1, 1],
        color2: [0, 1, 0, 1],
        speed: 0.2
    }
});
                        

Transitions

VFX-JS presets for transition animation. These animation start when the element gets in the viewport.


vfx.add(el, { shader: "slitScanTransition" });
                        

vfx.add(el, { shader: "warpTransition" });
                        

vfx.add(el, { shader: "pixelateTransition" });
                        

vfx.add(el, { shader: "focusTransition" });
                        

Custom Shaders

You can write GLSL shader by yourself.


const shader = `
precision highp float;
uniform vec2 resolution;
uniform vec2 offset;
uniform float time;
uniform sampler2D src;
uniform float scroll;
out vec4 outColor;

void main (void) {
    vec2 uv = (gl_FragCoord.xy - offset) / resolution;

    // Scroll X
    uv.x = fract(uv.x + scroll + time * 0.2);

    outColor = texture2D(src, uv);
}
`;

vfx.add(el, {
    shader,
    uniforms: {
        // Uniform functions are evaluated every frame
        scroll: () => window.scrollY / window.innerHeight,
    }
});
                        

Multipass Shaders

You can chain multiple shader passes by passing an array of VFXPass objects. Each pass writes to a named buffer that subsequent passes can read.


// Pass 1: Blur the image into "blur" buffer
const blurPass = {
    frag: `
        precision highp float;
        uniform sampler2D src;
        uniform vec2 resolution;
        uniform vec2 offset;
        out vec4 outColor;
        void main() {
            vec2 uv = (gl_FragCoord.xy - offset)
                     / resolution;
            vec2 t = 4.0 / resolution;
            vec4 c = texture(src, uv) * 0.4;
            c += texture(src, uv+vec2(t.x,0))*.15;
            c += texture(src, uv-vec2(t.x,0))*.15;
            c += texture(src, uv+vec2(0,t.y))*.15;
            c += texture(src, uv-vec2(0,t.y))*.15;
            outColor = c;
        }
    `,
    target: "blur",
};

// Pass 2: Combine original + blurred for glow
const glowPass = {
    frag: `
        precision highp float;
        uniform sampler2D src;
        uniform sampler2D blur;
        uniform vec2 resolution;
        uniform vec2 offset;
        out vec4 outColor;
        void main() {
            vec2 uv = (gl_FragCoord.xy - offset)
                     / resolution;
            vec4 c = texture(src, uv);
            vec4 b = texture(blur, uv);
            outColor = c + b * 0.6;
        }
    `,
};

vfx.add(el, {
    shader: [blurPass, glowPass],
});
                        

Made by Amagi