Community图像github.com

meth0xy/store-screenshots

端到端生成 App Store 和 Google Play 截图集。从代码库中发掘应用卖点,在 iOS 模拟器和 Android 模拟器(iPhone、iPad、iPhone Duo、安卓手机和平板)上以每种语言截取真实屏幕,用 HTML Canvas 组合每张图块,包含设备边框、标题和来自本地化 JSON 文件的标注,最后使用 Playwright 渲染每个语言 x 设备的组合。用于创建商店截图集、添加语言、添加设备尺寸或重建保持文本和 UI 精确不变的截图集。

store-screenshots 是什么?

这个技能提供了一个端到端的流水线,用于自动创建 App Store 和 Google Play 的截图集。它通过分析代码库来识别应用的核心卖点(benefits),然后将这些卖点组织成幻灯片结构。关键的创新在于将截图集视为数据而非生成的图像:每个图块都是一个 HTML Canvas,由背景、标题、包含真实截图的设备框架以及从屏幕中提取的 3D 标注(breakouts)分层构成。所有文本字符串都存储在 `locales/<locale>.json` 文件中,因此添加新语言只需创建一个新的 JSON 文件和对应的设备截图,并且渲染过程是确定性的:相同的输入保证产生完全相同的像素输出。该技能广泛支持多个平台和模拟器设备,包括 iPhone(6.7 英寸)、iPad 13 英寸、Android 手机和平板,以及 iPhone Duo 折叠屏。它适用于 Claude Code、Cursor 和 Codex 等 AI 编码代理,通过一系列命令行工具(Python 脚本)实现,包括 `capture.py`(在真实或模拟器上截图)、`render.py`(合成最终图块)、`add_locale.py`(添加新语言)和 `measure.py`(精确测量像素坐标以放置标注)。整个流水线分为 9 个步骤:从分析卖点开始,设计幻灯片,配置 `capture.json`,在模拟器上截图,组合设计,设置背景,配置 `set.json` 和本地化文件,渲染最终图像,以及审查结果。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/meth0xy/store-screenshots/tree/HEAD/skills/store-screenshots

Installed? Explore more 图像 skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

你将商店截图集构建为数据,而非生成的图像。每个图块都是一个 HTML Canvas,包含多层:背景、标题、一个带有真实截图的设备框架,以及从屏幕中提取的 3D 标注(截取部分或矢量文字标注)。每个字符串都存储在 locales/<locale>.json 中,因此添加新语言只需一个 JSON 文件和对应的截图,并且渲染过程是确定性的:相同的输入产生相同的像素。

下面的 $S 是这个 SKILL.md 文件所在的文件夹,$PY 是 $S/.venv/bin/python。如果虚拟环境不存在,请创建一次:

python3 -m venv $S/.venv && $S/.venv/bin/pip install -r $S/requirements.txt && $S/.venv/bin/playwright install chromium

流水线:

1 卖点 -> 2 幻灯片 -> 3 capture.json -> 4 截图 (模拟器) -> 5 组合
-> 6 背景 -> 7 set.json + 本地化文件 -> 8 渲染 -> 9 审查 -> (更多语言, 更多设备)

仓库中的 $S/../../examples/demo/ 是一个完整的项目(虚构应用,两种语言,五个设备)。在编写自己的 set.json 之前,请先阅读它。

项目布局

<project>/
  capture.json                  应用、截图设备、需要截图的屏幕
  set.json                      所有语言共享的组合配置
  locales/<locale>.json          每个字符串:动词、副标题、标注文本
  sim/<locale>/<slide>.png       手机截图(每个截图集一个文件夹)
  sim-tablet/  sim-duo/  sim-android/
  fonts/  assets/                可选字体、背景图片、道具
  out/<locale>/<device>/         仅限商店文件
  out/_sheets/                   每个语言和设备的联系表
  out/_captures/                 每种语言截图后的联系表

建议将 store-screenshots/ 放在应用仓库的根目录。将 out/ 和 .cache/ 添加到其 .gitignore。


1. 卖点

阅读代码库:导航(标签页、路由、屏幕)、引导文案、付费墙文案、README、现有的商店列表。列出 5 到 8 个用户获得的好处,按它们能推动安装的程度排序。每张幻灯片一个卖点。

每张幻灯片的标题是一个简短的大写动词加上最多两行的副标题:PLAN / YOUR WEEK IN MINUTES,SAVE / ON EVERY SHOP。动词命名的是好处,而不是功能。展示列表,并附上能证明每个卖点的屏幕,获得用户确认。

2. 幻灯片

ID 格式为 NN-name;数字是商店中的位置。为每个幻灯片选择屏幕并记录其所需状态(已登录、数据存在、某面板打开)。对图片密集的屏幕使用倾斜,对数据密集的屏幕保持平直。

3. capture.json

从 $S/templates/capture.json 开始。

键含义
app.iosbundleId,以及 app(指向模拟器 .app 构建的路径)或 copyFrom(已安装应用的模拟器 UDID)
app.androidpackage,可选的 activity,可选的要安装的 apk
devices.<key>platform ios 或 android,dir(截图文件夹),iOS:name(专用模拟器,由 setup 创建)和 type(xcrun simctl list devicetypes),可选的 runtime;Android:avd(emulator -list-avds)
设备额外选项appearance(light),locale(覆盖下面的模式),displaySize(2853x2007 用于 iPhone Duo 内屏),rotate(角度,用于横向截图的校正)
locale每个平台。iOS 使用 reboot(默认,最可靠)、relaunch(不重启,保持折叠屏姿态)或 launchArgs。Android 使用 app(默认,Android 13+ 的每应用语言,需要应用的 localeConfig)或 system(需要 root 权限的模拟器镜像)
launch启动后的 wait 秒数,可选的 url(用于替代启动,如 Expo 开发客户端 URL),可选的 steps
screens{id, steps, ready, after, devices, copyFrom} 列表,以及通过 byDevice/byLocale 块合并到屏幕上的内容

步骤按顺序执行,每个步骤都带有等待时间(wait,默认 1 到 2 秒):

步骤效果
{"open": "myapp://route"}深度链接。优于点击操作:在所有设备和平台上都有效
{"tap": {"label": "Save"}}点击具有该无障碍标签的元素(或 {"id": ...}),精确匹配然后子串匹配
{"tap": {"at": [0.5, 0.9]}}在屏幕的某个比例位置点击
{"tap": {...}, "until": {"label": "Details"}}一直点击(最多 3 次)直到该元素出现;用于屏幕还在稳定时的点击
{"waitFor": {"label": "Done", "timeout": 20}}等待直到屏幕上出现某个元素,用于加载或动画中的屏幕点击前
{"type": "pasta"}, {"key": "enter"}, {"key": "back"}文本和按键
{"swipe": [0.5, 0.8, 0.5, 0.3]}滑动,使用比例坐标
{"launch": true}重启应用

ready: {"region": [x, y, w, h], "minStd": 20, "tries": 5, "delay": 3} 会在该区域颜色单一(加载骨架行、旋转指示器、正在加载的图片)时重新截图。iPhone 截图会在模拟器渲染了灵动岛后自动重试。

copyFrom: "01-home" 会在该设备上复用另一张截图(例如平板电脑以分屏视图显示两个屏幕)。devices: ["phone"] 将屏幕限制在某些设备上。

capture.py PROJECT describe --device phone 会打印带有标签和框架的可点击元素。

4. 截图

$PY $S/capture.py <project> doctor              # 工具、设备、应用 ID
$PY $S/capture.py <project> setup               # 创建/启动专用模拟器,启动 AVD,安装应用
$PY $S/capture.py <project> run --locale en-US  # 每个设备和屏幕
$PY $S/capture.py <project> run --locale en-US --device phone --screen 03-search
  • 截图设备是专用的:iOS 模拟器按名称创建(Capture iPhone ...),Android 使用 capture.json 中命名的 AVD。绝不要将 capture.json 指向用户正在使用的模拟器,并在启动设备或切换其语言之前征询同意。
  • 在 setup 之后,应用通常需要演示状态:登录到演示账户、填充数据、关闭首次运行对话框(保存密码、通知、评价提示)。在每个设备上只做一次;该状态在语言切换后仍然保持。向用户询问演示凭据,绝不要将其写入 capture.json。
  • 显示调试覆盖层(开发菜单按钮、Toast)的开发构建需要为截图会话隐藏这些内容。在本地修补它们,并且不要提交该修补。
  • 逐张检查 out/_captures/<locale>.jpg:没有其他语言的字符串,没有对话框、Toast、旋转指示器或空状态。修复数据或步骤,然后重新运行该屏幕。渲染器会原样显示截图;不会对错误进行任何涂抹。
  • iPhone Duo:首先在 Simulator 或 DeviceHub 中展开模拟器并置于横屏;simctl 无法折叠或旋转。使用深度链接(HID 点击可能无法到达内屏),"locale": "relaunch" 和 "displaySize": "2853x2007"。

跨平台应用(React Native、Flutter)可以跳过 Android 截图:Android 图块会复用 iPhone 和 iPad 的截图,这也是默认设备所做的。原生 Android 应用会将其屏幕截图到 sim-android/,请参见第 10 节。

5. 组合(渲染前用户需批准)

用 ASCII 草图绘制每张幻灯片:标题、设备位置和倾斜度、哪个元素被提取出来以及它落在何处。获得同意后,再编写 set.json。

 +------------------------------+
 |            WATER             |  动词,一行
 |      EVERY PLANT RIGHT       |  副标题,最多两行
 |          ON TIME             |
 |      .--------------.        |
 |  [* 3 plants today]          |  标注,被提取,向左突出
 |      |  Today ...   |        |  设备倾斜 y 15, x 4
 +------------------------------+

6. 背景

每个截图集一个背景,所有语言和设备共享。可以是 CSS("background": {"css": "radial-gradient(...), #1f4a37"},演示中使用了这个)或图片({"image": "assets/bg.png"},background-size cover)。图片生成器适用于柔和的背景;提示生成一个无缝的 9:16 演播室背景,使用品牌色调和柔和光线,并明确指出:没有物体、没有文字、没有设备、没有形状。生成两个,让用户选择。道具(贴纸、产品照片)是带有透明通道的 PNG,按幻灯片放置。

7. set.json 和本地化文件

使用 measure.py 以截图像素为单位测量每个矩形,不要凭目测:

$PY $S/measure.py sim/en-US/05-fill.png --at 700,790            # 泛洪填充按钮、芯片、药丸形状
$PY $S/measure.py sim/en-US/01-plan.png --ink 40,415,700,75     # 在纯色区域上的文本边界
$PY $S/measure.py sim/en-US/02-cook.png --grid 440,1510,340,110  # 临时目录中的缩放网格图像
键含义
locales, devices完整渲染覆盖的范围;设备 ID 来自 $S/devices/devices.json
background{"image": ...} 或 {"css": ...},可选的 position
fonts{"family": "fonts/File.otf"},路径相对于项目;默认 display 字体是自带的 Archivo Black
headlinefont, descFont, verbColor, descColor, shadow, verbTracking, descTracking, descWordSpacing
captureplatform, statusBarBand(截图行被混合掉,iOS 默认 [66, 128]),sets({"tablet": {"dir": "sim-tablet", "statusBarBand": [12, 56]}}),devices({"android-phone": "android"} 将设备指向另一个截图集)
stylegloss, deviceShadow, thicknessRatio(侧面墙壁深度),sideLayers
statusBar渲染器绘制的状态栏的 time、color
layout按设备 ID,覆盖 devices.json 中的布局(deviceTop, deviceWidth, verbMax ...)
baseline实时截图集的 {device: {locale: folder}},用于 --compare
slides列表,见下方

幻灯片:id,sim(如果截图文件名不是 <id>.png 时使用),tilt {x, y, z} 度,offset {x, y} 画布比例,layout,breakouts,props(src,x,y,w 画布比例,rotate,shadow,z:front 或 back)。

标注(Breakout):

键含义
typecrop:截图自身的像素;callout:带有本地化文本的矢量药丸形状
rect 或 anchor来源元素在截图像素中的 [x, y, w, h]
at 或 dx/dy落点位置(at = 在截图像素中的新左上角)或偏移量
scale, lift大小和 Z 轴提升(像素,默认 80)
vacate, vacatePad用周围颜色填充原始位置(移动,而不是复制)
radius, shadow, origin圆角半径(截图像素)、阴影强度、变换原点
text, icon, stylecallout:本地化文件 callouts 中的键,tag 或 sparkles,以及 font,size,bg,fg,padX,padY,gap,radius,weight,tracking,iconScale,iconColor

slides 中的任何值都可以按设备和按语言变化:{"byDevice": {"phone": ..., "tablet": ..., "default": ...}}(键:设备 ID、截图集、default)和 {"byLocale": {"de-DE": ..., "default": ...}},两者可以嵌套。矩形几乎总是按语言变化,因为同一个芯片在德语中会更宽。

裁剪(Crop)对于大元素可以在最大约 1.7 倍缩放时保持清晰。小的芯片和文本会变成 callout(矢量),在任何缩放比例下都保持清晰。

本地化文件:

{
  "captures": "en-US",
  "dir": "ltr",
  "fonts": {"display": "fonts/NotoSansJP-Black.otf"},
  "slides": {
    "01-plan": {"verb": "Plan", "desc": "Your week in minutes", "callouts": {"savings": "approx. €7.81 saved"}}
  }
}

只有 slides 是必需的。captures 使一个语言复用另一个语言的截图(例如 en-GB 读取 en-US)。headline 和 statusBar 会覆盖 set.json 中的设置。Archivo Black 只覆盖拉丁字符;西里尔文、希腊文、中日韩文字、阿拉伯文和希伯来文需要 fonts 覆盖,从右到左的文字需要 "dir": "rtl"。

8. 渲染

$PY $S/render.py <project>                                  # 渲染所有内容
$PY $S/render.py <project> --locale de-DE --device iphone-67 --slide 01-plan
$PY $S/render.py <project> --compare                        # 基线 vs 新版本联系表

标题大小在某个语言和设备的幻灯片之间共享,因此整套看起来像一个整体。当截图的宽高比与设备屏幕开口不匹配时,渲染器会停止。

9. 审查

打开 out/_sheets/<locale>-<device>.jpg 并放大查看每个标注。打印为 CHECK 的行会命名问题(标题最小尺寸,重叠)。标题达到最小尺寸意味着文案太长:缩短它,不要降低限制。向用户展示联系表。

10. 更多语言和设备

添加语言:

$PY $S/add_locale.py <project> es-ES init --from en-US     # 本地化文件、byLocale 占位符、文件夹
$PY $S/capture.py <project> run --locale es-ES             # 截图
#   翻译 locales/es-ES.json:商店文案、简短动词、与截图匹配的标注
$PY $S/add_locale.py <project> es-ES measure --from en-US  # 重新查找矩形位置,审查并排图像
$PY $S/add_locale.py <project> es-ES measure --from en-US --write
$PY $S/add_locale.py <project> es-ES check                 # 渲染前确保 0 错误
$PY $S/render.py <project> --locale es-ES

区域变体(en-GB、de-AT、fr-CA):使用 init --share-captures,然后只需更改文本。

$S/devices/devices.json 中的设备:

id画布读取商店插槽
iphone-671290x2796手机 (1206x2622)ASC APP_IPHONE_67
android-phone1080x1920手机Play 手机截图
ipad-132064x2752平板 (2064x2752)ASC APP_IPAD_PRO_3GEN_129
android-tablet1792x2400平板Play 7 英寸和 10 英寸平板
iphone-duo2853x2007duo (2853x2007)ASC iPhone Duo

这些框架是用 make_frame.py 生成的通用图形,可自由分发。没有匹配框架的截图尺寸会生成一个:

# 原生 Android 截图,1080x2400,放入 sim-android/
$PY $S/make_frame.py --style android --screen 1080x2400 --device android-phone --captures android
# 然后在 set.json 中:"capture": {"sets": {"android": {"dir": "sim-android", "statusBarBand": [30, 105]}}}

样式:ios、android、tablet、landscape。--canvas WxH 设置新设备 ID 的商店尺寸。在真实截图上测量 statusBarBand:状态栏的行数加上一些保留区域。


设备框架

设备框架位于 $S/devices/frames/,由 $S/make_frame.py 生成。它们是简单的几何绘图,不包含来自品牌手机的闯入性图像,因此分发没有法律问题。

主要设备及其框架:

  • iPhone 6.7 英寸 (iphone-67):细长圆角矩形,带有动态岛的凹口。
  • Android 手机 (android-phone):带圆角的矩形,薄边框。
  • iPad 13 英寸 (ipad-13):更大的矩形,平直的顶部和底部边缘,Home 指示器条。
  • Android 平板 (android-tablet):中等矩形,横屏方向。
  • iPhone Duo (iphone-duo):横屏的大折叠设备,带有显示铰链的中间折痕。

每个框架都放置在 HTML Canvas 上,并可以相对于画布进行定位和倾斜。


常见工作流程

从头开始创建一个新的截图集

# 1. 创建项目结构
$PY $S/create_project.py my-app --app-path /path/to/app

# 2. 分析代码库以获取卖点
# (手动步骤,与 AI 协作)

# 3. 设置截图设备
$PY $S/capture.py my-app setup

# 4. 截取第一个语言的屏幕
$PY $S/capture.py my-app run --locale en-US

# 5. 组合幻灯片(在 set.json 中编写)

# 6. 渲染
$PY $S/render.py my-app

# 7. 审查并迭代

为现有截图集添加新语言

$PY $S/add_locale.py my-app fr-FR init --from en-US
# 翻译 locales/fr-FR.json
$PY $S/capture.py my-app run --locale fr-FR
$PY $S/add_locale.py my-app fr-FR measure --from en-US --write
$PY $S/add_locale.py my-app fr-FR check
$PY $S/render.py my-app --locale fr-FR

添加新设备

# 在 capture.json 中添加设备定义
# 在 devices.json 中添加设备 ID 和布局
$PY $S/make_frame.py --style ios --screen 1290x2796 --device new-iphone --captures phone
# 为舌头设备截图
$PY $S/capture.py my-app run --locale en-US --device new-iphone
# 渲染该设备
$PY $S/render.py my-app --device new-iphone

最佳实践

  1. 卖点第一:始终从分析代码库中的卖点开始。商店截图应传达价值,而不仅仅是功能。
  2. 稀疏截图:每张幻灯片只突出一个主要卖点。避免杂乱的布局。
  3. 一致的标题样式:对所有幻灯片使用相同的字体、大小和颜色,以保持品牌统一。
  4. 清晰的标注:确保标注(callouts)指向屏幕上的正确元素,并使用清晰、可操作的文本。
  5. 跨语言测试:为每个目标语言截图和渲染,验证位置和文本在多语言中是否合适。
  6. 版本控制:将 out/ 和 .cache/ 添加到 .gitignore,但跟踪 capture.json、set.json、locales/ 和 fonts/。
  7. ISO 镜像:使用 --locale 参数为多个区域设置生成截图,每个区域设置有自己的本地化文件和文本。
  8. 自动化 CI/CD:将截图生成集成到 CI 流程中,以便在每次应用更新时自动更新商店截图。

故障排除

问题解决
setup 无法创建模拟器确保 xcrun simctl 已安装,并且 macOS 版本支持所需的 iOS 版本
模拟器无法启动检查模拟器镜像是否可用:xcrun simctl list runtimes
Android 模拟器无法启动确保 emulator 在 PATH 中,并且 AVD 名称正确
截图步进过程中元素未找到使用 capture.py PROJECT describe 检查可访问性标签。考虑使用深度链接代替点击
渲染时截图宽高比不匹配检查 capture.json 中的 devices 和 screens 配置。确保模拟器窗口大小与设备 screen 尺寸匹配
语言切换后应用状态丢失检查 capture.json 中的 locale 设置。对于每应用语言(Android 13+),使用 "mode": "app"
动态岛出现在截图中自动重新截图。如果问题持续存在,增加 ready 重试次数或使用 statusBarBand 混合
字体不支持某些字符在语言配置的 fonts 中提供自定义字体,使用 "dir": "rtl" 处理 RTL 语言
标注错位使用 measure.py 正确测量元素位置。在 byLocale 中提供特定于语言的矩形

相关技能