DEV Community

Cover image for Better JetBrains Marketplace screenshots for every plugin
Yuriy Artamonov
Yuriy Artamonov

Posted on

Better JetBrains Marketplace screenshots for every plugin

The media section is the first thing people see on a JetBrains Marketplace plugin page. It's also where most plugins look their worst: full-screen IDE captures shrunk to carousel size, unreadable 13px text, desktop wallpaper around the window, and every screenshot a different size.

The good-looking ones are usually composed slides. A short headline sits on a tinted background next to a cropped, zoomed-in IDE window, and one thing on screen is highlighted. Making those by hand in a design tool takes a while, and you redo all of it whenever the UI changes.

So I built mpshots. It's a small Node CLI. You give it your raw IDE screenshots and a YAML file, and it renders a consistent set of Marketplace slides.

Raw capture of the Air plugin's account picker

Raw window capture…

Composed slide: "Bring your own agent and account"

…and the slide mpshots makes from it.

What it does

You describe each slide in a shots.yaml:

output:
  width: 1920
theme: dark
brand:
  name: Air
  accent: "#3574F0"
defaults:
  uiScale: 2              # Retina capture

slides:
  - id: accounts
    layout: hero
    headline: Bring your own agent and account
    body: Switch between JetBrains AI, a ChatGPT account or your own API key
    screenshot:
      src: screenshots/accounts.png
      crop: [574, 996, 1645, 720]          # x, y, w, h in source pixels
      highlight: [1561, 1256, 637, 413]    # draws an accent outline with a glow
Enter fullscreen mode Exit fullscreen mode

Then run mpshots build. You get one PNG per slide, plus an index.html that shows them at about the size the Marketplace carousel uses.

There are four layouts:

  • text-left: text on the left, IDE window on the right running off the edge of the slide.
  • text-right: the mirror image of text-left.
  • hero: centred headline with a wide window below.
  • window: the window on its own, no text.

On any slide you can add highlights, which outline something on screen. You can also add an overlay, a second window floating on top, such as a browser preview next to the IDE.

Every slide uses the same logical 1920×1080 canvas, and output.width sets the pixel size: 1920, 2560 or 3840. Your set always comes out with one aspect ratio, which the Marketplace guidelines ask for.

Here's the full set for the Air plugin, all from one spec:

Agent sessions slide

Terminal agent slide

Diff review slide

Inline prompt slide

The checks

Laying out slides wasn't the hard part. The hard part was knowing whether a slide will still be readable once it's shrunk into the carousel. Before rendering anything, mpshots validate checks:

  • IDE text size: it estimates how big the IDE's 13px UI font ends up after your crop and zoom (13 × uiScale × zoom), and warns if it lands under 16px.
  • Upscaling: it warns if the screenshot has to be blown up more than 1.05×, because the result will look soft.
  • Copy length: headlines over 60 characters, body text over 240.
  • Hard errors: missing files, and crops or highlights that fall outside the image.

--strict turns warnings into failures, so you can run it in CI.

Building this taught me one thing: a 1920×1080 capture at 100% IDE zoom can't be both readable and sharp on a slide. To make the text big enough, you have to scale the capture up, and then it goes blurry. The fix is at capture time. Zoom the IDE to 125–150% (View › Appearance › Zoom IDE), or capture on a Retina display, and set uiScale to match. The Air screenshots above are 2800×1800 Retina window captures. They pass both checks without being scaled up.

Finding crop coordinates

Nobody wants to guess pixel rectangles. mpshots grid draws a labelled pixel grid over a capture so you can read off [x, y, w, h] directly:

mpshots grid screenshots/accounts.png
# → screenshots/accounts.grid.png
Enter fullscreen mode Exit fullscreen mode

How it renders

There's no headless browser. Layout is done by satori, which turns flexbox-style elements into SVG. resvg turns that SVG into pixels, and sharp handles crops and resampling. Each screenshot is resampled once, with Lanczos, straight to the final output size. A slide takes about two to three seconds. It runs anywhere Node 18 does, CI included.

Try it

It installs straight from GitHub:

npm i -g github:jreznot/mpshots#v0.1.0
mpshots init      # creates shots.yaml and screenshots/
mpshots build
Enter fullscreen mode Exit fullscreen mode

The repo includes two complete examples: a set built from generated mock IDE screens, and the Air set above from real captures. Clone it and run mpshots build in examples/air to see the whole pipeline.

Next I'd like to remove the manual capture step. An IDE action could save a clean window capture at a known zoom and write the crop rectangles for you.

Issues and PRs are welcome: github.com/jreznot/mpshots.

Top comments (0)