Marketplace app-store-screenshots

Use when building App Store screenshot pages, generating exportable marketing screenshots for iOS apps, or creating programmatic screenshot generators with Next.js. Triggers on app store, screenshots, marketing assets, html-to-image, phone mockup.

install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/parthjadhav/app-store-screenshots" ~/.claude/skills/aiskillstore-marketplace-app-store-screenshots-833b71 && rm -rf "$T"
manifest: skills/parthjadhav/app-store-screenshots/SKILL.md
source content

App Store Screenshots Generator

Overview

Build a Next.js page that renders iOS App Store screenshots as advertisements (not UI showcases) and exports them via

html-to-image
at Apple's required resolutions. Screenshots are the single most important conversion asset on the App Store.

Core Principle

Screenshots are advertisements, not documentation. Every screenshot sells one idea. If you're showing UI, you're doing it wrong — you're selling a feeling, an outcome, or killing a pain point.

Step 1: Ask the User These Questions

Before writing ANY code, ask the user all of these. Do not proceed until you have answers:

Required

  1. App screenshots — "Where are your app screenshots? (PNG files of actual device captures)"
  2. App icon — "Where is your app icon PNG?"
  3. Brand colors — "What are your brand colors? (accent color, text color, background preference)"
  4. Font — "What font does your app use? (or what font do you want for the screenshots?)"
  5. Feature list — "List your app's features in priority order. What's the #1 thing your app does?"
  6. Number of slides — "How many screenshots do you want? (Apple allows up to 10)"
  7. Style direction — "What style do you want? Examples: warm/organic, dark/moody, clean/minimal, bold/colorful, gradient-heavy, flat. Share App Store screenshot references if you have any."

Optional

  1. Component assets — "Do you have any UI element PNGs (cards, widgets, etc.) you want as floating decorations? If not, that's fine — we'll skip them."
  2. Additional instructions — "Any specific requirements, constraints, or preferences?"

Derived from answers (do NOT ask — decide yourself)

Based on the user's style direction, brand colors, and app aesthetic, decide:

  • Background style: gradient direction, colors, whether light or dark base
  • Decorative elements: blobs, glows, geometric shapes, or none — match the style
  • Dark vs light slides: how many of each, which features suit dark treatment
  • Typography treatment: weight, tracking, line height — match the brand personality
  • Color palette: derive text colors, secondary colors, shadow tints from the brand colors

IMPORTANT: If the user gives additional instructions at any point during the process, follow them. User instructions always override skill defaults.

Step 2: Set Up the Project

Detect Package Manager

Check what's available, use this priority: bun > pnpm > yarn > npm

# Check in order
which bun && echo "use bun" || which pnpm && echo "use pnpm" || which yarn && echo "use yarn" || echo "use npm"

Scaffold (if no existing Next.js project)

# With bun:
bunx create-next-app@latest . --typescript --tailwind --app --src-dir --no-eslint --import-alias "@/*"
bun add html-to-image

# With pnpm:
pnpx create-next-app@latest . --typescript --tailwind --app --src-dir --no-eslint --import-alias "@/*"
pnpm add html-to-image

# With yarn:
yarn create next-app . --typescript --tailwind --app --src-dir --no-eslint --import-alias "@/*"
yarn add html-to-image

# With npm:
npx create-next-app@latest . --typescript --tailwind --app --src-dir --no-eslint --import-alias "@/*"
npm install html-to-image

Copy the Phone Mockup

The skill includes a pre-measured iPhone mockup at

mockup.png
(co-located with this SKILL.md). Copy it to the project's
public/
directory. The mockup file is in the same directory as this skill file.

File Structure

project/
├── public/
│   ├── mockup.png              # Phone frame (included with skill)
│   ├── app-icon.png            # User's app icon
│   └── screenshots/            # User's app screenshots
│       ├── home.png
│       ├── feature-1.png
│       └── ...
├── src/app/
│   ├── layout.tsx              # Font setup
│   └── page.tsx                # The screenshot generator (single file)
└── package.json

The entire generator is a single

page.tsx
file. No routing, no extra layouts, no API routes.

Font Setup

// src/app/layout.tsx
import { YourFont } from "next/font/google"; // Use whatever font the user specified
const font = YourFont({ subsets: ["latin"] });

export default function Layout({ children }: { children: React.ReactNode }) {
  return <html><body className={font.className}>{children}</body></html>;
}

Step 3: Plan the Slides

Screenshot Framework (Narrative Arc)

Adapt this framework to the user's requested slide count. Not all slots are required — pick what fits:

SlotPurposeNotes
#1Hero / Main BenefitApp icon + tagline + home screen. This is the ONLY one most people see.
#2DifferentiatorWhat makes this app unique vs competitors
#3EcosystemWidgets, extensions, watch — beyond the main app. Skip if N/A.
#4+Core FeaturesOne feature per slide, most important first
2nd to lastTrust SignalIdentity/craft — "made for people who [X]"
LastMore FeaturesPills listing extras + coming soon. Skip if few features.

Rules:

  • Each slide sells ONE idea. Never two features on one slide.
  • Vary layouts across slides — never repeat the same template structure.
  • Include 1-2 contrast slides (inverted bg) for visual rhythm.

Step 4: Write Copy FIRST

Get all headlines approved before building layouts. Bad copy ruins good design.

The Iron Rules

  1. One idea per headline. Never join two things with "and."
  2. Short, common words. 1-2 syllables. No jargon unless it's domain-specific.
  3. 3-5 words per line. Must be readable at thumbnail size in the App Store.
  4. Line breaks are intentional. Control where lines break with
    <br />
    .

Three Approaches (pick one per slide)

TypeWhat it doesExample
Paint a momentYou picture yourself doing it"Check your coffee without opening the app."
State an outcomeWhat your life looks like after"A home for every coffee you buy."
Kill a painName a problem and destroy it"Never waste a great bag of coffee."

What NEVER Works

  • Feature lists as headlines: "Log every item with tags, categories, and notes"
  • Two ideas joined by "and": "Track X and never miss Y"
  • Compound clauses: "Save and customize X for every Y you own"
  • Vague aspirational: "Every item, tracked"
  • Marketing buzzwords: "AI-powered tips" (unless it's actually AI)

Copy Process

  1. Write 3 options per slide using the three approaches
  2. Read each at arm's length — if you can't parse it in 1 second, it's too complex
  3. Check: does each line have 3-5 words? If not, adjust line breaks
  4. Present options to the user with reasoning for each

Reference Apps for Copy Style

  • Raycast — specific, descriptive, one concrete value per slide
  • Turf — ultra-simple action verbs, conversational
  • Mela / Notion — warm, minimal, elegant

Step 5: Build the Page

Architecture

page.tsx
├── Constants (W, H, SIZES, design tokens from user's brand)
├── Phone component (mockup with screen overlay)
├── Caption component (label + headline)
├── Decorative components (blobs, glows, shapes — based on style direction)
├── Screenshot1..N components (one per slide)
├── SCREENSHOTS array (registry)
├── ScreenshotPreview (ResizeObserver scaling + hover export)
└── ScreenshotsPage (grid + toolbar + export logic)

Export Sizes (Apple Required — iPhone only, portrait)

const SIZES = [
  { label: '6.9"', w: 1320, h: 2868 },
  { label: '6.5"', w: 1284, h: 2778 },
  { label: '6.3"', w: 1206, h: 2622 },
  { label: '6.1"', w: 1125, h: 2436 },
] as const;

Design at the LARGEST size (1320x2868) and scale down for export.

Rendering Strategy

Each screenshot is designed at full resolution (1320x2868px). Two copies exist:

  1. Preview: CSS
    transform: scale()
    via ResizeObserver to fit a grid card
  2. Export: Offscreen at
    position: absolute; left: -9999px
    at true resolution

Phone Mockup Component

The included

mockup.png
has these pre-measured values:

const MK_W = 1022;  // mockup image width
const MK_H = 2082;  // mockup image height
const SC_L = (52 / MK_W) * 100;   // screen left offset %
const SC_T = (46 / MK_H) * 100;   // screen top offset %
const SC_W = (918 / MK_W) * 100;  // screen width %
const SC_H = (1990 / MK_H) * 100; // screen height %
const SC_RX = (126 / 918) * 100;  // border-radius x %
const SC_RY = (126 / 1990) * 100; // border-radius y %
function Phone({ src, alt, style, className = "" }: {
  src: string; alt: string; style?: React.CSSProperties; className?: string;
}) {
  return (
    <div className={`relative ${className}`}
      style={{ aspectRatio: `${MK_W}/${MK_H}`, ...style }}>
      <img src="/mockup.png" alt=""
        className="block w-full h-full" draggable={false} />
      <div className="absolute z-10 overflow-hidden"
        style={{
          left: `${SC_L}%`, top: `${SC_T}%`,
          width: `${SC_W}%`, height: `${SC_H}%`,
          borderRadius: `${SC_RX}% / ${SC_RY}%`,
        }}>
        <img src={src} alt={alt}
          className="block w-full h-full object-cover object-top"
          draggable={false} />
      </div>
    </div>
  );
}

Typography (Resolution-Independent)

All sizing relative to canvas width W:

ElementSizeWeightLine Height
Category label
W * 0.028
600 (semibold)default
Headline
W * 0.09
to
W * 0.1
700 (bold)1.0
Hero headline
W * 0.1
700 (bold)0.92

Phone Placement Patterns

Vary across slides — NEVER use the same layout twice in a row:

Centered phone (hero, single-feature):

bottom: 0, width: "82-86%", translateX(-50%) translateY(12-14%)

Two phones layered (comparison):

Back: left: "-8%", width: "65%", rotate(-4deg), opacity: 0.55
Front: right: "-4%", width: "82%", translateY(10%)

Phone + floating elements (only if user provided component PNGs):

Cards should NOT block the phone's main content.
Position at edges, slight rotation (2-5deg), drop shadows.
If distracting, push partially off-screen or make smaller.

"More Features" Slide (Optional)

Dark/contrast background with app icon, headline ("And so much more."), and feature pills. Can include a "Coming Soon" section with dimmer pills.

Step 6: Export

Why html-to-image, NOT html2canvas

html2canvas
breaks on CSS filters, gradients, drop-shadow, backdrop-filter, and complex clipping.
html-to-image
uses native browser SVG serialization — handles all CSS faithfully.

Export Implementation

import { toPng } from "html-to-image";

// Before capture: move element on-screen
el.style.left = "0px";
el.style.opacity = "1";
el.style.zIndex = "-1";

const opts = { width: W, height: H, pixelRatio: 1, cacheBust: true };

// CRITICAL: Double-call trick — first warms up fonts/images, second produces clean output
await toPng(el, opts);
const dataUrl = await toPng(el, opts);

// After capture: move back off-screen
el.style.left = "-9999px";
el.style.opacity = "";
el.style.zIndex = "";

Key Rules

  • Double-call trick: First
    toPng()
    loads fonts/images lazily. Second produces clean output. Without this, exports are blank.
  • On-screen for capture: Temporarily move to
    left: 0
    before calling
    toPng
    .
  • Offscreen container: Use
    position: absolute; left: -9999px
    (not
    fixed
    ).
  • Resizing: Load data URL into Image, draw onto canvas at target size.
  • 300ms delay between sequential exports.
  • Set
    fontFamily
    on the offscreen container.
  • Numbered filenames: Prefix exports with zero-padded index so they sort correctly:
    01-hero-1320x2868.png
    ,
    02-freshness-1320x2868.png
    , etc. Use
    String(index + 1).padStart(2, "0")
    .

Common Mistakes

MistakeFix
All slides look the sameVary phone position (center, left, right, two-phone, no-phone)
Decorative elements invisibleIncrease size and opacity — better too visible than invisible
Copy is too complex"One second at arm's length" test
Floating elements block the phoneMove off-screen edges or above the phone
Plain white/black backgroundUse gradients — even subtle ones add depth
Too clutteredRemove floating elements, simplify to phone + caption
Too simple/emptyAdd larger decorative elements, floating items at edges
Headlines use "and"Split into two slides or pick one idea
No visual contrast across slidesMix light and dark backgrounds
Export is blankUse double-call trick; move element on-screen before capture