You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, intensity = "20", fps = "15") {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
// Parse parameters
const intensityNum = parseFloat(intensity) || 20;
const fpsNum = parseFloat(fps) || 15;
const intervalMs = 1000 / fpsNum;
let framesNotConnected = 0;
function renderGlitch() {
// Prevent memory leaks if the canvas is removed from the DOM
if (!canvas.isConnected) {
framesNotConnected++;
// Stop animating if unbound for more than roughly 5 seconds
if (framesNotConnected > (fpsNum * 5)) return;
} else {
framesNotConnected = 0;
}
ctx.globalAlpha = 1.0;
ctx.globalCompositeOperation = 'source-over';
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw the base original image
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Randomly skip processing a frame to show normal un-glitched image occasionally
if (Math.random() < 0.15) {
setTimeout(renderGlitch, intervalMs);
return;
}
// Effect 1: Global Chromatic Aberration / Color Flash Effect
if (Math.random() > 0.8) {
const shiftX = (Math.random() - 0.5) * intensityNum * 3;
const shiftY = (Math.random() - 0.5) * Math.min(10, intensityNum);
ctx.globalAlpha = 0.7;
ctx.globalCompositeOperation = 'screen';
ctx.drawImage(originalImg, shiftX, shiftY, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'overlay';
const flashColors = ['rgba(255, 0, 0, 0.5)', 'rgba(0, 255, 255, 0.5)', 'rgba(0, 255, 0, 0.5)'];
ctx.fillStyle = flashColors[Math.floor(Math.random() * flashColors.length)];
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalAlpha = 1.0;
ctx.globalCompositeOperation = 'source-over';
}
// Effect 2: Horizontal Glitch Slices
const maxSlices = Math.floor((Math.random() * 20 * intensityNum) / 20) + 1;
const totalSlices = Math.floor(Math.random() * maxSlices);
for (let i = 0; i < totalSlices; i++) {
const sliceY = Math.random() * canvas.height;
const sliceH = Math.random() * (canvas.height / 6);
const isMajorGlitch = Math.random() > 0.85;
const offsetX = (Math.random() - 0.5) * intensityNum * (isMajorGlitch ? 4 : 1.5);
// Randomly colorize a slice for VHS channel-shift effect
if (Math.random() > 0.65) {
ctx.save();
ctx.beginPath();
ctx.rect(0, sliceY, canvas.width, sliceH);
ctx.clip();
ctx.drawImage(originalImg, offsetX, 0, canvas.width, canvas.height);
const sliceColors = [
'rgba(255, 0, 0, 0.4)',
'rgba(0, 255, 255, 0.4)',
'rgba(0, 255, 0, 0.4)',
'rgba(255, 0, 255, 0.4)'
];
ctx.fillStyle = sliceColors[Math.floor(Math.random() * sliceColors.length)];
ctx.globalCompositeOperation = 'source-over';
ctx.fillRect(0, sliceY, canvas.width, sliceH);
ctx.restore();
} else {
// Direct positional shift for slice
ctx.drawImage(
originalImg,
0, sliceY, canvas.width, sliceH, // Source parameters
offsetX, sliceY, canvas.width, sliceH // Destination parameters
);
}
}
// Effect 3: CRT TV Analog Scanlines overlay
if (Math.random() > 0.4) {
ctx.fillStyle = `rgba(0, 0, 0, 0.15)`;
const scanlineHeight = Math.max(1, Math.floor(canvas.height / 250));
const step = scanlineHeight * 2;
for (let y = 0; y < canvas.height; y += step) {
ctx.fillRect(0, y, canvas.width, scanlineHeight);
}
}
// Effect 4: V-sync stutter (slight vertical mis-alignment frame)
if (Math.random() > 0.96) {
const shiftY = (Math.random() - 0.5) * (canvas.height * 0.1);
ctx.save();
ctx.globalAlpha = 0.6;
ctx.drawImage(originalImg, 0, shiftY, canvas.width, canvas.height);
ctx.restore();
}
// Schedule next glitch frame
setTimeout(renderGlitch, intervalMs);
}
// Start playing the glitch animation loop
renderGlitch();
return canvas;
}
Apply Changes