Skip to content
Dave Klein

Bezel bake

Frames iPhone screenshots and recordings in a device-matched, generated bezel automatically, the moment they land in a folder. Bezel bake is one of the Claude Code skills I wrote for building this site, with the site-specific values turned into placeholders and examples so it works on any project. The skill is the SKILL.md below, exactly as it ships in the zip.

Install

unzip bezel-bake.zip -d ~/.claude/skills

That installs it for every project. For one project, unzip into that project’s .claude/skills/ instead. Either way, Claude Code reads the folder on its next session and applies the skill when a request matches its description:

Frame iPhone screenshots and screen recordings in a device-matched bezel automatically, on the way into the repo. Detects an iPhone capture by its pixel size, picks the phone that took it, renders a generated frame at the scale that leaves the capture's pixels untouched, and bakes stills with a transparent surround and videos as light and dark masters with page-matched corners. A folder watcher runs it for anything dropped into a downloads folder. Use when a site shows phone captures and every one should arrive framed without a manual step.

Inside the zip

  • —bezel-bake/SKILL.md · 4 KB

The skill

A phone screenshot on a web page wants a frame, and the frame wants to be the right phone. Doing that by hand in an image editor, for every capture, is the step people skip. This skill makes it happen at the moment the file lands.

Detect, then match

  • Detection is a shape test. An iPhone portrait capture is at least 700 px wide with a height to width ratio between 1.95 and 2.35. Ordinary photos (3:4, 1.33) never fall in that band, so a watcher can route on it without a model or a filename convention.
  • The device is named by its native pixel size. Keep a table of devices with their screenshot dimensions; a capture’s width x height selects the phone that took it. Where generations share a screen size the newest wins, and a flag can pick another. The lineup runs from the iPhone 12 family to the iPhone 18 Pro and 18 Pro Max (Apple’s sheets dated 2026-09-09); a 1206 × 2622 or 1320 × 2868 capture therefore frames as an 18 Pro or 18 Pro Max unless --device says otherwise.
  • Never resample the capture. Render the frame at the scale that makes its active area exactly the capture’s pixels. A capture a pixel or two off its native size loses those pixels to a whole-pixel crop rather than being stretched.

Draw the frame, don’t paste it

Use a generated frame drawn from the manufacturer’s dimensional drawings (outer size, corner radii, screen inset, island), not raster frame art: it scales exactly, it has no baked highlights that fight the page, and one generator covers every device in the table. A published component that renders these frames from specs can double as the generator for the bake (render the SVG at the bake size, rasterize, composite).

Stills and videos are different files

  • Stills bake to <name>-framed.png: the capture placed in the frame, transparent outside the phone. The page’s image component recognizes the -framed suffix and gives it the framed treatment (a fixed display width, the object shadow) with no markup.
  • Videos have no alpha, so bake two masters, <name>-light.mp4 and <name>-dark.mp4, with the corners painted the page colour of each theme, plus matching poster JPEGs and a 3x variant for dense displays. Pre-compensate the dark corner colour one step brighter than the token: the RGB to YUV 4:2:0 round trip loses a unit per channel in the near blacks, and the file that decodes to the page colour is the one whose input was slightly off it. Measure once and write the value down.

The watcher

A launch agent polls a downloads folder every two seconds. Anything that passes the shape test detours through the bake and lands framed in the images folder; everything else is moved as is. Three things break it silently, so guard each:

  • PATH. A launch agent starts with a bare PATH. Resolve node from the version manager (the one npm installs run under, so native modules such as sharp match its architecture) and put Homebrew’s ffmpeg ahead of any Intel build in /usr/local/bin.
  • Permissions. The agent’s shell needs Full Disk Access to read the downloads folder.
  • Logging. Write every move, bake, and failure to a log file with a timestamp; when a capture arrives unframed, the log says why.

Open the resulting file in the editor the writer uses (an obsidian:// URL, a code command) so the bake is visible the moment it finishes.

Check on the page

The framed still should sit at the same display width as every other framed capture, cast the object shadow that whole things get, and show no fringe at the frame’s edge. A video’s corners should be indistinguishable from the page in both themes; if a dark corner reads as a tinted square, the compensation step is missing.