You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, intensity = 1, addFur = "true", addMoon = "true", addClawMarks = "true", hiddenEyes = "true") {
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 the original image first
ctx.drawImage(originalImg, 0, 0);
const intens = Math.min(1, Math.max(0, Number(intensity) || 1));
const doFur = String(addFur).toLowerCase() === "true";
const doMoon = String(addMoon).toLowerCase() === "true";
const doClaws = String(addClawMarks).toLowerCase() === "true";
const doEyes = String(hiddenEyes).toLowerCase() === "true";
// 1. Draw coarse fur streaks (before night color grading so it blends nicely)
if (doFur) {
ctx.save();
const numHairs = Math.floor((w * h) / 600); // density of fur
ctx.strokeStyle = 'rgba(10, 10, 10, 0.5)';
ctx.lineCap = 'round';
for (let i = 0; i < numHairs; i++) {
let x = Math.random() * w;
let y = Math.random() * h;
// Short thick strokes resembling coarse werewolf hair
let len = 10 + Math.random() * 30;
ctx.lineWidth = 1 + Math.random() * 2;
let angle = (Math.PI / 2) + (Math.random() * 0.8 - 0.4); // mostly downward flowing
ctx.beginPath();
ctx.moveTo(x, y);
ctx.quadraticCurveTo(
x + Math.cos(angle - 0.3) * len * 0.5,
y + Math.sin(angle - 0.3) * len * 0.5,
x + Math.cos(angle) * len,
y + Math.sin(angle) * len
);
ctx.stroke();
}
ctx.restore();
}
// 2. Pixel manipulation for Moonlight & Beast Vision (Vignette & Contrast)
const imageData = ctx.getImageData(0, 0, w, h);
const data = imageData.data;
const cx = w / 2;
const cy = h / 2;
const maxDist = Math.sqrt(cx * cx + cy * cy);
// variables to find the perfect shadow for hidden glowing eyes
let eyeX = cx, eyeY = cy;
if (doEyes) {
let minLum = 255;
// Sample points in the lower/darker regions of the image to hide the beast
for (let k = 0; k < 100; k++) {
let px = Math.floor(w * 0.15 + Math.random() * w * 0.7);
let py = Math.floor(h * 0.4 + Math.random() * h * 0.5);
let idx = (py * w + px) * 4;
let lum = 0.299 * data[idx] + 0.587 * data[idx+1] + 0.114 * data[idx+2];
if (lum < minLum) {
minLum = lum;
eyeX = px;
eyeY = py;
}
}
}
// Apply the moonlit night filter
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// standard luminance
let lum = 0.299 * r + 0.587 * g + 0.114 * b;
// Cinematic moonlight mapping (deep blues and cyans)
let moonR = lum * 0.25;
let moonG = lum * 0.45;
let moonB = lum * 0.70 + 30;
let outR = r * (1 - intens) + moonR * intens;
let outG = g * (1 - intens) + moonG * intens;
let outB = b * (1 - intens) + moonB * intens;
// Contrast boost for a dramatic, feral vibe
let contrastAmt = 1 + (0.5 * intens);
outR = (outR - 128) * contrastAmt + 128;
outG = (outG - 128) * contrastAmt + 128;
outB = (outB - 128) * contrastAmt + 128;
// Dark heavy vignette
let px = (i / 4) % w;
let py = Math.floor((i / 4) / w);
let dist = Math.sqrt((px - cx) ** 2 + (py - cy) ** 2);
let vignette = 1 - (dist / maxDist) * (0.85 * intens);
data[i] = Math.min(255, Math.max(0, outR * vignette));
data[i + 1] = Math.min(255, Math.max(0, outG * vignette));
data[i + 2] = Math.min(255, Math.max(0, outB * vignette));
}
ctx.putImageData(imageData, 0, 0);
// 3. Draw Hidden Glowing Beast Eyes
if (doEyes) {
const eyeSpacing = Math.max(w, h) * 0.035;
const eyeSize = Math.max(w, h) * 0.007;
ctx.save();
ctx.shadowColor = '#FF8800'; // menacing amber/orange glow
ctx.shadowBlur = eyeSize * 6;
ctx.fillStyle = '#FFFDEE';
// Left Eye (angled inward for an angry scowl)
ctx.save();
ctx.translate(eyeX - eyeSpacing / 2, eyeY);
ctx.rotate(0.15);
ctx.beginPath();
if (ctx.ellipse) {
ctx.ellipse(0, 0, eyeSize, eyeSize * 0.35, 0, 0, Math.PI * 2);
} else {
ctx.arc(0, 0, eyeSize * 0.6, 0, Math.PI * 2); // fallback
}
ctx.fill();
ctx.restore();
// Right Eye
ctx.save();
ctx.translate(eyeX + eyeSpacing / 2, eyeY);
ctx.rotate(-0.15);
ctx.beginPath();
if (ctx.ellipse) {
ctx.ellipse(0, 0, eyeSize, eyeSize * 0.35, 0, 0, Math.PI * 2);
} else {
ctx.arc(0, 0, eyeSize * 0.6, 0, Math.PI * 2); // fallback
}
ctx.fill();
ctx.restore();
ctx.restore();
}
// 4. Draw Full Moon Overlay
if (doMoon) {
ctx.save();
ctx.globalCompositeOperation = 'screen';
const moonRadius = Math.min(w, h) * 0.12;
const moonX = w * 0.85;
const moonY = h * 0.15;
// Halo / Glow
const gradient = ctx.createRadialGradient(moonX, moonY, moonRadius * 0.8, moonX, moonY, moonRadius * 4);
gradient.addColorStop(0, 'rgba(230, 240, 255, 1)');
gradient.addColorStop(0.2, 'rgba(100, 150, 255, 0.4)');
gradient.addColorStop(1, 'rgba(0, 0, 50, 0)');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(moonX, moonY, moonRadius * 4, 0, Math.PI * 2);
ctx.fill();
// Moon Body
ctx.fillStyle = '#F0F5FF';
ctx.beginPath();
ctx.arc(moonX, moonY, moonRadius, 0, Math.PI * 2);
ctx.fill();
// Crater textures onto the moon
ctx.globalCompositeOperation = 'multiply';
ctx.fillStyle = 'rgba(0, 0, 0, 0.15)';
ctx.beginPath();
ctx.arc(moonX - moonRadius * 0.2, moonY + moonRadius * 0.2, moonRadius * 0.3, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(moonX + moonRadius * 0.4, moonY - moonRadius * 0.3, moonRadius * 0.2, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(moonX + moonRadius * 0.1, moonY + moonRadius * 0.4, moonRadius * 0.25, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
// 5. Draw Feral Glowing Claw Marks
if (doClaws) {
ctx.save();
ctx.globalCompositeOperation = 'screen';
const startX = w * 0.15;
const startY = h * 0.25;
const endX = w * 0.85;
const endY = h * 0.85;
ctx.shadowColor = '#FF0000';
ctx.shadowBlur = Math.min(w, h) * 0.025;
ctx.fillStyle = '#FFDDDD'; // super hot core
const numClaws = 4; // 4 claw mark tears
const spacing = Math.min(w, h) * 0.08;
const dx = endX - startX;
const dy = endY - startY;
const len = Math.sqrt(dx * dx + dy * dy);
const perpX = -dy / len;
const perpY = dx / len;
for (let i = 0; i < numClaws; i++) {
let offset = (i - (numClaws - 1) / 2) * spacing;
// Randomize individual claw slice lengths/positions slightly
let rx1 = startX + perpX * offset + (Math.random() - 0.5) * spacing;
let ry1 = startY + perpY * offset + (Math.random() - 0.5) * spacing;
let rx2 = endX + perpX * offset + (Math.random() - 0.5) * spacing;
let ry2 = endY + perpY * offset + (Math.random() - 0.5) * spacing;
let bdx = rx2 - rx1;
let bdy = ry2 - ry1;
let dist = Math.sqrt(bdx * bdx + bdy * bdy);
let angle = Math.atan2(bdy, bdx);
let bowOffset = spacing * 0.3;
let thickness = spacing * 0.15;
ctx.save();
ctx.translate(rx1, ry1);
ctx.rotate(angle);
// Draw a fierce, jagged laceration
ctx.beginPath();
ctx.moveTo(0, 0);
// Arc forward, tearing deep
ctx.quadraticCurveTo(dist * 0.35, -bowOffset - thickness, dist, 0);
// Arc back, closing the wound
ctx.quadraticCurveTo(dist * 0.65, -bowOffset + thickness * 0.2, 0, 0);
ctx.fill();
ctx.restore();
}
ctx.restore();
}
return canvas;
}
Apply Changes