Content-aware resizing: seams peel away and the lighthouse stays intact.
A painted coastline is resized by removing seams, connected paths of one pixel per row that cross as little visible structure as possible. Dynamic programming over a forward-energy cost table finds the cheapest seam, which is removed and the search repeated, so sky and sea shrink while the lighthouse, cottage and boats keep their shape. The image is carved all the way down once in the background and the removal order of every pixel is recorded, which makes any width instant to show, and widening is seam insertion: the first k seams are duplicated. Side panels compare plain scaling and paint every removed seam onto the original.
Try it. Drag the right handle to narrow or widen, or the bottom handle to carve rows. Toggle the energy map and the cost table. Paint with the protect brush to keep something whole, or with the erase brush over a boat to carve it out and refill the width. Arrow keys resize; R resets.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build an interactive seam carving demo (content-aware image resizing) with JavaScript and the HTML canvas element. 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 test image in code on a 300 x 200 offscreen canvas: a gradient sky, a sea, a striped lighthouse on a cliff and a small boat. Lots of empty sky and water is what makes the effect work.
- Read its pixels with getImageData and compute an energy for each pixel: the sum of absolute colour differences to its left/right and up/down neighbours.
- Find the cheapest vertical seam with dynamic programming: M[y][x] = energy[y][x] + the minimum of M[y-1][x-1], M[y-1][x] and M[y-1][x+1]. Backtrack from the smallest value in the last row.
- Remove the seam (one pixel per row, shifting the rest left), and repeat. Draw the image scaled up with drawImage, and draw the seam about to be removed in red so you can watch them peel away.
- Add a slider for the target width, and next to the result show the same width made by plain scaling, so the difference is obvious.
Once that works, make it beautiful and fast:
- Use forward energy (Rubinstein et al.): instead of the pixel's own energy, charge each step for the new edges created when its neighbours slide together. Straight lines stay much straighter.
- Carve all the way down once and record the order in which each pixel was removed. Then any width is just 'keep pixels removed after step k', so dragging is instant.
- Toggle an overlay of the energy map and of the cost table M with a dark-to-bright colour map.
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 seam insertion to widen images, a brush to protect or remove objects, or carving rows by transposing the image.