<canvas class="view"></canvas>
<script id="backgroundFragment" type="x-shader/x-fragment">
// Adapted from: https://www.shadertoy.com/view/MdlGRr
// It is required to set the float precision for fragment shaders in OpenGL ES
// More info here: https://stackoverflow.com/a/28540641/4908989
#ifdef GL_ES
precision mediump float;
#endif
// This function returns 1 if `coord` correspond to a grid line, 0 otherwise
float isGridLine (vec2 coord) {
vec2 pixelsPerGrid = vec2(50.0, 50.0);
vec2 gridCoords = fract(coord / pixelsPerGrid);
vec2 gridPixelCoords = gridCoords * pixelsPerGrid;
vec2 gridLine = step(gridPixelCoords, vec2(1.0));
float isGridLine = max(gridLine.x, gridLine.y);
return isGridLine;
}
// Main function
void main () {
// Coordinates for the current pixel
vec2 coord = gl_FragCoord.xy;
// Set `color` to black
vec3 color = vec3(0.0);
// If it is a grid line, change blue channel to 0.3
color.b = isGridLine(coord) * 0.3;
// Assing the final rgba color to `gl_FragColor`
gl_FragColor = vec4(color, 1.0);
}
</script>
<script id="stageFragment" type="x-shader/x-fragment">
// Adapted from: https://www.shadertoy.com/view/4lSGRw
#ifdef GL_ES
precision mediump float;
#endif
// Uniforms from Javascript
uniform vec2 uResolution;
uniform float uPointerDown;
// The texture is defined by PixiJS
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
// Function used to get the distortion effect
vec2 computeUV (vec2 uv, float k, float kcube) {
vec2 t = uv - 0.5;
float r2 = t.x * t.x + t.y * t.y;
float f = 0.0;
if (kcube == 0.0) {
f = 1.0 + r2 * k;
} else {
f = 1.0 + r2 * (k + kcube * sqrt(r2));
}
vec2 nUv = f * t + 0.5;
nUv.y = 1.0 - nUv.y;
return nUv;
}
void main () {
// Normalized coordinates
vec2 uv = gl_FragCoord.xy / uResolution.xy;
// Settings for the effect
// Multiplied by `uPointerDown`, a value between 0 and 1
float k = -1.0 * uPointerDown;
float kcube = 0.5 * uPointerDown;
float offset = 0.02 * uPointerDown;
// Get each channel's color using the texture provided by PixiJS
// and the `computeUV` function
float red = texture2D(uSampler, computeUV(uv, k + offset, kcube)).r;
float green = texture2D(uSampler, computeUV(uv, k, kcube)).g;
float blue = texture2D(uSampler, computeUV(uv, k - offset, kcube)).b;
// Assing the final rgba color to `gl_FragColor`
gl_FragColor = vec4(red, green, blue, 1.0);
}
</script>
body {
margin: 0;
overflow: hidden;
background-color: black;
}
View Compiled
(function() {
// Get canvas view
const view = document.querySelector('.view')
// Loaded resources will be here
const resources = PIXI.Loader.shared.resources
// Target for pointer. If down, value is 1, else value is 0
// Here we set it to 1 to see the effect, but initially it will be 0
let pointerDownTarget = 1
let width, height, app, background, uniforms
// Set dimensions
function initDimensions () {
width = window.innerWidth
height = window.innerHeight
}
// Set initial values for uniforms
function initUniforms () {
uniforms = {
uResolution: new PIXI.Point(width, height),
uPointerDown: pointerDownTarget
}
}
// Init the PixiJS Application
function initApp () {
// Create a PixiJS Application, using the view (canvas) provided
app = new PIXI.Application({ view })
// Resizes renderer view in CSS pixels to allow for resolutions other than 1
app.renderer.autoDensity = true
// Resize the view to match viewport dimensions
app.renderer.resize(width, height)
// Set the distortion filter for the entire stage
const stageFragmentShader = document.getElementById('stageFragment').textContent
const stageFilter = new PIXI.Filter(undefined, stageFragmentShader, uniforms)
app.stage.filters = [stageFilter]
}
// Init the gridded background
function initBackground () {
// Create a new empty Sprite and define its size
background = new PIXI.Sprite()
background.width = width
background.height = height
// Get the code for the fragment shader from the loaded resources
const backgroundFragmentShader = document.getElementById('backgroundFragment').textContent
// Create a new Filter using the fragment shader
// We don't need a custom vertex shader, so we set it as `undefined`
const backgroundFilter = new PIXI.Filter(undefined, backgroundFragmentShader)
// Assign the filter to the background Sprite
background.filters = [backgroundFilter]
// Add the background to the stage
app.stage.addChild(background)
}
// Init everything
function init () {
initDimensions()
initUniforms()
initApp()
initBackground()
}
// Init the app
init()
})()
This Pen doesn't use any external CSS resources.