Build Shots.so

YESreplaces $5/mosaves $60/yrback to the verdict

0%0 of 19 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A screenshot beautifier as one static page: drop, paste or pick a screenshot, adjust padding, corners, shadow, background and canvas ratio with live preview, export a crisp PNG at 1x or 2x or copy it to the clipboard. Everything happens in the browser; nothing is uploaded; it works offline after the first load.

estimated effort one sittingthe files for this build are in the project pack

EverythingOne HTML file, vanilla JS, Canvas 2DHostingAny static host, or open the file

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Every step below is a command you type or a file you edit.

    Get it VS Code (code.visualstudio.com), Cursor or Zed. Open a folder for the project and use the editor's built-in terminal. open ↗

    Verify You can open a folder and run a command in its terminal

  2. installfree

    Why Clipboard image copying behaves differently in Safari; Phase 5 must be tested in both.

    Get it Chrome or Edge, plus Safari if you have a Mac. Without Safari, note the clipboard code path is untested there.

  3. have readyfree

    Why Including one very tall one and one wider than 4000px, to exercise ratios and performance.

    Get it Take three: a normal window, a full-page tall capture, a large retina one.

  4. free

    Why To share it with others. Locally, opening the file is enough.

    Get it Cloudflare Pages, Netlify or GitHub Pages: connect the repo, done. open ↗

  5. installfree

    Why History for your code, and the way most hosts deploy.

    Get it Install from git-scm.com or with your package manager, then run git init in the project folder once it exists. open ↗

    Verify git --version prints a version

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

A single `state` object drives every render: `{ image, padding, radius, shadow,
background, ratio, scale }`. Every control writes to `state` and calls one
`render()`. There is exactly one render function and one source of truth · the
moment two code paths draw to the canvas, the controls start disagreeing with
the export, which is the classic bug in this tool.

The build, in order

  1. Image input and render loop

    Three ways in, one render function, correct on HiDPI from the start.

    1. state = { image, padding, radius, shadow, background, ratio, scale }. Every control writes to state and calls render(). Exactly one render function; two code paths drawing to the canvas is the classic bug here.

      Files index.html

    2. paste: read clipboardData.items for an image type. All three create an Image from a Blob URL and set state.image.

    3. Backing store = css size times devicePixelRatio; ctx.scale once. Retrofitting this later means re-tuning every offset.

    done when · tick each as it passes
  2. Geometry controls

    Padding, radius and shadow as live sliders whose export matches the preview.

    1. Range inputs bound to state; render on input.

    2. ctx.roundRect and clip, not a CSS overlay, or the export will not match the preview. Draw the shadow with canvas shadow properties on the clipped shape.

    done when · tick each as it passes
  3. Backgrounds

    Ten presets that look premium before anyone touches anything.

    1. Plus a custom colour input and a transparent option.

    2. Most users never change it.

    done when · tick each as it passes
  4. Canvas ratios

    Fit without cropping or distortion.

    1. Store it in state; a change triggers one render().

    2. Compute the scale as the minimum of available width over image width and available height over image height. Never crop, never distort.

    done when · tick each as it passes
  5. Export

    Sharp PNG at 1x and 2x, and clipboard that works in both engines.

    1. Never upscale the preview bitmap.

    2. Pass a Promise resolving to a Blob into ClipboardItem; Safari requires the promise form and Chromium accepts it. Call navigator.clipboard.write synchronously inside the click handler.

    done when · tick each as it passes
  6. Polish

    Shortcuts, an empty state, memory, offline.

    1. Open DevTools > Network, reload with Offline checked.

    done when · tick each as it passes
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more screenshots.