关于 play-store-screenshots
play-store-screenshots 是用于制作 Google Play 商店宣传手机截图和特色图片的技能。它引导整理功能卖点、选择素材并确认视觉设置,再生成可配置的 HTML 生成器。
主要功能
- 01制作手机截图和特色图片
- 02引导梳理功能与素材
- 03从截图提取视觉设置
- 04通过 config.js 配置输出
- 05支持 text-top 和 full-bleed 布局
适用场景
- 01准备 Play 商店商品页宣传图片
- 02将应用截图制作为商店素材
- 03生成多语言截图素材
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mobile-dev-ci/ play-store-screenshots --skill play-store-screenshots安装后在 Claude Code 中输入/play-store-screenshots确认已加载。
附带文件example-config.js
详细介绍
Play 商店截图生成器
概览与核心理念
这项技能使用 Next.js 和 html-to-image 生成以广告宣传为导向的 Google Play 商店截图。核心原则:截图是广告,不是文档。 每张幻灯片都传达一个结果、一种感受或一种解决方案,而不是带用户浏览界面。
与 Apple App Store 不同,Play 商店还需要一张宣传图(1024×500px)——这是一张横幅图片,会醒目地显示在应用的商店详情页上。这项技能将其视为与手机截图同等重要的素材。
需求确认阶段
目标是在尽可能快地开始生成的同时,避免错误假设浪费用户的时间。做法是:询问必须了解的信息,推断可以推断的信息,始终展示你的判断,并在继续前确认。
步骤 1 — 先询问,再查看
查看任何文件前,先提出一个无法推断的问题:
“你的 3–6 项主要功能是什么?请简要说明每项功能为用户解决了什么问题。”
这是一个营销决策——任何文件或截图都无法回答这个问题。用户最了解自己应用的价值主张。
如果用户只提供功能名称,却没有说明解决的问题(例如“离线模式、深色主题、收藏夹”),请追问:
“对于每项功能——如果没有这项功能,用户会觉得哪里不方便?”
在获得这些信息前,不要进入步骤 2。
步骤 2 — 扫描并查找素材
了解功能后,扫描当前目录中的素材。查找以下内容:
- 截图:当前文件夹或
screenshots/子文件夹中的.png/.jpg文件 - 应用图标:先检查 Android 的标准路径:
如果不是 Android 项目,则查找任何名为app/src/main/res/mipmap-xxxhdpi/ic_launcher.png app/src/main/res/mipmap-xxhdpi/ic_launcher.pngicon*.png、logo*.png或app-icon.*的文件
如果找到所需的文件——列出文件并询问:
“我找到了这些截图:[列表]。我会使用这些截图。这样对吗?”
如果找到了多个候选文件,无法判断哪个合适——展示这些文件并询问:
“我找到了多个 PNG 文件。哪些是要使用的应用截图?”
如果什么也没找到——直接询问:
“我在此目录中没有找到任何截图。你的 Android 应用截图保存在哪里?”
有歧义时,绝不要默默猜测。选错一个文件就会让整次运行白费。
步骤 3 — 根据截图推断视觉设置
拿到截图后,进行视觉分析并推断以下内容。编写任何代码前,先用一个简短的确认区块展示你的判断:
Here's what I picked up from your screenshots — let me know if anything looks off:
App name: Aarti Mandir
Primary: #C9822A (toolbar orange)
Background: #FFF8F0 (warm cream)
Text: #2D1A00 (dark brown)
Accent: #C9822A
Theme: editorial (warm/earthy tones)
Font: Inter (default — let me know if you use a specific font)
Frame: white (light app)
Slides: 5
只有在用户确认或更正后才能继续。在这里花 10 秒确认,可以避免因颜色错误而重新生成所有内容。
如何推断各项值:
| 值 | 推断方法 |
|---|---|
| 应用名称 | 从截图中读取(工具栏、启动画面、图标标签) |
| 主色 | 界面中的主导颜色——工具栏、页眉、选中标签页、填充按钮 |
| 背景色 | 屏幕大部分内容后方的颜色 |
| 文字颜色 | 根据背景推断——深色背景 → #FFFFFF,浅色背景 → #111111 |
| 强调色 | CTA 按钮、高亮内容、开关、选中状态 |
| 次要色 | 渐变的搭配颜色——将主色的色相偏移 15–20 度,或使用界面中可见的次要颜色 |
| 主题 | 深色背景 → dark-bold · 浅色/白色背景 → clean-light · 暖色/大地色背景 → editorial · 品牌色铺满背景 → vibrant |
| 字体 | 默认使用 Inter,除非应用截图显示了明显独特的字体 |
| 边框颜色 | 深色应用(深色工具栏 + 背景)→ black · 浅色应用 → white |
| 幻灯片数量 | 默认 5 |
如果确实无法从截图中判断某个值——请询问,不要猜测。
“我无法从截图中清楚辨认你的主品牌色。你的主要品牌色的十六进制颜色值是什么?”
步骤 4 — 确认,然后构建
用户确认步骤 3 中的摘要后,继续生成 config.js 和 index.html。除非出现意外情况,否则不要再提问。
默认值(除非用户主动提及,否则绝不询问):
tablet.enabled:falselocales:["en"]featureGraphic.style:"gradient"featureGraphic.subtext:"Available on Google Play"
需要询问什么,以及需要推断什么
| 输入 | 处理方式 |
|---|---|
| 功能和用户问题 | 务必询问——无法推断 |
| 截图路径 | 扫描 → 如果找到则确认;如果未找到或不明确则询问 |
| 应用图标路径 | 扫描标准路径 → 如果找到则确认;如果没有则询问 |
| 应用名称 | 从截图中读取 → 在摘要中确认 |
| 品牌颜色 | 目视提取 → 在摘要中确认;如果不明确则询问 |
| 主题 | 根据背景颜色推断 → 在摘要中确认 |
| 字体 | 默认使用 Inter → 在摘要中确认;如果应用使用了独特字体则注明 |
| 设备边框颜色 | 根据应用的整体风格推断 → 在摘要中确认 |
| 幻灯片数量 | 默认 5 张 → 在摘要中说明,用户可以更改 |
| 平板 / 语言区域 / 横向布局 | 默认关闭/en/纵向 → 绝不询问,仅在用户主动提及时启用 |
项目架构
此技能会在一个新文件夹中生成两个文件。无需框架、无需 npm install,也无需构建步骤。
play-store-screenshots/
├── index.html ← rendering engine, export logic, overview mode (don't edit)
├── config.js ← ALL customization: copy, colors, slides (edit this)
└── screenshots/ ← user's raw Android app screenshots + app icon
├── app-icon.png
├── screen1.png
└── screen2.png
AI 会填写 config.js。index.html 会读取其中的内容并渲染所有内容。
使用方法:通过一行命令启动本地服务来提供该文件夹(加载本地图片时必需),在 Chrome 中打开,然后点击 Export All。
# Pick any one of these — whatever is available:
python3 -m http.server 8080
npx serve .
然后打开 http://localhost:8080。
关于导出文件的说明: 点击 "Export All" 会触发浏览器下载——文件会保存到系统的下载文件夹。上传到 Play Console 前,请先在那里重命名并整理文件。
是否应该将此项目提交到 git?
不应该。截图生成器是一个一次性工具——获得 PNG 后,该项目就完成了它的任务。唯一值得长期保留的文件是:
- 导出的 PNG(上传到 Play Console)
- 如果之后想重新生成或调整,则保留
config.js
可以在任意临时文件夹中操作。不要将其添加到应用的代码仓库中。
config.js 参考
config.js 是 AI 唯一需要编写的文件。它是纯 JavaScript——无需 TypeScript、无需导入,也无需构建步骤。
此技能目录中的 example-config.js 提供了一个虚构应用的完整可用示例——可以复制它作为起点。
const config = {
app: {
name: "Your App",
icon: "screenshots/app-icon.png",
},
brand: {
primary: "#6366F1", // dominant brand color
secondary: "#4F46E5", // gradient partner / secondary brand color
background: "#FFFFFF", // canvas background
surface: "#F4F4F8", // card / panel backgrounds
text: "#111111", // headline color
textMuted: "#666666", // caption / label color
accent: "#F59E0B", // highlight, call-to-action color
},
// "clean-light" | "dark-bold" | "vibrant" | "editorial"
theme: "clean-light",
device: {
color: "black", // "black" | "white" | "silver"
},
slides: [
{
id: "hero",
layout: "text-top",
screenshot: "screenshots/screen1.png",
label: "INTRODUCING",
headline: "Your app name.\nYour outcome.",
// Leave subtext empty on hero — let the visual breathe
},
{
id: "feature-one",
layout: "text-top",
screenshot: "screenshots/screen2.png",
label: "FEATURE NAME",
headline: "Short benefit\nstatement here.",
subtext: "One supporting sentence, maximum.",
},
// Add 2–8 slides total — all use layout: "text-top"
],
featureGraphic: {
headline: "The app headline goes here",
subtext: "Available on Google Play",
// "gradient" | "solid" | "screenshot-backed"
style: "gradient",
// Only used when style is "screenshot-backed"
screenshot: "screenshots/screen1.png",
},
// Optional: set enabled: true and add tablet screenshots to activate
tablet: {
enabled: false,
sizes: ["10-inch"], // "7-inch" | "10-inch" | both
},
// Add locale codes to generate localized sets: "de", "fr", "ar", "he", etc.
locales: ["en"],
};
多语言文案
当 locales 包含多个条目时,将字符串值改为语言区域映射:
slides: [
{
id: "hero",
layout: "text-top",
screenshot: { en: "screenshots/en/screen1.png", de: "screenshots/de/screen1.png" },
label: { en: "INTRODUCING", de: "NEU" },
headline: { en: "Your app.\nYour way.", de: "Deine App.\nDein Weg." },
},
]
幻灯片布局
统一布局,始终如一。
每张手机截图都采用相同的构图:文字在上方,大尺寸手机在下方。这不是限制,而是竖版 Play Store 截图的正确模式。这种方式行之有效。
┌─────────────────────┐
│ App Name │ ← small, top padding ~6% of canvas height
│ │
│ LABEL │ ← all-caps label
│ Big headline │ ← largest text on the slide
│ here. │
│ Subtext sentence. │ ← optional, smaller
│ │
│ ┌───────────────┐ │
│ │ │ │
│ │ [screenshot] │ │ ← phone, large, centered
│ │ │ │
│ │ │ │ ← bottom of phone crops off canvas (intentional)
└──┴───────────────┴──┘
标准手机尺寸——使用以下精确数值:
| 属性 | 数值 |
|---|---|
| 手机宽度 | PHONE_W * 0.82(≈885px) |
| 手机高度 | phoneWidth * 2.15(≈1903px — 高于画布) |
| 手机左侧位置 | (PHONE_W - phoneWidth) / 2(居中) |
| 手机顶部位置 | PHONE_H * 0.34(距顶部约 653px) |
| 底部裁切 | 手机约 25% 的高度超出画布——这是有意为之,可增加纵深感 |
手机底部超出画布边缘是有意且理想的效果——它能在视觉上稳固手机,并消除整部手机都显示出来时出现的尴尬留白。
文字块定位:
文字容器高度为 height: PHONE_H * 0.32,并设置 overflow: hidden。内容在容器内垂直居中。手机从 PHONE_H * 0.34 处开始,文字块底部与手机顶部之间留有约 2% 的缓冲间隙,避免标签或最后一行标题碰到设备边框。
| 元素 | 位置 |
|---|---|
| 应用名称 / 品牌 | top: PHONE_H * 0.06,居中 |
| 标签 | top: PHONE_H * 0.13,居中 |
| 标题 | 标签下方,居中,font-size: PHONE_W * 0.09 |
| 补充文字 | 标题下方,居中,font-size: PHONE_W * 0.038 |
所有文字都应位于画布高度顶部 32% 的范围内(容器会通过 overflow: hidden 限制内容)。如果文字溢出,请缩短标题,不要将手机下移。
feature-graphic (仅用于功能宣传图,不用于手机截图)
横向画布(1024×500px)。不使用设备模型。有两种构图方式:
- **图标靠左:**应用图标(180×180)置于左侧三分之一处,标题和补充文字置于右侧三分之二处
- **图标居中:**应用图标在顶部居中,标题置于其下方,补充文字再置于标题下方
背景使用选定的 featureGraphic.style 填充整个画布。
支持的布局
模板仅实现两种布局:
text-top— 大多数截图使用此布局(如上所述)full-bleed— 全屏截图叠加渐变;文字悬浮在顶部
其他任何 layout 值都会显示红色错误框。请勿使用 layout: "text-bottom"、layout: "split-screen"、layout: "hero-left" 或 layout: "hero-right" 创建截图,这些布局尚未实现。
full-bleed 布局
截图填满整个画布(width:100%; height:100%; object-fit:cover)。深色渐变从顶部向下渐隐(高度约占 35%),覆盖在截图上方。标签和标题以白色文字悬浮在顶部渐变上。不使用设备模型。
此布局仅用于一张截图——当应用截图本身具有很强的视觉吸引力时,效果最佳。切勿用于显示密集 UI(列表、设置)的截图。避免连续使用多张 full-bleed 截图。
┌─────────────────────┐
│ LABEL │ ← white text over gradient
│ Big headline │
│ here. │
│▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│ ← gradient fade
│ │
│ [screenshot fills │
│ entire canvas] │
│ │
└─────────────────────┘
Android 设备模型图(仅 CSS)
Android 手机边框使用**纯 CSS 实现,无需 PNG 资源。**这样可以避免脆弱的 PNG 偏移耦合问题,即必须让精确的像素值与特定图像文件匹配。
组件:<AndroidPhoneMockup>
属性:screenshot(字符串路径)、color("black" | "white" | "silver")、width(像素数值)、height(像素数值)
渲染结构和关键比例(所有值均根据组件的 width / height 计算):
┌──────────────────────┐ outer frame (corner radius: width*0.12)
│ ● │ punch-hole camera: width*0.028 diameter, centered, top height*0.018
│ ┌────────────────┐ │ screen: left/right inset width*0.030, top/bottom inset height*0.025
│ │ │ │
│ │ [screenshot] │ │
│ │ │ │
│ └────────────────┘ │
│ ─────── │ home indicator: width*0.30 wide, height*0.003 tall, bottom height*0.015
└──────────────────────┘
| 属性 | 值 |
|---|---|
| 外框圆角半径 | width * 0.12 |
| 边框厚度 | width * 0.008 |
| 屏幕左右内边距 | width * 0.030 |
| 屏幕顶部内边距 | height * 0.025 |
| 屏幕底部内边距 | height * 0.028 |
| 摄像头直径 | width * 0.028 |
| 摄像头中心距顶部 | height * 0.018 |
| 主屏幕指示条宽度 | width * 0.30 |
| 主屏幕指示条高度 | height * 0.003 |
| 主屏幕指示条距底部 | height * 0.014 |
根据 color 属性设置边框颜色:
"black"→ 边框#1C1C1E,轮廓#3A3A3C,屏幕背景#000000"white"→ 边框#F2F2F7,轮廓#D1D1D6,屏幕背景#FFFFFF"silver"→ 边框#8E8E93,轮廓#636366,屏幕背景#111111
**重要:**手机边框或轮廓切勿使用品牌色。边框必须始终使用上述中性色之一。使用品牌色(例如应用的强调橙色或紫色)作为边框颜色会显得不专业,并分散用户对屏幕内容的注意力。边框应在视觉上退居其次,而非与 UI 争夺注意力。
边框还应添加柔和的投影,使其从背景中微微浮起:
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.18), 0 8px 24px rgba(0, 0, 0, 0.10);
根据主题调整不透明度:浅色背景使用较淡的阴影,深色背景使用较浓的阴影。
侧边按键(可选细节,可提升真实感):
- 电源键:右侧,距顶部 38% 处,高度为总高度的 8%,宽度为宽度的 0.6%
- 音量加/减键:左侧,分别位于距顶部 32% 和 42% 处,尺寸相同
高级设计元素
基础截图与高级感设计之间的区别完全在于装饰层——背景处理、标签设计,以及手机背后微妙的景深效果。这些效果都可通过纯 CSS 应用于幻灯片画布。
背景处理
切勿将纯色平铺用作幻灯片背景。至少叠加两个元素:
- 基础渐变——使用品牌色的对角或径向多段渐变
- 装饰光球——放置在文字和手机背后的 2–3 个大型强模糊圆形
/* Example: dark theme with purple brand */
.slide {
background: linear-gradient(160deg, #080613 0%, #120B22 60%, #060410 100%);
position: relative;
overflow: hidden;
}
/* Blurred decorative orb */
.orb {
position: absolute;
border-radius: 50%;
filter: blur(140px);
pointer-events: none;
z-index: 1;
}
/* Top orb — sits behind the text block */
.orb-top {
width: 700px; height: 700px;
top: -120px; left: 50%;
transform: translateX(-50%);
background: radial-gradient(circle, #7C3AED 0%, transparent 70%);
opacity: 0.28;
}
/* Bottom orb — sits behind the phone */
.orb-bottom {
width: 900px; height: 900px;
top: 500px; left: 50%;
transform: translateX(-50%);
background: radial-gradient(circle, #4338CA 0%, transparent 70%);
opacity: 0.20;
}
根据主题调整光球的不透明度:
- 深色主题:
0.25–0.40 - 浅色主题:
0.08–0.15(非常柔和的染色效果,几乎不可见)
胶囊徽标样式的标签
标签必须是带背景的胶囊形徽标,而非纯文本。仅此一项改动,就能让幻灯片看起来像经过设计,而不是简单拼凑出来的。
/* All values below are illustrative — scale relative to W as shown in comments */
.label-pill {
display: inline-flex;
align-items: center;
padding: 12px 32px; /* W*0.011 W*0.030 */
border-radius: 100px;
font-size: 28px; /* W * 0.026 */
font-weight: 700;
letter-spacing: 0.14em;
text-transform: uppercase;
margin-bottom: 32px; /* W * 0.030 */
}
/* Dark theme — glass/translucent variant */
.label-pill-glass {
background: rgba(255, 255, 255, 0.10);
color: rgba(255, 255, 255, 0.80);
border: 1.5px solid rgba(255, 255, 255, 0.14);
}
/* Dark theme — colored variant (hero slide or high-emphasis labels) */
.label-pill-accent {
background: rgba(124, 58, 237, 0.18); /* use brand primary at ~18% */
color: #C4B5FD; /* lighter tint of primary */
border: 1.5px solid rgba(124, 58, 237, 0.32);
}
/* Light theme */
.label-pill-light {
background: rgba(201, 130, 42, 0.12); /* brand primary at ~12% */
color: #92600E; /* darker shade for contrast */
border: 1.5px solid rgba(201, 130, 42, 0.25);
}
标题排版
使用紧凑的字间距和微妙的文字阴影,营造景深效果:
/* font-size must be set via inline style using the proportional system — not hardcoded */
.headline {
/* font-size: W * 0.090 (set inline, not in CSS class) */
font-weight: 800;
line-height: 1.05;
letter-spacing: -0.02em;
}
/* Dark theme only */
.slide-dark .headline {
text-shadow: 0 4px 40px rgba(0, 0, 0, 0.40);
}
标题中的应用图标
在标签上方显示应用图标(约 80px,圆角)。无需添加杂乱元素,即可在每张幻灯片中凸显品牌标识。
.app-icon {
width: 80px; height: 80px;
border-radius: 18px;
object-fit: cover;
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.30);
margin-bottom: 20px;
}
手机环境光晕(仅限深色主题)
在背景与手机之间添加径向光晕,让设备看起来像是融入光线之中,而非简单地贴在背景上:
.phone-glow {
position: absolute;
width: 900px; height: 900px;
border-radius: 50%;
background: radial-gradient(circle, var(--brand-primary) 0%, transparent 65%);
filter: blur(80px);
opacity: 0.18;
top: 400px;
left: 50%;
transform: translateX(-50%);
pointer-events: none;
z-index: 4; /* above background orbs, below phone */
}
浅色背景上不要添加光晕——看起来会像一块浑浊的污渍。
噪点纹理叠加层(可选,高级质感)
微妙的 SVG 噪点纹理可让渐变显得不那么平滑,更有印刷质感。保持很低的不透明度:
.slide::after {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
opacity: 0.04;
mix-blend-mode: overlay;
pointer-events: none;
z-index: 100;
}
导出规格
手机竖屏(主要规格——始终必需)
1080 × 1920px
所有内容均按此分辨率设计和导出。Play Store 接受宽高比介于 1:2 和 2:1 之间的任意尺寸;1080×1920 适用于所有手机。
手机横屏(可选)
1920 × 1080px
适用于游戏和以横屏 UI 为主的应用。如果用户的应用主要以横屏方向使用,请提供此规格。
平板(可选)
| 屏幕 | 尺寸 |
|---|---|
| 7 英寸 | 1200 × 1920px |
| 10 英寸 | 1600 × 2560px |
特色图片(Play Store 要求)
1024 × 500px
这是显示在 Play Store 列表顶部的横向横幅。它不是手机截图——没有设备边框。所有应用都必须提供。
常量
// Phone portrait (primary)
const PHONE_W = 1080;
const PHONE_H = 1920;
// Phone landscape (optional)
const PHONE_LAND_W = 1920;
const PHONE_LAND_H = 1080;
// Tablet 7-inch (optional)
const TAB7_W = 1200;
const TAB7_H = 1920;
// Tablet 10-inch (optional)
const TAB10_W = 1600;
const TAB10_H = 2560;
// Feature graphic (required)
const FG_W = 1024;
const FG_H = 500;
文案策略与信息传达
每张幻灯片包含三个文本元素:标签、标题和可选的副文案。每个元素的作用都不同。三者都做到位,这张幻灯片就能在一秒内打动用户。
步骤 1:将功能描述转化为文案
当用户描述某项功能时,不要只是复述给他们听。改为询问:
“如果没有这项功能,什么情况会让人感到焦虑或沮丧?”
这种焦虑就是你的标题。功能只是解决方案。
示例:
- 用户说:“离线模式——没有网络也能使用应用”
- 焦虑:需要使用应用时,身处没有信号的地方
- 标题:
"没信号?\n没问题。"或"每一次祈祷。\n始终相伴。" - 不要写:
"支持离线使用"或"离线支持"
示例:
- 用户说:“可以调整字体大小”
- 焦虑:小字看起来费劲,尤其是对年长用户而言
- 标题:
"字体更大。\n文字更清晰。"或"按你的方式阅读。" - 不要写:
"可调节字体大小"或"无障碍功能"
示例:
- 用户说:“收藏/为祈祷内容添加书签”
- 焦虑:要翻遍所有内容,才能找到最常用的那一篇
- 标题:
"你的祈祷。\n始终在手边。"或"珍爱之物,\n随时珍藏。" - 不要写:
"收藏系统"或"为内容添加书签"
步骤 2:撰写标题
标题是幻灯片上字号最大的文字。即使缩略图大小,也必须在一秒内传达清楚。
以下六种公式都很有效。选择最符合功能情感角度的一种:
公式 1:解决痛点
点明问题,并暗示解决方案。简短有力。
"没信号?\n没问题。""别再搜索。\n直接找到。""又忘了?\n再也不会。"
公式 2:归属感(所有格+结果)
营造个人拥有的感觉,更显亲近。
"你的祈祷。\n始终在手边。""你的节奏。\n你的进步。""你的数据。\n你做主。"
公式 3:描绘瞬间(呈现确切时刻)
描述用户受益的具体时刻,让体验更真切。
"每一次祈祷。\n触手可及。""每天中午前。\n轻松完成。""打开应用。\n即刻平静。"
公式 4:简单对比(暗示前后变化)
两行短句。第一行制造张力,第二行化解。
"字体更大。\n文字更清晰。""轻点一下。\n即刻访问。""减少干扰。\n更加专注。"
公式 5:发出邀请(主动动词+回报)
以动词开头,充满活力,直截了当。
"珍爱之物,\n随时珍藏。""找到任何内容。\n就在此刻。""切换语言。\n随时随地。"
公式 6:明确宣言(自信地表达身份)
大胆说出应用的定位。最适合主视觉幻灯片。
"每一次祈祷。\n触手可及。""全心投入。\n专注当下。""简化你的\n每日虔修。"
步骤 3:撰写标签
标签是标题上方的小号全大写文字。它的作用是引导读者——提前告诉他们接下来会看到哪类益处,让标题更有冲击力。
规则:
- 1–3 个词,全部大写
- 标明益处类别,而非功能名称
- 应能引发读者对下方标题的好奇
| 功能 | 不佳标签 | 优质标签 |
|---|---|---|
| 离线模式 | OFFLINE MODE | 100% OFFLINE |
| 字体大小设置 | ACCESSIBILITY | READ COMFORTABLY |
| 收藏 | BOOKMARKS | FAVOURITES |
| 双语 | LANGUAGES | BILINGUAL |
| 深色模式 | DARK MODE | EASIER ON EYES |
| 每日提醒 | NOTIFICATIONS | DAILY REMINDER |
第 4 步:撰写补充文案
补充文案是标题下方的一句辅助说明。它是可选的——如果标题本身已经足够有力,就留空(尤其是首屏幻灯片)。
使用补充文案时:
- 补充一个标题刻意留白的具体细节
- 写得自然亲切,不要像企业宣传文案
- 最多 8–10 个词
- 不要换种说法重复标题
| 标题 | 不好的补充文案 | 好的补充文案 |
|---|---|---|
"每一次祈祷。\n触手可及。" | "在一个地方轻松访问所有祈祷" | "Aarti • Chalisa • Mantra——尽在一处" |
"没有信号?\n也没问题。" | "这款应用无需联网也能使用" | "每一次祈祷,随时可用。" |
"字体更大。\n文字更清晰。" | "你可以调整字体大小,提升易读性" | "调整字体大小,适合自己。" |
"收藏你\n喜爱的内容。" | "将你喜欢的祈祷保存为书签" | "快速访问你最常用的祈祷。" |
适用于所有内容的规则
每张幻灯片只讲一个想法。 如果你发现自己写了“以及”,那就该拆成两张幻灯片,而不是一张。
每行 3–5 个词。 有意安排换行——换行是设计的一部分,不是意外折行。
尽量用短词。 1–2 个音节。测试一下:10 岁的孩子能立刻看懂吗?
多用动词,少用名词。 “收藏你喜爱的内容”胜过“收藏管理”。“查找任何内容”胜过“搜索功能”。
绝不要使用这些词: 无缝、强大、高级、稳健、直观、创新、全面、精简、杠杆、利用。它们毫无意义。
完整的“不佳 → 更好”参考
| 功能描述 | 不好的标题 | 好的标题 |
|---|---|---|
| "带优先级的任务管理" | "高级任务管理" | "中午前完成。\n每天如此。" |
| "跨设备同步" | "跨设备同步" | "你的手机。\n你的平板。\n同一份清单。" |
| "分析仪表盘" | "强大的分析功能" | "看看哪些\n真的有效。" |
| "推送通知" | "实时通知" | "别错过\n重要时刻。" |
| "主屏幕小组件" | "可自定义的小组件" | "你的信息。\n就在眼前。" |
| "离线模式" | "支持离线使用" | "没有信号?\n也没问题。" |
| "字体大小控制" | "无障碍功能" | "字体更大。\n文字更清晰。" |
| "收藏喜爱的内容" | "书签系统" | "你的祈祷。\n始终相伴。" |
| "深色模式" | "支持深色模式" | "让你的\n眼睛更轻松。" |
| "切换语言" | "双语支持" | "Hindi 还是 English。\n由你选择。" |
宣传图标题
规则相同,但可以稍长——由于横向画布空间更大,最多 8 个词。应以一行文字传达应用的核心承诺。无需换行。
"改变你祈祷方式的应用"✓"每一份虔心。尽在一款精美应用。"✓"陪伴你的日常祈祷"✓
技术实现
设置
新建一个文件夹,并在其中创建两个文件:
mkdir play-store-screenshots
cd play-store-screenshots
mkdir screenshots
# Copy the user's app screenshots and icon into ./screenshots/
然后创建 config.js(由 AI 填写)和 index.html(由 AI 生成)。设置就这么简单——无需包管理器,也无需安装。
index.html 结构
<head> 通过 CDN 加载所有内容——无需本地依赖:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800;900&display=swap" rel="stylesheet">
<script src="https://unpkg.com/[email protected]/dist/html-to-image.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script src="config.js"></script>
</head>
<body>
<div id="topbar">...</div>
<div id="slide-grid">
</div>
<div id="export-canvases" style="position:fixed;left:-9999px;top:0;z-index:-1">...</div>
<script>
// All rendering and export logic here
</script>
</body>
</html>
核心原则:所有幻灯片始终在网格中可见。没有“每次只显示一张”的模式,也没有切换开关。 网格就是界面——你可以一眼检查所有幻灯片,然后再导出。
字体排版
通过上方的 <link> 标签加载字体。推荐默认字体:Inter、Plus Jakarta Sans、DM Sans。如果用户指定了偏好字体,请与之保持一致。
所有字号都应根据画布宽度缩放——在幻灯片渲染中,绝不要硬编码 px 值:
// Typography scale — derive from canvas width W
function typography(W) {
return {
label: W * 0.028, // all-caps category label
headline: W * 0.090, // standard headline (1–2 lines)
headlineLg: W * 0.100, // hero slide headline (larger)
subtext: W * 0.038, // supporting sentence
caption: W * 0.030, // small secondary text
};
}
这样无论以何种分辨率导出,文字都能正确呈现,无需修改。
渲染标题换行
关键:config.js 中的标题使用 \n 换行(例如 "Every prayer.\nAt your fingertips.")。切勿依赖 white-space: pre-line 来渲染这些换行——它只对实际换行符有效,不适用于配置值中可能出现的两个字面字符 \n。插入 innerHTML 前,务必使用辅助函数进行转换:
const nl2br = (text) => text.replace(/\\n|\n/g, '<br>');
在将这些值插入 HTML 的所有位置,都使用 nl2br(slide.headline) 和 nl2br(slide.subtext)。
主题系统
四个命名主题,均为普通 JS 对象。通过 config.theme 键选择主题:
const THEMES = {
"clean-light": {
bg: "#FFFFFF",
fg: "#111111",
accent: config.brand.primary,
muted: "#888888",
surface: "#F4F4F8",
},
"dark-bold": {
bg: "#0A0A0A",
fg: "#FFFFFF",
accent: config.brand.accent,
muted: "#999999",
surface: "#1A1A1A",
},
"vibrant": {
bg: config.brand.primary,
fg: "#FFFFFF",
accent: config.brand.accent,
muted: "rgba(255,255,255,0.7)",
surface: config.brand.secondary,
},
"editorial": {
bg: "#F8F5F0",
fg: "#1A1A1A",
accent: config.brand.primary,
muted: "#7A7A7A",
surface: "#EDE9E3",
},
};
const theme = THEMES[config.theme];
幻灯片网格缩放
缩放每张手机幻灯片,使其能舒适地适应视口高度。计算一个统一的缩放比例,并应用到所有幻灯片包装元素:
const TOPBAR_H = 52; // height of the top controls bar in px
const SCALE = Math.min(
(window.innerHeight - TOPBAR_H - 64) / PHONE_H, // fit vertically
(window.innerWidth - 80) / (PHONE_W * config.slides.length + 20 * (config.slides.length - 1))
);
document.querySelectorAll(".slide-wrap").forEach(wrap => {
wrap.style.width = `${PHONE_W * SCALE}px`;
wrap.style.height = `${PHONE_H * SCALE}px`;
});
document.querySelectorAll(".slide").forEach(slide => {
slide.style.transform = `scale(${SCALE})`;
slide.style.transformOrigin = "top left";
});
功能图也会在同一行渲染。按比例缩放,使其高度在视觉上与手机幻灯片相匹配:
const fgScale = (PHONE_H * SCALE) / FG_H;
fgWrap.style.width = `${FG_W * fgScale}px`;
fgWrap.style.height = `${FG_H * fgScale}px`;
fgEl.style.transform = `scale(${fgScale})`;
fgEl.style.transformOrigin = "top left";
屏幕外的导出画布始终保持完整分辨率,切勿缩放。
功能图实现
功能图是独立组件,不是手机幻灯片。它在自己的 1024×500px 画布上渲染。
关键:强制使用精确的画布尺寸
必须通过 CSS 显式设置画布元素的尺寸,切勿让浏览器根据内容确定尺寸:
#feature-graphic-canvas {
width: 1024px;
height: 500px;
position: relative;
overflow: hidden;
/* Never set width/height from JS or let it auto-size */
}
在网格预览中,使用 CSS transform: scale(...) 调整其视觉尺寸,但底层 DOM 元素必须保持精确的 1024×500。如果画布尺寸不正确,导出的 PNG 尺寸就会出错。
三种样式(通过配置中的 featureGraphic.style 设置)
gradient
整个画布使用从 brand.primary 到 brand.secondary 的对角渐变。叠加 2–3 个模糊光球以增加层次感(使用与手机幻灯片相同的技巧)。应用图标位于左侧三分之一处(垂直居中,180×180px)。标题位于中心偏右处,副文本位于下方。
┌──────────────────────────────────────────────────────────┐
│ ░░░░░░░░░░░░░░░░ gradient bg + subtle orbs ░░░░░░░░░ │
│ │
│ ┌──────┐ App Name │
│ │ ICON │ │
│ │ │ Big headline here │
│ └──────┘ Available on Google Play │
│ │
└──────────────────────────────────────────────────────────┘
适用场景:大多数应用。简洁、专业,适用于任何品牌颜色。
solid
使用 brand.background 平铺填充,添加一条细水平强调线(brand.primary)和居中的大型应用图标。标题和副文本居中显示在下方。
适用场景:实用工具类应用、效率工具,以及品牌形象简洁或极简的应用。
screenshot-backed
应用截图占据画布右侧 55%(裁剪,object-fit cover)。左侧 45% 是纯色 brand.primary 面板。两侧之间以渐变羽化过渡。标题和图标位于纯色面板上。
适用场景:视觉内容丰富的应用(摄影、设计、社交),展示 UI 本身就是卖点。
高级功能图构图
对功能图应用相同的装饰光球技巧:
.fg-orb {
position: absolute;
border-radius: 50%;
filter: blur(80px);
pointer-events: none;
}
/* Large orb upper-left, behind icon */
.fg-orb-1 {
width: 300px; height: 300px;
top: -60px; left: -40px;
background: radial-gradient(circle, var(--brand-secondary) 0%, transparent 70%);
opacity: 0.40;
}
/* Smaller orb lower-right */
.fg-orb-2 {
width: 200px; height: 200px;
bottom: -40px; right: 80px;
background: radial-gradient(circle, var(--brand-primary) 0%, transparent 70%);
opacity: 0.30;
}
功能图排版(按 FG_W = 1024 缩放)
const FGT = {
headline: FG_W * 0.060, // ~61px — confident, reads at small sizes
subtext: FG_W * 0.026, // ~27px
appName: FG_W * 0.030, // ~31px — shown above the headline
};
导出机制
使用 html-to-image(相比 html2canvas,它对 CSS 渐变、滤镜和 clip-path 的支持更好)。使用 JSZip + FileSaver.js 将所有导出文件打包为一个 ZIP 下载。
关键:双重调用模式
这是确保字体和图像正确渲染所必需的。第一次调用会预加载延迟加载的资源;第二次调用会生成干净的输出。跳过第一次调用会导致文本模糊或图像缺失。
下面的 captureSlide 辅助函数实现了此模式,并由 exportAll 调用:
// Moves the element on-screen momentarily (required by html-to-image),
// captures twice for clean output, then returns the data URL.
async function captureSlide(element) {
element.style.left = "0px";
element.style.top = "0px";
element.style.position = "fixed";
element.style.zIndex = "9999";
// First call: warms up fonts and images — result discarded
await htmlToImage.toPng(element, { pixelRatio: 1 });
// Second call: clean, correct output
const dataUrl = await htmlToImage.toPng(element, { pixelRatio: 1 });
// Restore to off-screen position
element.style.left = "-9999px";
element.style.top = "0px";
element.style.position = "fixed";
element.style.zIndex = "-1";
await new Promise((r) => setTimeout(r, 200));
return dataUrl;
}
文件名规范
使用零填充数字前缀,确保文件系统和上传到 Play Store 时按字母顺序排序正确:
exports/phone/en/
├── 01-hero-1080x1920.png
├── 02-feature-one-1080x1920.png
├── 03-feature-two-1080x1920.png
├── 04-trust-1080x1920.png
└── 05-cta-1080x1920.png
exports/feature-graphic/
└── feature-graphic-1024x500.png
批量导出为 ZIP
所有幻灯片会收集到一个 ZIP 文件中,并通过一次点击下载。不单独下载各个文件。
// Capture helper — double-call pattern for clean font and image rendering
async function captureSlide(element) {
element.style.left = "0px";
element.style.top = "0px";
element.style.position = "fixed";
element.style.zIndex = "9999";
// First call: warms up lazy-loaded fonts and images — result discarded
await htmlToImage.toPng(element, { pixelRatio: 1 });
// Second call: clean, correct output
const dataUrl = await htmlToImage.toPng(element, { pixelRatio: 1 });
element.style.left = "-9999px";
element.style.top = "0px";
element.style.position = "fixed";
element.style.zIndex = "-1";
await new Promise((r) => setTimeout(r, 200));
return dataUrl;
}
async function exportAll() {
const zip = new JSZip();
const phoneFolder = zip.folder("phone");
const fgFolder = zip.folder("feature-graphic");
for (const locale of config.locales) {
const localeFolder = phoneFolder.folder(locale);
// Phone slides
for (let i = 0; i < config.slides.length; i++) {
const el = document.getElementById(`canvas-${locale}-${config.slides[i].id}`);
if (!el) continue;
const name = `${String(i + 1).padStart(2, "0")}-${config.slides[i].id}-${PHONE_W}x${PHONE_H}.png`;
const dataUrl = await captureSlide(el);
localeFolder.file(name, dataUrl.split(",")[1], { base64: true });
}
// Feature graphic
const fg = document.getElementById(`canvas-${locale}-feature-graphic`);
if (fg) {
const dataUrl = await captureSlide(fg);
fgFolder.file(`feature-graphic-${FG_W}x${FG_H}.png`, dataUrl.split(",")[1], { base64: true });
}
// Tablet slides (if enabled)
if (config.tablet && config.tablet.enabled) {
for (const size of config.tablet.sizes) {
const W = size === "10-inch" ? TAB10_W : TAB7_W;
const H = size === "10-inch" ? TAB10_H : TAB7_H;
const tabFolder = zip.folder(`tablet-${size}/${locale}`);
for (let i = 0; i < config.slides.length; i++) {
const el = document.getElementById(`canvas-tablet-${size}-${locale}-${config.slides[i].id}`);
if (!el) continue;
const name = `${String(i + 1).padStart(2, "0")}-${config.slides[i].id}-${W}x${H}.png`;
const dataUrl = await captureSlide(el);
tabFolder.file(name, dataUrl.split(",")[1], { base64: true });
}
}
}
}
// Generate and trigger download of the ZIP
const appSlug = config.app.name.replace(/\s+/g, "-").toLowerCase();
const blob = await zip.generateAsync({ type: "blob" });
saveAs(blob, `${appSlug}-play-store-screenshots.zip`);
}
点击一次即可生成 focusflow-play-store-screenshots.zip,其中包含按类型和语言区域整理的所有幻灯片。解压后即可上传到 Play Console。
多语言与 RTL 支持
截图会按语言区域整理到 exports/phone/ 下的文件夹中:
exports/phone/
├── en/
├── de/
└── ar/ ← RTL locale — layouts are mirrored
RTL 检测与布局镜像:
const RTL_LOCALES = new Set(["ar", "he", "fa", "ur"]);
const isRtl = RTL_LOCALES.has(selectedLocale);
// Apply dir attribute to each slide container element:
// slideEl.setAttribute("dir", isRtl ? "rtl" : "ltr");
//
// CSS flexbox respects dir automatically — text and layout mirror
// without needing manual position overrides.
当 config.locales 包含多个条目时,会在控件栏中构建一个语言区域 <select>。更改选项后,使用所选语言重新渲染所有预览幻灯片。
QA 检查清单
导出最终资源前,请检查以下所有项目。
内容
- 每张幻灯片只传达一个观点——不要使用带有“和”的复合主张
- 每个标题都能通过一臂距离下的一秒测试
- 各幻灯片之间没有重复的功能
- 整套内容具有叙事脉络:吸引注意 → 证明 → 建立信任 → CTA(或类似结构)
- 副文本(如有)提供了新信息,而不是重复内容
视觉
- 所有幻灯片均使用
layout: "text-top"(或至多一张使用"full-bleed")——不使用其他布局值 - 文本不会与手机边框重叠(若标题可能溢出,请保持简短)
- 功能图片在 50% 缩放时仍清晰可读(即其在 Play 商店搜索结果中的显示效果)
Play 商店合规性
- 至少导出 2 张手机截图
- 每种设备类型最多导出 8 张手机截图
- 功能图片的尺寸必须恰好为 1024 × 500px
- 所有截图均为 JPEG 或 24 位 PNG——最终导出文件中不得包含 Alpha 通道/透明度
- 所有文件均小于 8MB
- 不得出现 iOS 风格的 UI 元素——包括灵动岛、iPhone 刘海形状、iOS 主屏幕指示条、iOS 状态栏样式
- 任何位置都不得出现 Apple 品牌标识、App Store 徽章或 iOS 系统图标
- 所有资源的背景均完全不透明
导出质量
- 所有文本在完整分辨率下都清晰锐利(无模糊伪影)
- 模拟图中的截图没有拉伸或变形——保持原始纵横比
- 使用了双重调用导出模式(跳过此步骤会导致字体模糊)
- 文件名使用零填充(
01-、02-,而非1-、2-)
导出后:上传到 Play Console
- 前往 Google Play Console → 您的应用 → 商店展示 → 主要商店详情
- 在手机截图下,按顺序上传
exports/phone/en/中的文件 - 在功能图片下,上传
feature-graphic-1024x500.png - 如果生成了平板截图,请将其上传到对应的平板部分
- 保存并提交审核
Play 商店会即时处理上传内容——提交版本前无需等待资源审核。