oneshotlm
Compare all models on this prompt →

Mandelbrot explorer · grok-4.20

Render the Mandelbrot set with a smooth color gradient on a full-screen canvas, with click-and-drag to pan and mouse-wheel to zoom.

⛨ sandboxed Open in new tab ↗
transcript · 11 messages
user

Render the Mandelbrot set with a smooth color gradient on a full-screen canvas, with click-and-drag to pan and mouse-wheel to zoom.

assistant
thinking
The task is to build a single-page web app that renders the Mandelbrot set with a smooth color gradient on a full-screen canvas. It should support click-and-drag to pan and mouse-wheel to zoom. Everyt...The task is to create a single-page web app in one index.html file that renders the Mandelbrot set with smooth coloring on a full-screen canvas, with click-and-drag panning and mouse-wheel zooming. No external resources, CSS in <style>, JS in <script>.

I need to implement:

- Full-screen 2D canvas.

- Mandelbrot rendering with smooth color gradient based on escape time.

- Pan: click and drag.

- Zoom: mouse wheel.

- Probably reset button or double-click to reset view.

- Keep it self-contained.

Recall Mandelbrot: for c = x + yi, iterate z = z 2 + c, z0=0, if |z| > 2 after max_iter, escapes.

For smooth: use fractional iteration count.

Standard smooth coloring: mu = n + 1 - log(log(|z|))/log(2), where n is integer iter when |z|>2.

Then color 0 to 255 based on mu mod 1 or use hue = mu * factor.

For gradient, use HSL with hue based on mu.

In JS, for each pixel, compute iter and smooth, then set pixel color.

For efficiency: use ImageData, loop over pixels, compute.

Initial view: center around 0,0 with scale to show -2 to 1 on x, -1.5 to 1.5 on y.

Variables: centerX, centerY, zoomFactor (where higher zoom means smaller range).

Scale = pixels per complex unit.

Let's define:

- centerX, centerY: complex center 0+0i

- scale: complex units per pixel (initial ~0.01 or so)

Better: zoom = units per pixel, initial 0.005 for full view.

For full screen say 1920x1080, to cover x range 3.5 units, scale = 3. 5 / 1920 ~0.0018 units/pixel.

But to make initial fixed, use fixed range and adjust center and range.

Let's go with:

let centerX = -0.75;

let centerY = 0;

let zoom = 1; // zoom=1 initial, zoom >1 zoomed in

Then viewWidth = 3 / zoom; // adjust to cover

For standard, viewWidth = 3.5 / zoom; to have range 3.5 when zoom=1.

For y, same but aspect adjusted.

For wheel: zoom *= 1.2 or 0.8 depending on direction (wheel up zoom in).

For direction: wheel deltaY positive down, but usually wheel up zooms in.

For pan: on drag, deltaX * (viewWidth / w) to update centerX -= deltaX * scaleX

Yes.

For color: use a function to map smooth iter 0 to max to color.

Let's use HSV: hue = (smooth * 0.1) % 1 , saturation 1, value 1 or something.

Then rgb = hsv2rgb(hue,1,1)

I need to implement hsv to rgb.

Yes, standard function.

For black 0 when not escaped.

If iter >= maxIter, color black.

Set maxIter = 100 or 200.

For full screen, to avoid slow, but for task ok.

Also add event listeners: mousedown, mousemove, mouseup, wheel, resize.

For resize, redraw.

Reset: double click 0,0 zoom1.

Let's start writing the code in mind.

HTML:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Mandelbrot Explorer</title>

<style>

body { margin: 0; overflow: hidden; background: black; }

canvas { display : block; }

#controls {

  position: absolute;

  top: 10px;

  left: 10px;

  color: white;

  font-family: Arial;

  z-index: 10;

}

</style>

</head>

<body>

<canvas id="canvas"></canvas>

<div id=" controls">

<button id="reset">Reset</button>

<span id="info">Drag to pan, scroll to zoom</span>

</div>

<script>

// JS code here

const canvas = document.getElementById('canvas');

const ctx = canvas.getContext('2d');

const resetBtn = document.getElementBy id('reset');

let w, h;

let centerX = -0.75;

let centerY = 0;

let zoom = 1;

const MAX_ITER = 200;

const VIEW_WIDTH = 3.5;

let dragging = false;

let startX, startY;

let startCenterX, startCenterY;

function resize() {

  w = canvas.width = window.innerWidth;

  h = canvas.height = window.innerHeight;

  draw();

}

function draw() {

  const imageData = ctx.createImageData(w, h);

  const data = imageData.data;

  const viewWidth = VIEW_WIDTH / zoom;

  const viewHeight = viewWidth * h / w;

  const minX = centerX - viewWidth / 2;

  const maxX = centerX + viewWidth / 2;

  const minY = centerY - viewHeight / 2;

  const maxY = centerY + viewHeight / 2;

  const dx = viewWidth / w;

  const dy = viewHeight / h;

  for (let px = 0; px < w; px++) {

    for (let py = 0; py < h; py++) {

      const x0 = minX + px * dx;

      const y0 = maxY - py * dy; // top maxY

      let zx = 0, zy = 0;

      let iter = 0;

      while (zx*zx + zy*zy <= 4 && iter < MAX_ITER) {

        const tx = zx*zx - zy*zy + x0;

        zy = 2 * zx * zy + y0;

        zx = tx;

        iter++;

      }

      let r, g, b;

      if (iter >= MAX_ITER) {

        r = g = b = 0;

      } else {

        // smooth

        const z = Math.sqrt(zx*zx + zy*zy);

        const smooth = iter + 1 - Math.log(Math.log(z)) / Math.log(2);

        // hue = smooth * 10 % 360

        const hue = (smooth * 10) % 360;

        // use hsv to rgb with s=0.8, v=0.8

        const rgb = hsvToRgb(hue, 0.8, 0.8);

        r = rgb.r;

        g = rgb.g;

        b = rgb.b;

      }

      const idx = (py * w + px) * 4;

      data[idx] = r;

      data[idx+1] = g;

      data[idx+2] = b;

      data[idx+3] = 255;

    }

  }

  ctx.putImageData(imageData,  0, 0);

}

function hsvToRgb(h, s, v) {

  h = h % 360;

  const c = v * s;

  const x = c * (1 - Math.abs((h / 60) % 2 - 1));

  const m = v - c;

  let r1, g1, b1;

  if (h < 60) {

    r1 = c; g1 = x; b1 = 0;

  } else if (h < 120) {

    r1 = x; g1 = c; b1 = 0;

  } else if (h < 180) {

    r1 = 0; g1 = c; b1 = x;

  } else if (h < 240) {

    r1 = 0; g1 = x; b1 = c;

  } else if (h < 300) {

    r1 = x; g1 = 0; b1 = c;

  } else {

    r1 = c; g1 = 0; b1 = x;

  }

  return {

    r: Math.round((r1 + m) * 255 ),

    g: Math.round((g1 + m) * 255),

    b: Math.round((b1 + m) * 255)

  };

}

function updateInfo() {

  // update if needed

}

function panStart(e) {

  dragging = true;

  startX = e.clientX ;

  startY = e.clientY;

  startCenterX = centerX;

  startCenterY = centerY;

  canvas.style.cursor = 'grabbing';

}

function panMove(e) {

  if (!dragging) return;

  const dx = e.
write index.html (16458 bytes)
toolResult

Successfully wrote 16458 bytes to index.html

assistant
thinking
The task is to build a single-page web app for rendering the Mandelbrot set with smooth color gradient on a full-screen canvas, with click-and-drag to pan and mouse-wheel to zoom. All in one index.htm...
edit {"path":"index.html","edits":[{"oldText":" @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');\n
toolResult

Found 2 occurrences of edits[1] in index.html. Each oldText must be unique. Please provide more context to make it unique.

assistant
thinking
The edit failed because the oldText appeared twice. I need to make the oldText unique by including more context.
read {"path":"index.html","offset":1,"limit":100}
toolResult

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mandelbrot Explorer</title> <style> @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); body { margin: 0; overflow: hidden; background: #000; color: #0ff; font-family: 'Press Start 2P', system-ui; } canvas { display: block; cursor: grab; } canvas:active { cursor: grabbing; } #overlay { position: absolute; top: 20px; left: 20px; background: rgba(0, 0, 20, 0.85); padding: 20px; border: 3px solid #0ff; box-shadow: 0 0 20px #0ff; max-width: 280px; pointer-events: none; z-index: 10; } h1 { margin: 0 0 15px 0; font-size: 18px; text-shadow: 0 0 10px #0ff; color: #0ff; } .instructions { font-size: 11px; line-height: 1.5; color: #0cc; } #info { position: absolute; top: 20px; right: 20px; background: rgba(0, 0, 20, 0.85); padding: 12px 18px; border: 2px solid #0f0; font-size: 13px; font-family: monospace; box-shadow: 0 0 15px #0f0; z-index: 10; min-width: 180px; } #controls { position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); display: flex; gap: 12px; z-index: 10; } button { background: #001122; color: #0ff; border: 2px solid #0ff; padding: 10px 20px; font-family: 'Press Start 2P', system-ui; font-size: 11px; cursor: pointer; box-shadow: 0 0 10px #0ff; transition: all 0.1s; } button:hover { background: #003355; box-shadow: 0 0 20px #0ff; } .scanline { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient( [398 more lines in file. Use offset=101 to continue.]

assistant
edit {"path":"index.html","edits":[{"oldText":" @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');\n
edit {"path":"index.html","edits":[{"oldText":" button {\n background: #001122;\n color: #0ff;\n border:
toolResult

Successfully replaced 1 block(s) in index.html.

toolResult

Successfully replaced 1 block(s) in index.html.

assistant
thinking
The app is now complete: a single self-contained index.html with a full-screen canvas rendering the Mandelbrot set using smooth coloring (via the mu formula for fractional iterations). It supports:

The file `index.html` has been created in the current directory. Open it in a web browser to explore the Mandelbrot set (full-screen canvas, smooth coloring, pan via drag, zoom via mouse wheel, etc.).

TAKE IT TO CODE

A single self-contained HTML file — copy it and open in any browser, or reuse the prompt with your own pi-agent run.

RUN

modelgrok-4.20
vendorxAI · Grok
harnesspi-agent
generated2026-08-01

EVALUATION

4/5 working

Smooth-colored Mandelbrot renders correctly; drag pans and wheel zooms work, click/keyboard have no effect as expected.

Vision grade · anthropic/claude-sonnet-5

MEASUREMENTS

Raw readings from the capture, not a verdict — the grade above is the only judgement. Percentages are how much of the screen changed; the measure under-reports sparse motion on a dark background.

idle motion0.0%
on click0.0%
on drag56.5%
on wheel19.2%
on enter + space0.0%
on arrow keys0.0%
on w/a/s/d0.0%
frame spread52.2 / 255
console errors0
js errors none

METRICS

runtime94.8s
tokens in5.2k
tokens out16k
cached20k
cost / run$0.0497