@marvinhuelsmann/screenflow
v0.4.23
Published
CLI tool to create beautiful mockup device screenshots
Downloads
1,525
Readme
screenflow
Wrap iOS simulator screenshots in a pixel-perfect device frame — straight from your terminal. No Figma, no design tools, no fuss.
Installation
brew install marvinhuelsmann/screenflow/screenflowUsage
screenflow <screenshot>Output defaults to SVG and is placed next to your input file.
screenflow screenshot.png
# → screenshot_iphone-17-pro_cosmic-orange.svgCommands
| Command | Description |
|---|---|
| screenflow <file> | Frame a screenshot (default) |
| screenflow video <file> | Create an animated marketing video |
| screenflow appstore <file> | Generate a ready-to-upload App Store screenshot |
| screenflow mcp install | Register the MCP server with your AI agents (auto-runs on install) |
| screenflow devices | List all available devices and their colors |
| screenflow config | Show your saved defaults |
| screenflow set-default | Set a default device and color interactively |
| screenflow author | About the author |
Frame options
| Option | Short | Description |
|---|---|---|
| --device <device> | -d | Device frame (default: iphone-17-pro) |
| --color <color> | -c | Frame color (default: first color for the chosen device) |
| --png | | Output as PNG instead of SVG (still images only) |
| --jpeg | | Output as JPEG instead of SVG (still images only) |
| --mp4 | | Output as MP4 · H.264 on black instead of MOV · HEVC · Transparent (screen recordings only) |
| --output <path> | -o | Custom output file path |
Examples
# Default — iPhone 17 Pro, Cosmic Orange frame, SVG output
screenflow screenshot.png
# Deep Blue frame
screenflow screenshot.png --color deep-blue
# Cosmic Orange, exported as PNG
screenflow screenshot.png -c cosmic-orange --png
# Render your screen recording into a static mockup
screenflow simulator.mov
# iPad Pro 11, Space Gray
screenflow screenshot.png -d ipad-pro-11 -c space-gray --png
# Custom output path
screenflow screenshot.png -o framed/app_store.svg
# JPEG for smaller file size
screenflow screenshot.png --jpeg
# Set a persistent default device and color
screenflow set-default
# List all available devices and colors
screenflow devicesVideo animation
screenflow video <file> renders an animated MP4 marketing clip. Requires ffmpeg — screenflow will offer to install it automatically via Homebrew if it's not present.
Video options
| Option | Short | Description |
|---|---|---|
| --style <style> | -s | Animation style (default: zoom-in) |
| --duration <seconds> | | Clip length in seconds, 1–60 (default: 9). For a still it's the animation length; for a recording it trims the clip (capped to the recording's length) |
| --tilt <degrees> | -t | Perspective tilt downward in degrees, 0–45 (default: 0) |
| --fps <fps> | | Frame rate: 24, 30, 60, or 120 (default: 60) |
| --device <device> | -d | Device frame |
| --color <color> | -c | Frame color |
| --output <path> | -o | Custom output file path |
Animation styles
| Style | Description |
|---|---|
| zoom-in (default) | 2× zoom, pan from bottom to top |
| zoom-out | Zoom out 1.8× → 1×, centered |
| pan-down | Constant 1.4× zoom, pan from top to bottom |
| pan-left | Full device visible, slides from right to left across the frame |
| pan-right | Full device visible, slides from left to right across the frame |
# Default zoom-in style (9 seconds)
screenflow video screenshot.png
# → screenshot_iphone-17-pro_cosmic-orange.mp4
# 15-second video
screenflow video screenshot.png --duration 15
# Pan from top to bottom
screenflow video screenshot.png --style pan-down
# Zoom out with specific device and color
screenflow video screenshot.png -d iphone-16-pro -c natural --style zoom-out
# Pan left with custom output
screenflow video screenshot.png --style pan-left -o ~/Desktop/promo.mp4
# Zoom-in with 15° downward tilt
screenflow video screenshot.png --tilt 15
# Zoom-in at 120 fps for 5 seconds
screenflow video screenshot.png --fps 120 --duration 5Output is always 1920 × 1080 H.264 MP4, CRF 12.
App Store screenshots
screenflow appstore <file> turns a single screenshot into a ready-to-upload App Store screenshot at the mandatory 1242 × 2688 (iPhone 6.5") size: a headline caption on top, the framed device below, on a solid background. The caption is set in SF Pro Display, and its color is chosen automatically for contrast against the background. Use \n in the caption for manual line breaks (long captions also wrap automatically).
App Store options
| Option | Short | Description |
|---|---|---|
| --caption <text> | | Headline text rendered above the device |
| --align <align> | | Caption alignment: left | center | right (default center) |
| --bg <color> | | Background color, hex (default #0A84FF) |
| --device <device> | -d | Device frame |
| --color <color> | -c | Frame color |
| --jpeg | | Output as JPEG instead of PNG |
| --output <path> | -o | Custom output file path |
# Hero screenshot — blue background, centered caption
screenflow appstore screenshot.png --caption "Find your way, anywhere."
# → screenshot_iphone-17-pro_appstore.png (1242×2688)
# Light background (caption auto-switches to black), left-aligned
screenflow appstore screenshot.png -d iphone-16-pro -c black \
--caption "Plan routes in seconds." --align left --bg "#F2F2F7"
# Dark background, long captions wrap automatically
screenflow appstore screenshot.png --bg "#1C1C1E" \
--caption "Discover every hidden corner of your city with confidence"
# Manual line break with \n
screenflow appstore screenshot.png \
--caption "Find your way.\nAnywhere, anytime."Screen recordings & HEIC input
The commands are the same — just hand them a screen recording (.mp4, .mov, .m4v, .webm, .mkv, .avi) or any still image (including .heic/.heif) instead of a PNG/JPG. screenflow detects the input type automatically (requires ffmpeg for video).
| Input | screenflow <file> (default) | screenflow video <file> |
|---|---|---|
| Still image (PNG/JPG/HEIC) | Static framed image (SVG/PNG/JPEG) | Animated marketing clip (--duration seconds) |
| Screen recording (MP4/MOV/…) | Device stays still, the screen plays the recording | Camera animation (zoom/pan/tilt) runs while the screen plays |
For a screen recording the output length defaults to the recording length. With the video command you can pass --duration to trim the clip shorter (it's capped to the recording's own length — a recording can't be extended). --png/--jpeg don't apply to the default command.
# Static framing of a screen recording → transparent .mov (HEVC with alpha), audio kept
screenflow recording.mov -d iphone-17-pro
# → recording_iphone-17-pro_cosmic-orange.mov
# H.264 .mp4 on a black background instead
screenflow recording.mov --mp4
# → recording_iphone-17-pro_cosmic-orange.mp4
# Drop the audio track
screenflow recording.mov --mute
# Animate a screen recording (length = recording), 15° tilt
screenflow video recording.mov --style zoom-in --tilt 15
# HEIC still works just like a PNG
screenflow shot.heic -d iphone-17 --png- Default command + recording → transparent
.mov(HEVC with alpha) — alpha channel preserved at ~90× smaller files than ProRes, plays natively in QuickTime/Keynote and composites in Final Cut or After Effects; use--mp4for H.264 on a black background. videocommand + recording →1920 × 1080H.264 MP4 (the established marketing format).- Audio from the recording is kept by default; use
--muteto strip it.
Note: transparent
.movoutput uses HEVC with alpha (hardware-encoded via VideoToolbox on macOS), keeping files small even for large canvases (iMac, iPad).
Use it from AI agents (MCP)
screenflow ships an MCP server (screenflow-mcp) so AI coding agents — Claude Code, Codex, Cursor, Claude Desktop — can frame screenshots, build App Store screenshots and wrap recordings for you. Ask the agent to "put this screenshot in an iPhone mockup" or "make App Store screenshots" and it picks the right tool automatically.
Tools exposed: frame_screenshot, frame_recording, create_appstore_screenshot, list_devices.
Each media tool takes the input one of three ways, in order of preference:
input_path— a real existing file on the machine running the server. Fastest; use it whenever the agent is on the same computer (e.g. Claude Code on your Mac).input_url— a public URL the server downloads. Fast.input_base64— the raw bytes, base64-encoded. Works in any environment (sandboxed/containerised agents with no shared filesystem) but is slow and expensive for large files, because the model has to emit the entire blob — only use it when no path or URL is available.
The result is returned inline as a downscaled preview image (max 1568 px long edge — set inline_max_px: 0 for full resolution inline). Pass output_path to also save the full-resolution file to disk. If a bogus path is passed, the tool replies with guidance to use a URL or base64 instead.
Zero-config setup
Installing the CLI automatically registers the MCP server with every AI agent it finds on your machine — no manual steps:
brew install marvinhuelsmann/screenflow/screenflow # or: npm i -g @marvinhuelsmann/screenflowThat's it. Restart your agent and ask it to frame a screenshot. Re-run the registration anytime (e.g. after installing a new agent):
screenflow mcp install # register with all detected agents
screenflow mcp install --dry-run # preview what it would change
screenflow mcp uninstall # remove the registration everywhereManual setup (optional)
If you'd rather wire it up by hand:
# Claude Code
claude mcp add screenflow -- screenflow-mcp# Codex — ~/.codex/config.toml
[mcp_servers.screenflow]
command = "screenflow-mcp"// Cursor / Claude Desktop — mcpServers
{ "mcpServers": { "screenflow": { "command": "screenflow-mcp" } } }The server communicates over stdio and needs no extra setup; ffmpeg is only required for the recording tool.
Supported Devices
| Device | ID | Colors |
|---|---|---|
| iPhone 17 Pro | iphone-17-pro | cosmic-orange, deep-blue, silver |
| iPhone 16 Pro | iphone-16-pro | black, natural, white |
| iPad Pro 11" | ipad-pro-11 | silver, silver-with-apple-pencil, space-gray, space-gray-with-apple-pencil |
| iPad Pro 13" | ipad-pro-13 | silver, space-gray |
| iPhone Air | iphone-air | black, blue, gold, white |
| iPhone 17" | iphone-17 | black, lavender, mist-blue, sage, white |
| iPhone 16" | iphone-16 | black, pink, teal, ultramarine, white |
| Imac | imac | blue, green, orange, pink, purple, silver, yellow |
| Apple Watch Ultra | apple-watch-ultra | black-alpine-loop, black-milanese, natural-alpine-loop, natural-milanese |
| Apple Watch Series 11" | apple-watch-series-11 | titanium-gold-magnetic-link-sage-gray, titanium-gold-milanese-loop, titanium-natural-magnetic-link-caramel, titanium-natural-sport-band-stone-gray, titanium-slate-magnetic-link-navy, titanium-slate-milanese-loop |
Updating
brew upgrade screenflowProject Structure
src/
index.ts ← entry point (3 lines)
cli.ts ← program setup + command routing
composer.ts ← SVG compositing, output rendering + buildFrameAssets (video overlay/mask)
config.ts ← Config class (reads/writes ~/.config/screenflow/config.json)
ui.ts ← shared terminal helpers (spinner, colors, name formatting)
ffmpeg.ts ← shared ffmpeg/ffprobe helpers + input-kind detection
video-compose.ts ← ffmpeg filtergraph for compositing a recording inside a frame
frames/
index.ts ← FRAMES registry — source of truth for devices, colors, dimensions
iphone-17-pro/ ← SVG frame files per color
cosmic-orange.svg
deep-blue.svg
silver.svg
ipad-pro-11/
ipad-pro-13/
iphone-16-pro/
commands/
frame.ts ← frame a screenshot
video.ts ← render a 5-second marketing video animation
setDefault.ts ← interactive default picker
devices.ts ← list devices and colors
showConfig.ts ← print saved defaults
author.ts ← author info
scripts/
add-device.js ← automation: registers a new device across all filesContributing
Contributions are welcome — new devices, new color variants, bug fixes. Here's how everything fits together.
Setup
git clone https://github.com/marvinhuelsmann/screenflow.git
cd screenflow
npm installDevelopment
# Run directly without building
npm run dev -- screenshot.png
# Build
npm run build
# Test your build
node dist/index.js screenshot.pngAdding a new device
1. Export the SVG frames from your design tool — one file per color variant. Name each file after its color (e.g. silver.svg, space-gray.svg).
2. Create the device folder and drop in the SVGs:
src/frames/
iphone-17-pro/ ← existing
your-new-device/ ← new
silver.svg
space-gray.svg3. Run the add-device script:
npm run add-device your-new-device
# or with a custom display name:
npm run add-device your-new-device 'Your New Device'The script automatically:
- Detects the frame type (vector SVG or raster PNG-in-SVG)
- Calculates the screen coordinates by scanning for the transparent screen area
- Registers the device in
src/frames/index.ts - Adds the
cpcommand to thepackage.jsonbuild script - Adds the device and its colors to both completion files
- Adds a row to the device table in
README.md
4. Build and test:
npm run build
node dist/index.js screenshot.png --device your-new-device --color silverThe first color registered for a device is used as that device's automatic default.
Vector frames (like the iPhone 17 Pro SVGs) have a
<path id="Screen mask">element. The script registers them but cannot auto-detect screen coordinates from vector paths — check the logged output and correct the values insrc/frames/index.tsmanually if needed.
Adding a new color to an existing device
- Drop the SVG into the device folder (e.g.
src/frames/iphone-17-pro/midnight.svg) - Add the color entry in
src/frames/index.tsunder the device'scolorsmap - Add the color to both completion files (
completions/screenflow.fishandcompletions/_screenflow) - Build and test
Opening a pull request
- Fork the repo and create a branch:
git checkout -b feat/iphone-18-pro - Make your changes and build cleanly:
npm run build node dist/index.js screenshot.png --device iphone-18-pro - Push and open a PR against
develop:git push origin feat/iphone-18-pro - In the PR description include:
- Which device / color was added
- A sample output screenshot so the result can be reviewed visually
License
MIT © Marvin Hülsmann
