Reaction-diffusion · deepseek-chat
Run a Gray-Scott reaction-diffusion simulation on a canvas that grows organic Turing patterns in real time, with the mouse seeding new growth.
This one-shot run produced no runnable artifact.
agent produced no index.html
The transcript below shows what the model did — read it to see why the one shot fell short.
transcript · 2 messages
Run a Gray-Scott reaction-diffusion simulation on a canvas that grows organic Turing patterns in real time, with the mouse seeding new growth.
Here's a single-file web app that implements a Gray-Scott reaction-diffusion simulation with mouse interaction to seed new growth. The simulation runs in real-time on an HTML canvas, and clicking on the canvas will seed new growth at the mouse position. html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Gray-Scott Reaction-Diffusion</title> <style> body { margin: 0; overflow: hidden; background: #222; display: flex; justify-content: center; align-items: center; height: 100vh; font-family: Arial, sans-serif; } canvas { display: block; cursor: crosshair; } .controls { position: absolute; top: 10px; left: 10px; color: white; background: rgba(0, 0, 0, 0.5); padding: 10px; border-radius: 5px; } </style> </head> <body> <div class="controls"> <div>Click/tap to seed new growth</div> </div> <canvas id="canvas"></canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); let width, height; let resolution = 1; // Lower = higher resolution // Simulation parameters (Gray-Scott model) const feed = 0.055; const kill = 0.062; const diffusionA = 1.0; const diffusionB = 0.5; const dt = 1.0; // Grids for the simulation let gridA; let gridB; let nextA; let nextB; function init() { width = Math.floor(window.innerWidth / resolution); height = Math.floor(window.innerHeight / resolution); canvas.width = width; canvas.height = height; // Initialize grids gridA = new Array(width * height).fill(1.0); gridB = new Array(width * height).fill(0.0); nextA = new Array(width * height).fill(0.0); nextB = new Array(width * height).fill(0.0); // Seed with some random spots for (let i = 0; i < 10; i++) { const x = Math.floor(Math.random() * width); const y = Math.floor(Math.random() * height); seedSpot(x, y, 5); } // Start simulation loop requestAnimationFrame(update); } function seedSpot(x, y, radius) { const radiusSq = radius * radius; for (let dy = -radius; dy <= radius; dy++) { for (let dx = -radius; dx <= radius; dx++) { const distSq = dx * dx + dy * dy; if (distSq <= radiusSq) { const nx = x + dx; const ny = y + dy; if (nx >= 0 && nx < width && ny >= 0 && ny < height) { const idx = nx + ny * width; gridB[idx] = 1.0; } } } } } function update() { for (let y = 1; y < height - 1; y++) { for (let x = 1; x < width - 1; x++) { const idx = x + y * width; const a = gridA[idx]; const b = gridB[idx]; // Laplacian calculation (diffusion) let laplaceA = 0; let laplaceB = 0; laplaceA += a * -1; laplaceB += b * -1; laplaceA += gridA[idx + 1] * 0.2; laplaceA += gridA[idx - 1] * 0.2; laplaceA += gridA[idx + width] * 0.2; laplaceA += gridA[idx - width] * 0.2; laplaceA += gridA[idx + 1 + width] * 0.05; laplaceA += gridA[idx - 1 + width] * 0.05; laplaceA += gridA[idx + 1 - width] * 0.05; laplaceA += gridA[idx - 1 - width] * 0.05; laplaceB += gridB[idx + 1] * 0.2; laplaceB += gridB[idx - 1] * 0.2; laplaceB += gridB[idx + width] * 0.2; laplaceB += gridB[idx - width] * 0.2; laplaceB += gridB[idx + 1 + width] * 0.05; laplaceB += gridB[idx - 1 + width] * 0.05; laplaceB += gridB[idx + 1 - width] * 0.05; laplaceB += gridB[idx - 1 - width] * 0.05; // Gray-Scott equations const reaction = a * b * b; nextA[idx] = a + (diffusionA * laplaceA - reaction + feed * (1 - a)) * dt; nextB[idx] = b + (diffusionB * laplaceB + reaction - (feed + kill) * b) * dt; // Clamp values nextA[idx] = Math.max(0, Math.min(1, nextA[idx])); nextB[idx] = Math.max(0, Math.min(1, nextB[idx])); } } // Swap grids [gridA, nextA] = [nextA, gridA]; [gridB, nextB] = [nextB, gridB]; // Render render(); requestAnimationFrame(update); } function render() { const imageData = ctx.createImageData(width, height); const data = imageData.data; for (let i = 0; i < gridA.length; i++) { const a = gridA[i]; const b = gridB[i]; const col = Math.floor(b * 255); // Simple coloring based on B concentration data[i * 4] = col; data[i * 4 + 1] = col; data[i * 4 + 2] = col; data[i * 4 + 3] = 255; } ctx.putImageData(imageData, 0, 0); } // Mouse interaction canvas.addEventListener('mousedown', (e) => { const rect = canvas.getBoundingClientRect(); const x = Math.floor((e.clientX - rect.left) / resolution); const y = Math.floor((e.clientY - rect.top) / resolution); seedSpot(x, y, 10); }); // Touch interaction for mobile canvas.addEventListener('touchstart', (e) => { e.preventDefault(); const rect = canvas.getBoundingClientRect(); const x = Math.floor((e.touches[0].clientX - rect.left) / resolution); const y = Math.floor((e.touches[0].clientY - rect.top) / resolution); seedSpot(x, y, 15); }); window.addEventListener('resize', init); init(); </script> </body> </html> This creates a minimal web app that: 1. Runs a Gray-Scott reaction-diffusion simulation in real-time 2. Renders the results to a full-screen canvas 3. Allows you to seed new growth by clicking/tapping anywhere 4. Works on both desktop and mobile devices You can adjust the `feed` and `kill` parameters to create different patterns (try values between 0.02 and 0.08). The coloring is simple grayscale based on the concentration of chemical B - feel free to modify the render function for more colorful displays.
TAKE IT TO CODE
This run produced no artifact — reuse the prompt with a different model or your own pi-agent run.