A treasure map hides in a landscape's lowest bits. Peel the bit planes to find it.
A procedurally painted landscape, with sensor grain and a tone curve like a real photo, carries a second picture in the lowest bit of each of its R, G and B values: a treasure map dithered per channel, or a typed message after a 32-bit length header. At 1 bit per channel no value moves by more than 1 out of 255, so the picture looks untouched, but the strip of bit planes shows the high planes as a posterized copy of the scene and bit 0 as the map. With more bits per channel the map gets cleaner and the cover starts to suffer. Encrypting the payload with a keyed stream turns plane 0 back into noise, yet the histogram gives it away: random low bits even out each pair of values 2i and 2i+1, and Westfeld and Pfitzmann's chi-square attack turns that into a probability of embedding, plotted as it scans the image.
Try it. Drag across the image to move the wipe between the picture and a bit plane, and pick the plane from the strip (or press up and down). Hover to read a pixel's bits before and after embedding. Type to hide your own message and watch which pixels flash; the buttons switch between map and text, 1 to 4 bits per channel, plain or encrypted payload, and a map of every changed pixel.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a steganography explorer with JavaScript and the HTML canvas element that hides a secret image in the least significant bits of another. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Paint a cover image yourself into an offscreen canvas, about 200x125 pixels: a sunset sky, mountains and a lake, plus a little random grain on every channel so it behaves like a photo.
- Paint a second, secret image of the same size: a simple treasure map with a coastline, a dotted trail and a big X. Threshold each of its color channels to a single bit.
- Hide it: for every pixel and channel, replace the cover's lowest bit with the secret's bit, using (cover & ~1) | bit. Draw the result scaled up. It should look identical to the cover.
- Add a bit plane slider from 7 down to 0 that shows, for each channel, just that bit at full brightness. The top planes look like a posterized picture, and plane 0 reveals the map.
Once that works, make it beautiful:
- Show all eight bit planes as a strip of thumbnails I can click, and a draggable wipe that splits the main view between the normal picture and the selected plane.
- Let me choose 1 to 4 bits per channel and dither the secret to that many levels, so the trade-off between a clearer secret and a damaged cover is visible.
- Hover a pixel to print its channel values in binary before and after embedding, with the changed bits highlighted.
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as hiding typed text with a length header, encrypting the payload so plane 0 looks like noise, or the chi-square attack that detects LSB embedding from the histogram.