You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, targetName = "X", textColor = "#ff0000", effectIntensity = "50") {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
// Parse effect intensity
let intensity = parseInt(effectIntensity);
if (isNaN(intensity)) intensity = 50;
// Normalize intensity between 0 and 1
const normIntensity = Math.min(100, Math.max(0, intensity)) / 100;
// 1. Apply dark and desaturated cinematic filter to original image
ctx.filter = `contrast(${1 + 0.6 * normIntensity}) saturate(${1 - 0.7 * normIntensity}) brightness(${1 - 0.3 * normIntensity})`;
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
ctx.filter = 'none';
// 2. Apply Glitch (Chromatic Aberration) and Noise ("Lossy" / "Losky" vibe)
const glitchAmount = normIntensity * (canvas.width * 0.015);
if (normIntensity > 0) {
const idata = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = idata.data;
const copyData = new Uint8ClampedArray(data);
const shift = Math.floor(glitchAmount);
const shiftOffset = shift * 4;
for (let y = 0; y < canvas.height; y++) {
for (let x = 0; x < canvas.width; x++) {
const i = (y * canvas.width + x) * 4;
const noise = (Math.random() - 0.5) * 60 * normIntensity;
let r = data[i];
let g = data[i+1];
let b = data[i+2];
// Simple horizontal RGB shift simulating a glitch/VHS lossy effect
if (shift > 0) {
if (x + shift < canvas.width) {
r = copyData[i + shiftOffset]; // Shift red channel left
}
if (x - shift >= 0) {
b = copyData[i - shiftOffset + 2]; // Shift blue channel right
}
}
// Add randomized noise and assign channels
data[i] = Math.min(255, Math.max(0, r + noise));
data[i+1] = Math.min(255, Math.max(0, g + noise));
data[i+2] = Math.min(255, Math.max(0, b + noise));
}
}
ctx.putImageData(idata, 0, 0);
}
// 3. Apply heavy Vignette around the edges to focus on the center
const cx = canvas.width / 2;
const cy = canvas.height / 2;
const radius = Math.max(cx, cy);
const gradient = ctx.createRadialGradient(cx, cy, radius * 0.2, cx, cy, radius * 1.5);
gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
gradient.addColorStop(1, `rgba(0, 0, 0, ${0.9 * normIntensity})`);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 4. Optionally draw some "VHS scratches" across the screen
if (normIntensity > 0) {
ctx.fillStyle = `rgba(255, 255, 255, ${0.1 * normIntensity})`;
for (let i = 0; i < 6; i++) {
const y = Math.random() * canvas.height;
const h = Math.random() * 3 + 1;
ctx.fillRect(0, y, canvas.width, h);
}
}
// 5. Dynamic font loading (Creepster google font with safe fallback)
let fontFamily = 'Impact, sans-serif';
if (!document.getElementById('losky-creepster-font')) {
const link = document.createElement('link');
link.id = 'losky-creepster-font';
link.rel = 'stylesheet';
link.href = 'https://fonts.googleapis.com/css2?family=Creepster&display=swap';
document.head.appendChild(link);
}
try {
await document.fonts.load('10px "Creepster"');
if (document.fonts.check('10px "Creepster"')) {
fontFamily = '"Creepster", Impact, sans-serif';
}
} catch (e) {
// Ignored. Stays as Impact if font fails to fetch.
}
// 6. Draw "I KILLED X" text
const text = `I KILLED ${targetName}`.toUpperCase();
let fontSize = canvas.width * 0.15;
ctx.font = `${fontSize}px ${fontFamily}`;
// Scale down text if it happens to be too wide for the canvas
const maxTextWidth = canvas.width * 0.9;
const metrics = ctx.measureText(text);
if (metrics.width > maxTextWidth) {
fontSize = fontSize * (maxTextWidth / metrics.width);
ctx.font = `${fontSize}px ${fontFamily}`;
}
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Start with glowing shadow
ctx.shadowColor = textColor;
ctx.shadowBlur = Math.max(10, 25 * normIntensity);
ctx.fillStyle = textColor;
// Initial fill pass
ctx.fillText(text, cx, cy);
// Reset shadow for the sharp stroke
ctx.shadowBlur = 0;
// Black outline to make it pop and legible over dark patches
ctx.strokeStyle = 'black';
ctx.lineWidth = Math.max(2, fontSize * 0.04);
ctx.lineJoin = 'round';
ctx.strokeText(text, cx, cy);
// Final fill pass to cover any inner stroke bleed
ctx.fillText(text, cx, cy);
return canvas;
}
Apply Changes