本文へ移動
cccskills
無料GitHub で公開

play-store-screenshots

Never invoke implicitly; use only when explicitly asked for Play Store assets. Builds or updates RIPDPI's marketing screenshots and feature graphic (Next.js generator in play-store-screenshots/).

インストール方法を見る

含まれるファイル(2)

  • SKILL.md18.4 KB
  • agents/openai.yaml307 B

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Google Play Screenshots Generator (RIPDPI)

Overview

Build or update the Next.js page in play-store-screenshots/ that renders Google Play Store screenshots as designed store artwork with accurate app UI and exports them via html-to-image + Puppeteer batch capture at Google Play's required resolutions.

Google Play constraints:

  • Max 8 screenshots per device type (phone, 7" tablet, 10" tablet)
  • Text overlay must not exceed 20% of the screenshot area
  • No promotional text (pricing, rankings, awards)
  • 24-bit PNG or JPEG only (no alpha transparency)
  • Max 8 MB per image
  • Minimum 2 screenshots to publish, 4+ recommended for visibility

Core Principle

Each screenshot communicates one supported capability. Show the real app experience, and prioritize actual UI in the first three screenshots. Preserve the captured state, warnings and disabled controls. Use short headings to explain the capability without promising an unverified outcome. Do not invent settings, measurements or active connections.

Follow the Google Play preview-asset requirements. They take precedence over older marketing examples in this skill.

Existing Project Structure

The generator already exists at play-store-screenshots/. Check if it needs updating rather than scaffolding from scratch. For the current file layout, asset sources and resolutions, brand/logo state, and the two-stage raw-capture-to-rendered-output pipeline, read play-store-screenshots/AGENTS.md first -- it is the canonical, actively-verified source for those facts; do not re-derive them here.

Screenshot quality floor: only use the high-res Stage-1 captures in public/screenshots/ (see AGENTS.md for the current resolution and file list). The Roborazzi test screenshots under app/src/test/screenshots/ are too low-resolution for Play Store quality (420x900 to 720x920) -- if a screen is only available as a test screenshot, use a text-focused slide instead.

Step 1: Confirm RIPDPI Defaults with the User

Pre-Filled from DESIGN.md (confirm, don't ask from scratch)

All colors come from the project's design system (DESIGN.md / RipDpiExtendedColors). The Play Store screenshots use these tokens for brand consistency.

Brand-palette note: the repo-root DESIGN.md (alpha) is monochrome-first light (#FAFAFA background, #1A1A1A foreground). Marketing slides honor the design system: light, monochrome-first, restrained semantic color, no decorative gradients. BRAND_LIGHT is the canonical default; BRAND (the strict dark inversion) is kept for at most 1-2 rhythm-break slides per set and uses the same role mapping, not a separate visual identity.

ItemDefault
App nameRIPDPI
Design philosophyMonochrome-first, semantic color for status only. Technical, precise, utilitarian.
Font familiesGeist Sans (Latin copy), Vazirmatn v33.003 for fa, Geist Mono (values/configs); preserve the app fonts in raw captures

Light Theme Tokens (canonical default)

const BRAND_LIGHT = {
  bg: "#FAFAFA",           // background
  card: "#FFFFFF",         // card
  text: "#1A1A1A",         // foreground
  muted: "#F5F5F5",        // muted
  mutedFg: "#575757",      // mutedForeground
  accent: "#E8E8E8",       // accent
  border: "#E0E0E0",       // border
  success: "#047857",      // success
  warning: "#B45309",      // warning
  error: "#B91C1C",        // destructive
  info: "#1D4ED8",         // info
  restricted: "#6B7280",   // restricted
} as const;

Dark Theme Tokens (strict inversion — same role mapping)

Use sparingly for at most 1-2 rhythm-break slides. Status colors are slightly lighter than light-theme variants for dark-surface contrast — never bright.

const BRAND = {
  bg: "#1A1A1A",           // background
  card: "#1F1F1F",         // card
  text: "#FAFAFA",         // foreground
  muted: "#262626",        // muted
  mutedFg: "#A3A3A3",      // mutedForeground
  accent: "#2A2A2A",       // accent
  border: "#2A2A2A",       // border
  success: "#10B981",      // success
  warning: "#D97706",      // warning
  error: "#DC2626",        // destructive
  info: "#3B82F6",         // info
  restricted: "#6B7280",   // restricted
} as const;

Shape Tokens (from RipDpiShapeTokens)

TokenRadiusUsage in screenshots
xl16dpButtons, cards, text fields
xlIncreased20dpExpressive interactive surfaces
xxl28dpPills, FABs
full50%Avatars, status dots

Use these for screenshot frame corners (40px = ~3.7% of 1080px width) and UI element pills.

Typography Reference

ElementFamilyWeightCurrent full-size text
Phone headlineGeist Sans or pinned locale font700100px at 1080w
Phone explanationSame locale font400At least 48px at 1080w
Banner wordmarkGeist Sans70064px at 1024w
Banner value statementLocale font40056px at 1024w

M3 Expressive principle: Prefer weight promotion (400->500->700) over size increase for emphasis.

| Feature list | 1. path optimization (proxy + VPN modes) 2. No root required 3. Advanced strategy controls (TCP, QUIC, DNS) 4. Encrypted DNS (DoH/DoT/DNSCrypt) 5. Integrated diagnostics & monitoring 6. Per-network policies 7. Works with AdGuard 8. Session telemetry & export | | Style direction | Light, monochrome-first. Restrained semantic color (use info/success/warning only when the state itself matters). No decorative gradients on any slide — DESIGN.md forbids them in-app and the marketing surface honors the same rule. |

Confirm missing requirements

For an existing generator, keep its configured slide count and locales unless the user asks to change them. A request to implement banners includes the feature graphic. Ask only when a missing requirement could change the result; otherwise use the existing project defaults and proceed.

  1. Number of slides -- "How many screenshots do you want? (Google Play allows up to 8)"
  2. Feature Graphic -- "Shall I generate a Feature Graphic (1024x500)? It's required for Play Store listings."
  3. Localized screenshots -- "Do you want screenshots in multiple languages? If yes, which languages?"
  4. Additional instructions -- "Any specific requirements or preferences?"

IMPORTANT: If the user says "figure it out" or similar, use the defaults and proceed without asking.

Derived (do NOT ask)

  • Background style: flat solid backgrounds only (no gradients). BRAND_LIGHT.bg (#FAFAFA) for the canonical light slides; BRAND.bg (#1A1A1A) for the rare rhythm-break dark slide.
  • Decorative elements: subtle low-opacity monochrome Grid pattern is the only allowed decoration. No radial glow orbs, no circuit-board, no shield motifs — these read as consumer-dashboard flourish and violate the design system.
  • Light vs dark slides: light-first (matches DESIGN.md). At most 1-2 of 6 slides may use the dark inversion for visual rhythm; never more.
  • Screenshot placement: use top positioning (not bottom + translateY) to precisely control where screenshots start below headlines

Step 2: Set Up / Update the Project

If project already exists

cd play-store-screenshots
bun install  # or npm install

public/screenshots/ holds the raw Stage-1 app captures (see play-store-screenshots/AGENTS.md's Two-Stage Pipeline section). If a screen's UI changed, re-capture it from a device per that file's Stage 1 instructions -- do not copy from docs/screenshots/, which holds the rendered Stage-2 marketing outputs, not a source for raw captures.

If scaffolding new (only if the project does not already exist)

Package manager priority: bun > pnpm > yarn > npm

bunx create-next-app@latest play-store-screenshots --typescript --tailwind --app --src-dir --no-eslint --import-alias "@/*"
cd play-store-screenshots
bun add html-to-image
bun add -d puppeteer
bun pm trust puppeteer  # allow postinstall to download Chromium

Copy the app icon, then seed public/screenshots/ with fresh Stage-1 device captures per play-store-screenshots/AGENTS.md:

mkdir -p public/screenshots
cp ../app/src/main/ic_launcher-playstore.png public/app-icon.png
# then follow AGENTS.md's Stage 1 capture steps to populate public/screenshots/*.png

Font Setup (Next.js 16+)

Next.js 16 ships Geist fonts natively via next/font/google:

// src/app/layout.tsx
import { Geist, Geist_Mono } from "next/font/google";
const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] });
const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] });

Use var(--font-geist-sans) and var(--font-geist-mono) in slide styles.

Next.js 16 Caveats

  • useSearchParams requires Suspense: Wrap the main component in <Suspense> to avoid build failures during static prerendering.
  • Production build for capture: bun run build && bun run start -- the dev server HMR websocket causes Puppeteer and Chrome DevTools navigation timeouts.

Step 3: Plan the Slides

Screenshot Framework (Narrative Arc)

SlotPurposeRIPDPI Suggestion
#1ConnectionComplete Home frame with real service state
#2DiagnosticsCompleted real run and its actual results
#3Relay configurationComplete relay controls with a meaningful viewport
#4DNS optionsActual DNS settings screen
#5Packet strategiesActual packet strategy controls
#6BackupsActual backup and restore screen; one clear function

Rules:

  • Each slide sells ONE idea
  • Vary layouts -- never repeat the same template structure in adjacent slides
  • Light-first: at most 1-2 of 6 slides may be the dark inversion, for rhythm only
  • Text overlay must not exceed 20% of the screenshot area
  • Slides with no high-res screenshot available should be text-focused (feature cards, protocol pills, etc.)

Step 4: Write Copy FIRST

The Iron Rules

  1. One idea per headline. Never join two things with "and."
  2. Short, common words. 1-2 syllables. No jargon unless domain-specific.
  3. 3-5 words per line. Readable at thumbnail size.
  4. Line breaks are intentional. Control with <br />.
  5. Max 20% text overlay.

Three Approaches (pick one per slide)

TypeWhat it doesExample
Paint a momentYou picture yourself doing it"Open any site. No extra steps."
State an outcomeWhat your life looks like after"The internet you were promised."
Kill a painName a problem and destroy it"No more blocked pages."

Step 5: Build the Page

Architecture

The entire generator is a single page.tsx file:

page.tsx
├── Constants (PHONE_W/H, FEATURE_GRAPHIC, BRAND tokens)
├── Screenshot component (frameless, 40px border-radius, bgColor prop)
├── Caption component (label + headline)
├── Decorative components (Glow, Grid, Pill)
├── Slide container component
├── Slide1..N components (one per slide)
├── FeatureGraphicSlide component (1024x500)
├── SLIDES array (registry)
├── ScreenshotPreview (ResizeObserver scaling + click-to-export)
├── ScreenshotsPage (grid + export logic)
└── Page wrapper (Suspense boundary)

Key Dimensions

const PHONE_W = 1080;
const PHONE_H = 1920;
const FEATURE_GRAPHIC = { w: 1024, h: 500 };

Screenshot Component (Frameless)

function Screenshot({ src, alt, style, bgColor = "#ffffff" }: {
  src: string; alt: string; style?: React.CSSProperties; bgColor?: string;
}) {
  return (
    <div style={{ position: "relative", ...style }}>
      <div style={{
        width: "100%", height: "100%",
        borderRadius: 40,  // ~3.7% of 1080px, close to xl (16dp) scaled up
        overflow: "hidden",
        boxShadow: "0 12px 60px rgba(0,0,0,0.5)",
        background: bgColor,
      }}>
        <img src={src} alt={alt}
          style={{ display: "block", width: "100%", height: "100%",
            objectFit: "cover", objectPosition: "top" }}
          draggable={false} />
      </div>
    </div>
  );
}

UI frame placement (Critical)

The current source frames are 1080x1800. Use their exact aspect ratio and scale the complete frame to fit below the headline. Use top positioning and check both bottom and side margins. Do not crop or stretch the real UI:

// Fit the complete frame below a compact heading
<Screenshot src="/screenshots/home-light.png" alt="Home"
  style={{
    position: "absolute",
    top: 310,           // precise control -- no overlap
    left: "50%",
    transform: "translateX(-50%)",
    width: 840,
    aspectRatio: "1080/1800",
  }}
/>

Never use bottom: 0 + translateY(N%) for complete source screenshots -- the percentage math is hard to get right and leads to overlap or excessive gaps.

Single-Slide Mode

Support ?slide=N (1-6) and ?slide=fg for headless capture:

export default function Page() {
  return (
    <Suspense fallback={<div style={{ background: "#0a0a0a", minHeight: "100vh" }} />}>
      <ScreenshotsPage />
    </Suspense>
  );
}

function ScreenshotsPage() {
  const searchParams = useSearchParams();
  const slideParam = searchParams.get("slide");
  if (slideParam) {
    if (slideParam === "fg") return <FeatureGraphicSlide />;
    const idx = parseInt(slideParam) - 1;
    const slide = SLIDES[idx];
    if (slide) { const C = slide.component; return <C />; }
  }
  // ... grid view with export
}

Step 6: Export

Browser Export (interactive)

import { toJpeg } from "html-to-image";
const opts = { width: w, height: h, pixelRatio: 1, quality: 1, cacheBust: true, backgroundColor: "#FAFAFA" };
await toJpeg(el, opts);  // warm-up call
const dataUrl = await toJpeg(el, opts);  // actual JPEG capture

Puppeteer Batch Export (headless)

Prefer bun run capture:prod (see play-store-screenshots/AGENTS.md's Common Workflows table) -- it builds, boots the production server, runs the capture, and always tears the server down. The manual equivalent, against a production build (dev server HMR causes timeouts):

bun run build && bun run start -- -p 3099 &
node capture.mjs
// capture.mjs
import puppeteer from "puppeteer";
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
for (const slide of SLIDES) {
  await page.setViewport({ width: slide.w, height: slide.h, deviceScaleFactor: 1 });
  await page.goto(`http://localhost:3099/?slide=${slide.param}`, { waitUntil: "load", timeout: 60000 });
  await new Promise(r => setTimeout(r, 2000));  // fonts + images
  await page.screenshot({ path: outPath, type: "png", clip: { x: 0, y: 0, width: slide.w, height: slide.h } });
}

Captured images go to docs/screenshots/ for README usage.

Key Export Rules

  • Double-call trick for html-to-image: first call warms up fonts/images
  • Formats: Browser downloads use opaque JPEG. Batch capture uses RGB PNG, checked by the strict asset validator. Background color alone does not change a canvas PNG from RGBA to RGB.
  • Numbered filenames: 01-hero.png, 02-no-root.png, etc.
  • Feature Graphic filename: feature-graphic.png
  • Production server only for Puppeteer -- dev server HMR websocket causes infinite loading

Step 7: Final QA Gate

Google Play Compliance

  • No alpha transparency; batch PNG color type is checked, browser export is JPEG
  • Text overlay <= 20% of screenshot area
  • No promotional pricing, rankings, or awards
  • Aspect ratio valid (1920/1080 = 1.78, passes max 2:1)
  • Minimum 4 screenshots
  • Feature Graphic exactly 1024x500
  • Each file under 8 MB
  • Batch assets are 24-bit PNG; browser downloads are JPEG

Visual Quality

  • Each advertised function is visible in its actual app frame; no repeated Home used as evidence for another function
  • Key headings and explanations remain readable at 260px poster width and 360px banner width
  • No orphan headings or clipped controls, warnings, or explanations in the chosen source viewport. Long result lists may continue below the viewport.
  • All seven locale sets pass full-size and thumbnail review; Persian font and grouped RTL branding are verified
  • No repeated layouts in adjacent slides
  • No text/screenshot overlap
  • Screenshots fully contained (no clipping at edges)
  • At least 1 light contrast slide for rhythm
  • Decorative elements don't cover app UI

Design System Alignment

  • Colors match DESIGN.md tokens (light canonical: #FAFAFA bg, #1A1A1A text, #1D4ED8 info; dark inversion: #1A1A1A bg, #FAFAFA text, #3B82F6 info)
  • Font families are Geist Sans (headlines, labels) and Geist Mono (pills, badges, values)
  • Weight emphasis follows M3 Expressive principle (400->500->700, not size increase)
  • Pill/badge corners use design system radii (12-16px range)

Common Mistakes

MistakeFix
Text overlaps phone screenshotUse top positioning, not bottom + translateY
Screenshot clipped at edgesUse left/right: "4%" not negative values
Blank Puppeteer capturesMust use production build (bun run build && bun run start)
useSearchParams build errorWrap component in <Suspense>
Low-res screenshots look badUse only validated Stage-1 captures from play-store-screenshots/public/screenshots/; never use rendered marketing output as raw input
Decorative gradients on slidesDESIGN.md forbids them in the app and they also break the marketing brand. Use solid backgrounds plus the Grid utility for subtle texture. No linear-gradient(...) or radial-glow orbs anywhere.
Bright saturated status accentsUse restrained DESIGN.md tokens (#1D4ED8 info, #047857 success, #B45309 warning), never bubblegum-bright variants. Reserve status color for slides where the state itself matters.
All slides look the sameVary: centered phone, right-offset, left-offset, text-only, pills-only
Copy too complex"One second at arm's length" test; 3-5 words per line

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

RIPDPI's own Compose conventions: ViewModel pattern, Route/Screen split, DataStore->StateFlow, RipDpiThemeTokens. Use for how this app does Compose, not generic Compose API questions (see compose).

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月13日 更新

ADB-based RIPDPI device/emulator debugging: build/install/launch, logcat filtering, fixture port-forwarding, instrumented tests, crash/ANR triage. Use when debugging on a real device or emulator.

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月13日 更新

RIPDPI Appium launch-contract reference: start routes and permission/service/data presets. Use when a test launches to the wrong screen or a new automation route is added. General flakiness: appium-test-debug.

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月13日 更新

RIPDPI Appium test authoring: page objects, resource-id locators, assertions, wait tiers. Use when writing a new Appium test or page object, or adding coverage for a new screen.

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月13日 更新

RIPDPI Appium failure triage: flaky tests, locator/session/wait issues, screenshot and element-tree debugging. Use when an Appium test fails or is flaky.

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月13日 更新

Add or modify a GitHub Actions job. Use when editing a file under .github/workflows/. Not for running a workflow locally (local-ci-act) or release signing (release-signing).

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月13日 更新

po4yka のスキルをすべて見る

このスキルの問題を報告する