You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, intensity = 1.0, colorShift = 5, showVHSOverlay = 1) {
// Ensure parameters are numbers
intensity = parseFloat(intensity);
colorShift = parseInt(colorShift, 10);
showVHSOverlay = parseInt(showVHSOverlay, 10);
const canvas = document.createElement('canvas');
const w = originalImg.width;
const h = originalImg.height;
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
// Draw solid black background in case of transparent image
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, w, h);
ctx.drawImage(originalImg, 0, 0);
// 1. Apply Glitched Block Shifts (Tracking Distortion)
const numShifts = Math.floor(20 * intensity);
for (let i = 0; i < numShifts; i++) {
const y = Math.random() * h;
// Slice height varies between 2px and 5% of height
const sliceHeight = Math.random() * (h * 0.05) + 2;
const shiftMax = w * 0.05 * intensity;
const shiftX = (Math.random() - 0.5) * shiftMax;
ctx.drawImage(canvas, 0, y, w, sliceHeight, shiftX, y, w, sliceHeight);
// Wrap around the shifted boundary to fill transparency gaps
if (shiftX < 0) {
ctx.drawImage(canvas, 0, y, w, sliceHeight, w + shiftX, y, w, sliceHeight);
} else {
ctx.drawImage(canvas, 0, y, w, sliceHeight, shiftX - w, y, w, sliceHeight);
}
}
// 2. Pixel Manipulation (Chromatic Aberration, Noise, Scanlines)
const imgData = ctx.getImageData(0, 0, w, h);
const data = imgData.data;
const outData = new Uint8ClampedArray(data);
const shiftAmount = Math.floor(colorShift * intensity);
for (let y = 0; y < h; y++) {
const isScanline = (y % 3 === 0);
// Create a horizontal wave tracking band near the bottom
const wave = Math.sin(y * 0.05) * 15;
const isTrackingBand = (y > h * 0.88 + wave && y < h * 0.95);
for (let x = 0; x < w; x++) {
const i = (y * w + x) * 4;
// Chromatic Aberration: Shift Red left, Blue right
const rx = Math.max(0, x - shiftAmount);
const bx = Math.min(w - 1, x + shiftAmount);
const ri = (y * w + rx) * 4;
const bi = (y * w + bx) * 4;
let r = data[ri];
let g = data[i + 1]; // Green stays in place
let b = data[bi + 2];
// Color grading: boost greens, drop blues to look washed out/magnetic
g = Math.min(255, g * 1.05);
b = b * 0.95;
// CRT Scanlines: Darken specific rows
if (isScanline) {
r *= 0.85;
g *= 0.85;
b *= 0.85;
}
// Add Static / Noise
let noiseProb = 0.03 * intensity;
if (isTrackingBand) noiseProb = 0.4 * intensity; // High noise in tracking band
if (Math.random() < noiseProb) {
const noise = (Math.random() - 0.5) * 120 * intensity;
r = Math.min(255, Math.max(0, r + noise));
g = Math.min(255, Math.max(0, g + noise));
b = Math.min(255, Math.max(0, b + noise));
}
outData[i] = r;
outData[i + 1] = g;
outData[i + 2] = b;
outData[i + 3] = 255; // Set solid alpha
}
}
// Apply edited pixels back onto canvas
imgData.data.set(outData);
ctx.putImageData(imgData, 0, 0);
// 3. Add CRT Vignette Darkening effect
const gradient = ctx.createRadialGradient(
w / 2, h / 2, Math.max(w, h) * 0.35,
w / 2, h / 2, Math.max(w, h) * 0.75
);
gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
gradient.addColorStop(1, 'rgba(0, 0, 0, 0.6)');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, w, h);
// 4. VHS "PLAY" and Timestamp Text Overlay
if (showVHSOverlay === 1) {
const fontSize = Math.max(16, Math.floor(h * 0.05));
ctx.font = `bold ${fontSize}px "Courier New", Courier, monospace`;
ctx.textBaseline = 'top';
// Add fake CRT screen glow
ctx.shadowColor = 'rgba(255, 255, 255, 0.8)';
ctx.shadowBlur = Math.max(2, Math.floor(h * 0.01));
ctx.fillStyle = '#ffffff';
// Add some slight text jitter down or right for extra aesthetic effect
const textJitterX = (Math.random() - 0.5) * 3 * intensity;
const textJitterY = (Math.random() - 0.5) * 3 * intensity;
ctx.fillText("PLAY ►", w * 0.05 + textJitterX, h * 0.05 + textJitterY);
ctx.textBaseline = 'bottom';
ctx.fillText("SP 0:00:00", w * 0.05 + textJitterX, h * 0.95 + textJitterY);
// Reset Shadow
ctx.shadowBlur = 0;
}
return canvas;
}
Apply Changes