bezelkit · an open-source web component
Most mockups break your screenshots.
This is an iPhone 17 Pro screenshot, 1206 × 2622. Here's what a typical mockup does to it.
Scroll
width: 100%; height: 100%
Squashed.
The mockup's screen is 9:16. Your screenshot is 19.5:9, so it gets pressed 18% flat. Circles turn into ovals.
status bar: painted on
Doubled.
The frame draws its own status bar over the one already in your screenshot.
object-fit: cover
Sliced.
Cover keeps the shape but trims 80 px off each end. Your tab bar goes with it.
notch: z-index 10
Covered.
Then the painted-on notch lands on your header.
fit="auto"
Your screenshots,framed properly.
bezelkit draws the device's real screen in CSS pixels, compares it with your screenshot and picks the fit. This one matches the iPhone 17 Pro, so it maps 1:1.
bezelkit · an open-source web component
Most mockups break your screenshots.
The same iPhone 17 Pro screenshot, 1206 × 2622, four ways a typical mockup gets it wrong, and bezelkit.
device="…"
Every screen at its real size.
26 current frames, drawn in CSS. Screens use each device's published viewport, and frames scale to any width without blurring.
el.flip()
Turn it over.
An 800 ms turn to the back: camera plateau, finish, mirrored buttons. All CSS. No photos, no logos.
side="both"
Both sides, one tag.
The back tilts in behind the front, ready for a product shot. Pick a finish.
Install
One tag.
No build step.
<script type="module" src="https://cdn.jsdelivr.net/npm/bezelkit@0/dist/bezelkit.js"></script><bezel-device
device="iphone-17-pro"
src="screenshot.png">
</bezel-device>
Zero dependencies. The same tag works in plain HTML, React 19, Vue, Svelte, Astro, MDX and Markdown docs. Screens also take a video, a URL or your own HTML, and stay clickable.
iphone-17-pro · 402 × 874
Four ways to fit, picked for you
bezelkit compares your image's shape with the device's real screen and uses whichever strategy loses the least. These are live frames, not pictures.
Playground
Drop in your own screenshot, recording, or URL. Everything here runs locally in your browser.
41 frames and counting
Each one is drawn in CSS at the device's real viewport, so it stays sharp at any size. Pick a device to try it in the playground.
API
Point it at bezelkit.dev/llms-full.txt. It has every attribute, the fit rules, framework notes and all 41 devices with their screenshot resolutions, so Claude, ChatGPT or Cursor can wire it up for you.
One element for plain HTML, React 19, Vue, Svelte and Astro. Give it a width and it scales; give it a width and height and it fits inside both. The full reference is in the README.
| Attribute | Values | What it does |
|---|---|---|
device | iphone-17-pro … see above | Which frame to render. |
src | image · video · URL | Type is detected from the extension; URLs become a live iframe at the true viewport. Omit it to slot your own HTML. |
fit | auto cover top contain scroll fill | auto picks for you, as shown above. |
color · orientation | finish name · landscape | Official finishes or any CSS colour; content rotates with the device. |
side · variant · folded | back both · deck 3d · boolean | Back panels and stacked shots, 3D laptops and desktops, and foldables. flip(), fold() and open() animate them. |
chrome · safe-area | auto on off · pad none | Status bar and home indicator, and keeping live HTML clear of the notch. |
Frame your first screenshot.
Drop one on the phone. It stays in your browser. bezelkit reads its size and tells you which fit it picked.
Drop a screenshot here.