You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, title1 = "UNFRIENDED", title2 = "THE CONJURING", releaseDate = "IN THEATERS 2027", glitchIntensity = 5) {
// Dynamically inject fonts if they don't exist
if (!document.getElementById("conjuring-unfriended-fonts")) {
const fontLink = document.createElement("link");
fontLink.id = "conjuring-unfriended-fonts";
fontLink.href = "https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@700&family=Share+Tech+Mono&display=swap";
fontLink.rel = "stylesheet";
document.head.appendChild(fontLink);
}
// Wait for the fonts to be ready
try {
await document.fonts.load('80px "Cinzel Decorative"');
await document.fonts.load('80px "Share Tech Mono"');
await document.fonts.ready;
} catch (e) {
console.warn("Fonts may not have loaded correctly, falling back to system fonts.");
}
const intensity = Number(glitchIntensity) || 5;
// Create standard movie poster canvas (2:3 aspect ratio)
const canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 1200;
const ctx = canvas.getContext("2d");
// Calculate crop to cover the whole canvas
const targetRatio = canvas.width / canvas.height;
const imgRatio = originalImg.width / originalImg.height;
let sw, sh, sx, sy;
if (imgRatio > targetRatio) {
sh = originalImg.height;
sw = sh * targetRatio;
sx = (originalImg.width - sw) / 2;
sy = 0;
} else {
sw = originalImg.width;
sh = sw / targetRatio;
sx = 0;
sy = (originalImg.height - sh) / 2;
}
// 1. Draw original base image
ctx.drawImage(originalImg, sx, sy, sw, sh, 0, 0, canvas.width, canvas.height);
// 2. Pixel Manipulation: Glitch, Corrupt, Color Grade, and Vignette
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imgData.data;
const copyData = new Uint8ClampedArray(data);
const cx = canvas.width / 2;
const cy = canvas.height / 2;
const maxDist = Math.sqrt(cx * cx + cy * cy);
for (let y = 0; y < canvas.height; y++) {
// Random horizontal slice glitch
const isGlitchSlice = Math.random() < (0.01 * intensity);
const sliceShift = isGlitchSlice ? (Math.random() - 0.5) * 25 * intensity : 0;
for (let x = 0; x < canvas.width; x++) {
// Apply horizontal slice shift
let srcX = x + sliceShift;
if (srcX < 0) srcX = 0;
if (srcX >= canvas.width) srcX = canvas.width - 1;
// Chromatic aberration (RGB shift)
let rx = srcX + intensity * 1.5;
let bx = srcX - intensity * 1.5;
let gx = srcX;
if (rx >= canvas.width) rx = canvas.width - 1;
if (bx < 0) bx = 0;
const posR = (y * canvas.width + Math.floor(rx)) * 4;
const posG = (y * canvas.width + Math.floor(gx)) * 4;
const posB = (y * canvas.width + Math.floor(bx)) * 4;
let r = copyData[posR];
let g = copyData[posG + 1];
let b = copyData[posB + 2];
// Color Grading (Conjuring Style: Desaturated, moody green/blue tint)
const luminance = r * 0.3 + g * 0.59 + b * 0.11;
r = r * 0.3 + luminance * 0.7;
g = g * 0.3 + luminance * 0.7;
b = b * 0.3 + luminance * 0.7;
// Apply tint
r *= 0.65;
g *= 0.85;
b *= 0.95;
// Cinematic noise/grain
const noise = (Math.random() - 0.5) * 35;
r += noise;
g += noise;
b += noise;
// Strong Vignette
const dist = Math.sqrt((x - cx) ** 2 + (y - cy) ** 2);
const vignetteAmt = 1 - (dist / maxDist) * 0.85; // Edges will be 15% brightness
r *= vignetteAmt;
g *= vignetteAmt;
b *= vignetteAmt;
const i = (y * canvas.width + x) * 4;
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
data[i + 3] = 255;
}
}
ctx.putImageData(imgData, 0, 0);
// 3. Add CRT Scanlines
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
for (let i = 0; i < canvas.height; i += 4) {
ctx.fillRect(0, i, canvas.width, 1);
}
// Add cinematic bottom shadow gradient for text readability
const textGrad = ctx.createLinearGradient(0, 600, 0, 1200);
textGrad.addColorStop(0, 'transparent');
textGrad.addColorStop(0.7, 'rgba(0, 0, 0, 0.8)');
textGrad.addColorStop(1, '#000000');
ctx.fillStyle = textGrad;
ctx.fillRect(0, 600, canvas.width, 600);
// 4. Draw Webcam/Desktop UI Elements
ctx.textBaseline = 'middle';
// Top Left: REC
ctx.fillStyle = '#ff0000';
ctx.beginPath();
ctx.arc(60, 60, 8, 0, Math.PI * 2);
ctx.fill();
ctx.textAlign = 'left';
ctx.font = '24px "Share Tech Mono", monospace';
ctx.letterSpacing = '2px';
ctx.fillText("REC", 80, 62);
// Top Right: Camera info & Battery
ctx.textAlign = 'right';
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
ctx.fillText("CAM_VALAK", canvas.width - 90, 62);
ctx.strokeStyle = 'rgba(255, 255, 255, 0.8)';
ctx.lineWidth = 2;
ctx.strokeRect(canvas.width - 70, 52, 35, 18);
ctx.fillRect(canvas.width - 68, 54, 25, 14); // Battery partial level
// Central Creepy Chat Box Overlay
ctx.fillStyle = 'rgba(10, 15, 20, 0.8)';
const boxW = 550, boxH = 120;
const boxX = (canvas.width - boxW) / 2;
const boxY = (canvas.height - boxH) / 2 - 50;
ctx.fillRect(boxX, boxY, boxW, boxH);
ctx.strokeStyle = 'rgba(150, 0, 0, 0.5)';
ctx.lineWidth = 1;
ctx.strokeRect(boxX, boxY, boxW, boxH);
ctx.textAlign = 'center';
ctx.fillStyle = '#ffffff';
ctx.font = '26px "Share Tech Mono", monospace';
ctx.fillText("UNKNOWN_USER has joined the call.", canvas.width / 2, boxY + boxH / 2 - 15);
ctx.fillStyle = '#ff3333';
ctx.font = '20px "Share Tech Mono", monospace';
ctx.fillText("[ SUPERNATURAL INTERFERENCE ]", canvas.width / 2, boxY + boxH / 2 + 20);
// 5. Typography (Poster Titles & Text)
ctx.shadowColor = "rgba(0, 0, 0, 0.9)";
ctx.shadowBlur = 10;
ctx.textAlign = 'center';
// Top Header
ctx.font = '22px "Share Tech Mono", monospace';
ctx.fillStyle = '#cccccc';
ctx.letterSpacing = "6px";
ctx.fillText("A NEW CHAPTER IN DIGITAL TERROR", canvas.width / 2, 130);
// Main Movie Title 1: "UNFRIENDED"
ctx.font = 'bold 75px "Share Tech Mono", monospace';
ctx.fillStyle = '#ffffff';
ctx.letterSpacing = "15px";
ctx.fillText(title1.toUpperCase(), canvas.width / 2, 850);
// Main Movie Title 2: "THE CONJURING"
ctx.font = 'bold 85px "Cinzel Decorative", serif';
ctx.fillStyle = '#cc0000'; // Deep unholy red
ctx.letterSpacing = "8px";
ctx.fillText(title2.toUpperCase(), canvas.width / 2, 960);
ctx.shadowBlur = 0; // Turn off shadow
// Bottom Data / Release
ctx.font = '26px "Share Tech Mono", monospace';
ctx.fillStyle = '#888888';
ctx.letterSpacing = "8px";
ctx.fillText(releaseDate.toUpperCase(), canvas.width / 2, 1100);
// Clean up contextual styles
ctx.letterSpacing = "0px";
return canvas;
}
Apply Changes