You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, topText = "YOUR", middleText = "STUDIO", bottomText = "PRESENTS", monolithColor = "#e5b80b", skyColor = "#000033") {
const width = 1280;
const height = 720;
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Utility: ensure a valid #RRGGBB color
function normalizeColor(c) {
const temp = document.createElement('canvas').getContext('2d');
temp.fillStyle = c;
const hex = temp.fillStyle;
if (!/^#[0-9a-fA-F]{6}$/.test(hex)) return "#e5b80b";
return hex;
}
const gold = normalizeColor(monolithColor);
const sky = normalizeColor(skyColor);
// Utility: adjust hex color brightness
function shadeColor(color, percent) {
let R = parseInt(color.substring(1,3), 16);
let G = parseInt(color.substring(3,5), 16);
let B = parseInt(color.substring(5,7), 16);
R = parseInt(R * (100 + percent) / 100);
G = parseInt(G * (100 + percent) / 100);
B = parseInt(B * (100 + percent) / 100);
R = Math.max(0, Math.min(255, R));
G = Math.max(0, Math.min(255, G));
B = Math.max(0, Math.min(255, B));
const RR = (R.toString(16).length === 1 ? "0" : "") + R.toString(16);
const GG = (G.toString(16).length === 1 ? "0" : "") + G.toString(16);
const BB = (B.toString(16).length === 1 ? "0" : "") + B.toString(16);
return "#" + RR + GG + BB;
}
// 1. Draw Starry Night Sky
const skyGrad = ctx.createLinearGradient(0, 0, 0, height);
skyGrad.addColorStop(0, sky);
skyGrad.addColorStop(1, shadeColor(sky, -50));
ctx.fillStyle = skyGrad;
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = "#ffffff";
for (let i = 0; i < 250; i++) {
const x = Math.random() * width;
const y = Math.random() * height;
const r = Math.random() * 1.5;
const alpha = Math.random();
ctx.globalAlpha = alpha;
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fill();
}
ctx.globalAlpha = 1.0;
// Glowing aura behind monument
const aura = ctx.createRadialGradient(width/2, height/2 + 100, 100, width/2, height/2 + 100, 600);
aura.addColorStop(0, 'rgba(255, 255, 255, 0.15)');
aura.addColorStop(1, 'rgba(255, 255, 255, 0)');
ctx.fillStyle = aura;
ctx.fillRect(0, 0, width, height);
// 2. Draw Background Searchlights
function drawSpotlight(bx, by, tx1, tx2, alpha) {
ctx.save();
ctx.globalCompositeOperation = 'screen';
const grad = ctx.createLinearGradient(bx, by, (tx1+tx2)/2, 0);
grad.addColorStop(0, `rgba(255, 255, 255, ${alpha})`);
grad.addColorStop(1, 'rgba(255, 255, 255, 0)');
ctx.fillStyle = grad;
ctx.beginPath();
ctx.moveTo(bx, by);
ctx.lineTo(tx1, 0);
ctx.lineTo(tx2, 0);
ctx.closePath();
ctx.fill();
ctx.restore();
}
drawSpotlight(200, height, -100, 300, 0.5);
drawSpotlight(400, height, 100, 500, 0.4);
drawSpotlight(width/2, height, width/2 - 200, width/2 + 200, 0.6);
drawSpotlight(width - 400, height, width - 500, width - 100, 0.4);
drawSpotlight(width - 200, height, width - 300, width + 100, 0.5);
// 3. Set Up Monument Perspective (Looking down-left, with rightward slant)
ctx.save();
ctx.translate(width / 2, height / 2 + 50);
ctx.transform(1, -0.08, 0, 1, 0, 0); // subtle cinematic skew
// Dynamic Sizing based on text
const size1 = 60, size2 = 80, size3 = 100;
ctx.font = `bold ${size1}px Impact, sans-serif`;
const t1Width = ctx.measureText(topText).width;
ctx.font = `bold ${size2}px Impact, sans-serif`;
const t2Width = ctx.measureText(middleText).width;
ctx.font = `bold ${size3}px Impact, sans-serif`;
const t3Width = ctx.measureText(bottomText).width;
const maxImgW = 350;
const maxImgH = 200;
const imgScale = Math.min(maxImgW / originalImg.width, maxImgH / originalImg.height);
const imgW = originalImg.width * imgScale;
const imgH = originalImg.height * imgScale;
// Strict pyramidal hierarchy logic
const b0w = imgW + 40;
const b1w = Math.max(350, t1Width + 60, b0w + 40);
const b2w = Math.max(550, t2Width + 80, b1w + 40);
const b3w = Math.max(750, t3Width + 100, b2w + 40);
// 3D Rendering Utilities
function draw3DPlatform(x, y, w, h, depth) {
// Extrude down and left
for(let i = 0; i < depth; i++) {
const sx = x - i * 0.4;
const sy = y + i;
ctx.fillStyle = shadeColor(gold, - (i/depth) * 50 - 10);
ctx.fillRect(sx - w/2, sy - h/2, w, h);
}
// Top Face
const grad = ctx.createLinearGradient(0, y - h/2, 0, y + h/2);
grad.addColorStop(0, shadeColor(gold, 20));
grad.addColorStop(1, shadeColor(gold, -15));
ctx.fillStyle = grad;
ctx.fillRect(x - w/2, y - h/2, w, h);
ctx.strokeStyle = shadeColor(gold, 40);
ctx.lineWidth = 1.5;
ctx.strokeRect(x - w/2, y - h/2, w, h);
}
function draw3DText(text, x, y, size, depth) {
ctx.font = `bold ${size}px Impact, sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Extrude down and left
for(let i = 0; i < depth; i++) {
const sx = x - i * 0.4;
const sy = y + i;
ctx.fillStyle = shadeColor(gold, - (i/depth) * 50);
ctx.fillText(text, sx, sy);
}
// Front Face
const faceGrad = ctx.createLinearGradient(0, y - size/2, 0, y + size/2);
faceGrad.addColorStop(0, shadeColor(gold, 40));
faceGrad.addColorStop(0.5, gold);
faceGrad.addColorStop(1, shadeColor(gold, -20));
ctx.fillStyle = faceGrad;
ctx.fillText(text, x, y);
ctx.lineWidth = 1;
ctx.strokeStyle = shadeColor(gold, 60);
ctx.strokeText(text, x, y);
}
function draw3DBillboard(img, x, y, w, h, depth) {
draw3DPlatform(x, y, w, h, depth);
// Paint Image onto the face
ctx.drawImage(img, x - w/2 + 5, y - h/2 + 5, w - 10, h - 10);
}
// Draw objects from back (lowest Y visually) to front (highest Y visually)
// to naturally handle occlusions looking from a high isometric angle
// 1. Pedestal 4 (Bottom Base)
draw3DPlatform(0, 190, b3w, 40, 50);
// 2. Text 3 (Bottom Text)
if(bottomText.trim()) draw3DText(bottomText, 0, 130, size3, 30);
// 3. Pedestal 3
draw3DPlatform(0, 60, b2w, 20, 40);
// 4. Text 2 (Middle Text)
if(middleText.trim()) draw3DText(middleText, 0, 10, size2, 30);
// 5. Pedestal 2
draw3DPlatform(0, -50, b1w, 20, 40);
// 6. Text 1 (Top Text)
if(topText.trim()) draw3DText(topText, 0, -90, size1, 30);
// 7. Pedestal 1 (For image)
draw3DPlatform(0, -150, b0w + 40, 20, 40);
// 8. The Billboard Image
draw3DBillboard(originalImg, 0, -260, b0w, imgH + 20, 30);
ctx.restore();
// 4. Foreground Sweep Searchlight (overlays monument)
drawSpotlight(width + 100, height, width/2 - 300, width/2 + 50, 0.20);
return canvas;
}
Apply Changes