mcmc-generator / Index.html
devinendorphin's picture
Update Index.html
961c25c verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MCMC Animation Generator (Stable Diffusion)</title>
<style>
body { background: #1e1e2e; color: white; font-family: sans-serif; }
canvas { background: black; display: block; margin: 10px auto; border: 2px solid #4ecdc4; }
.log { max-height: 200px; overflow-y: auto; font-family: monospace; font-size: 12px; background: #111; padding: 10px; border-radius: 10px; margin: 10px; }
</style>
</head>
<body>
<h1 style="text-align:center">MCMC Animation Generator (Stable Diffusion)</h1>
<div style="text-align:center">
<input type="text" id="prompt" placeholder="Prompt" value="A surreal dreamscape" />
<input type="number" id="seed" value="42" />
<button onclick="generateInitialImage()">Generate Image</button>
<button onclick="startAnimation()">Start Animation</button>
</div>
<canvas id="canvas" width="512" height="512"></canvas>
<div class="log" id="log"></div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const logEl = document.getElementById('log');
let state = {
currentPosition: Array.from({ length: 100 }, () => Math.random() * 2 - 1),
currentVelocity: Array(100).fill(0),
currentEnergy: 0,
baseImage: null, // This will now store a canvas element
seed: 42,
};
function log(msg) {
logEl.innerHTML += `[${new Date().toLocaleTimeString()}] ${msg}<br>`;
logEl.scrollTop = logEl.scrollHeight;
}
// This function is no longer needed as we're fetching from Stable Diffusion
// function generateMockImage(seed) { ... }
async function generateInitialImage() {
const prompt = document.getElementById('prompt').value;
const seed = parseInt(document.getElementById('seed').value);
state.seed = seed;
log('Generating image with Stable Diffusion...');
try {
const response = await fetch('
https://devinendorphin-mcmc-generator.hf.space/run/predict', { // REPLACE THIS URL
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: [prompt, seed] }),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || `HTTP error! status: ${response.status}`);
}
const result = await response.json();
// Assuming the image is returned as a base64 data URL (e.g., "data:image/png;base64,...")
const imageDataUrl = result.data[0];
const img = new Image();
img.src = imageDataUrl;
// Wait for the image to load before drawing
await new Promise((resolve) => { img.onload = resolve; });
// Clear the main canvas and draw the new image
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, 512, 512);
// Create a new canvas to store the base image for MCMC operations
state.baseImage = document.createElement('canvas');
state.baseImage.width = 512;
state.baseImage.height = 512;
const baseCtx = state.baseImage.getContext('2d');
baseCtx.drawImage(img, 0, 0, 512, 512);
const imageData = ctx.getImageData(0, 0, 512, 512);
state.currentEnergy = calculateEnergy(imageData);
log('Stable Diffusion image loaded and energy calculated.');
} catch (e) {
log('Error using Hugging Face Space: ' + e.message);
}
}
function calculateEnergy(imageData) {
let energy = 0;
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const intensity = (data[i] + data[i + 1] + data[i + 2]) / 3;
energy += Math.pow(intensity - 128, 2) * 0.00001;
}
return energy;
}
function generateImageVariation(base, params) {
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
const ctx = canvas.getContext('2d');
ctx.drawImage(base, 0, 0); // 'base' is now a canvas element
const imgData = ctx.getImageData(0, 0, 512, 512);
const data = imgData.data;
for (let i = 0; i < data.length; i += 4) {
const p = params[Math.floor((i / 4) % 100)];
data[i] += p * 10;
data[i + 1] += p * 5;
data[i + 2] += p * 15;
}
ctx.putImageData(imgData, 0, 0);
return canvas;
}
function calculateGradient(position, baseImage) {
const epsilon = 0.01;
const grad = new Array(position.length).fill(0);
for (let i = 0; i < position.length; i++) {
const posPlus = [...position];
const posMinus = [...position];
posPlus[i] += epsilon;
posMinus[i] -= epsilon;
const imgPlus = generateImageVariation(baseImage, posPlus);
const imgMinus = generateImageVariation(baseImage, posMinus);
const energyPlus = calculateEnergy(imgPlus.getContext('2d').getImageData(0, 0, 512, 512));
const energyMinus = calculateEnergy(imgMinus.getContext('2d').getImageData(0, 0, 512, 512));
grad[i] = (energyPlus - energyMinus) / (2 * epsilon);
}
return grad;
}
async function startAnimation() {
if (!state.baseImage) return log('No base image loaded. Please generate an image first.');
log('Starting animation...');
const T = 1.0, stepSize = 0.01, damping = 0.5;
for (let frame = 0; frame < 30; frame++) {
const grad = calculateGradient(state.currentPosition, state.baseImage);
const newVelocity = state.currentVelocity.map((v, i) => v - stepSize * (grad[i] + damping * v) + (Math.random() * 2 - 1) * Math.sqrt(2 * damping * T * stepSize));
const newPosition = state.currentPosition.map((x, i) => x + stepSize * newVelocity[i]);
const proposedImage = generateImageVariation(state.baseImage, newPosition);
const proposedEnergy = calculateEnergy(proposedImage.getContext('2d').getImageData(0, 0, 512, 512));
let accept = false;
if (proposedEnergy <= state.currentEnergy) accept = true;
else if (Math.random() < Math.exp(-(proposedEnergy - state.currentEnergy) / T)) accept = true;
if (accept) {
state.currentPosition = newPosition;
state.currentVelocity = newVelocity;
state.currentEnergy = proposedEnergy;
ctx.drawImage(proposedImage, 0, 0);
log(`Frame ${frame + 1}: Accepted, Energy: ${proposedEnergy.toFixed(4)}`);
} else {
log(`Frame ${frame + 1}: Rejected`);
}
await new Promise(res => setTimeout(res, 50));
}
log('Animation complete.');
}
</script>
</body>
</html>