You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, gridColumns = "16", gridRows = "16", explosionDepth = "300", speedMs = "5000") {
// Parse parameters
const cols = Math.max(1, parseInt(gridColumns, 10) || 16);
const rows = Math.max(1, parseInt(gridRows, 10) || 16);
const depth = parseInt(explosionDepth, 10) || 300;
const speed = parseInt(speedMs, 10) || 5000;
// Constrain image size to maximize performance
const maxW = 500;
const maxH = 500;
let imgW = originalImg.width;
let imgH = originalImg.height;
let scale = 1;
if (imgW > maxW || imgH > maxH) {
scale = Math.min(maxW / imgW, maxH / imgH);
imgW = Math.round(imgW * scale);
imgH = Math.round(imgH * scale);
}
// Draw to an offscreen canvas to extract pixel colors if possible
const cvs = document.createElement('canvas');
cvs.width = imgW;
cvs.height = imgH;
const ctx = cvs.getContext('2d');
ctx.drawImage(originalImg, 0, 0, imgW, imgH);
let imgData;
let bgUrl;
try {
imgData = ctx.getImageData(0, 0, imgW, imgH).data;
bgUrl = cvs.toDataURL(); // Avoid CORS taint in CSS if possible
} catch (e) {
bgUrl = originalImg.src; // Fallback to raw src URL
}
// Base container wrapping the animation
const container = document.createElement('div');
container.style.cssText = `
position: relative;
width: 100%;
height: ${imgH + 300}px;
background: radial-gradient(circle at center, #2b2b36 0%, #111118 100%);
display: flex;
align-items: center;
justify-content: center;
perspective: 1200px;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
`;
// Overlay to sell the "Planner" vibe
const uiInfo = document.createElement('div');
uiInfo.style.cssText = `
position: absolute;
top: 20px;
left: 20px;
color: #00ffcc;
background: rgba(0, 0, 0, 0.7);
padding: 10px 18px;
border-radius: 6px;
border: 1px solid rgba(0, 255, 204, 0.3);
font-size: 13px;
letter-spacing: 0.5px;
z-index: 10;
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
`;
uiInfo.innerHTML = `
<div style="font-size: 15px; margin-bottom: 5px; font-weight: bold; text-transform: uppercase;">3D Layout Animation Planner</div>
<div style="color: #ccc;">Grid Density: ${cols}x${rows}</div>
<div style="color: #ccc;">Z-Space Depth: ${depth}px</div>
<div style="color: #ccc;">Cycle Duration: ${speed / 1000}s</div>
`;
container.appendChild(uiInfo);
// 3D Scene Wrapper
const scene = document.createElement('div');
scene.style.cssText = `
position: relative;
width: ${imgW}px;
height: ${imgH}px;
transform-style: preserve-3d;
`;
const tileW = imgW / cols;
const tileH = imgH / rows;
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
let brightness = 0.5; // Default middle-ground
if (imgData) {
// Sample center point of each rectangle
let cx = Math.floor(c * tileW + tileW / 2);
let cy = Math.floor(r * tileH + tileH / 2);
let idx = (cy * imgW + cx) * 4;
brightness = (imgData[idx] + imgData[idx + 1] + imgData[idx + 2]) / (3 * 255);
}
const tile = document.createElement('div');
// Tile base styling creates a modular planner grid aesthetic
tile.style.cssText = `
position: absolute;
left: ${Math.floor(c * tileW)}px;
top: ${Math.floor(r * tileH)}px;
width: ${Math.ceil(tileW)}px;
height: ${Math.ceil(tileH)}px;
background-image: url(${bgUrl});
background-size: ${imgW}px ${imgH}px;
background-position: -${Math.floor(c * tileW)}px -${Math.floor(r * tileH)}px;
background-repeat: no-repeat;
transform-style: preserve-3d;
border: 0.5px solid rgba(255, 255, 255, 0.15);
box-sizing: border-box;
`;
// Layout Planner Math Logic (Mapping Z depth based on image brightness map)
// Lighter portions of the image push forward, darker portions recede.
let zTarget = (brightness * depth) - (depth / 2);
// Give them a slight rotation mapped to their spatial coordinates
let rotXTarget = ((r / rows) - 0.5) * -20;
let rotYTarget = ((c / cols) - 0.5) * 20;
// Stagger animation based on position for a wave effect
let delayTime = (c + (rows - r)) * (speed / (cols + rows)) * 0.4;
// Apply Web Animations API keyframes
tile.animate([
{ transform: 'translate3d(0, 0, 0) rotateX(0deg) rotateY(0deg)', border: '0.5px solid rgba(255,255,255,0)' },
{ transform: `translate3d(0px, 0px, ${zTarget}px) rotateX(${rotXTarget}deg) rotateY(${rotYTarget}deg)`, border: '0.5px solid rgba(0, 255, 204, 0.4)' },
{ transform: 'translate3d(0, 0, 0) rotateX(0deg) rotateY(0deg)', border: '0.5px solid rgba(255,255,255,0)' }
], {
duration: speed,
iterations: Infinity,
easing: 'ease-in-out',
delay: delayTime
});
scene.appendChild(tile);
}
}
// Give the entire scene a slow continuous panoramic rotation
scene.animate([
{ transform: 'rotateX(8deg) rotateY(-25deg)' },
{ transform: 'rotateX(-5deg) rotateY(25deg)' },
{ transform: 'rotateX(8deg) rotateY(-25deg)' }
], {
duration: speed * 1.8,
iterations: Infinity,
easing: 'ease-in-out'
});
container.appendChild(scene);
return container;
}
Apply Changes