npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chengyu08/ipa-cli

v0.2.0

Published

CLI for IPA review risk analysis, similarity checks, baseline scanning, and static asset review.

Readme

screenshots 工作区说明

本目录由 ipa-cli screenshots init-config 初始化,目的是让你可以直接开始准备原始截图、编辑渲染配置并输出 App Store 上架图。

如果你当前是在仓库源码里调试,也可以把下面示例里的 ipa-cli 替换成 npx tsx src/cli.ts

目录里有什么

  • screenshot.config.json:渲染配置文件,screenshots render 会直接读取它。
  • raw/:原始截图目录,建议按语言拆分子目录。
  • README.screenshots.md:当前说明文档。

默认初始化后的目录结构如下:

.
|-- README.screenshots.md
|-- screenshot.config.json
`-- raw/
    `-- zh-Hans/
        `-- 01_home.png

这个流程是怎么做的

screenshots 模块的链路是:

原始截图(raw)
  -> 编辑 screenshot.config.json
  -> ipa-cli screenshots render
  -> 输出 screenshots/<locale>/<target>/*.png
  -> ipa-cli screenshots check 做结果校验

也就是说,这个命令不会自动操作 App 页面。你需要自己准备原始截图,常见方式有两种:

  1. ipa-cli screenshots from-simulator 从 iOS 模拟器截取页面图。
  2. 自己准备营销图、设计图或真实页面截图,然后放进 raw/ 目录。

推荐使用步骤

  1. 把原始截图放到 raw/zh-Hans/ 目录,例如 raw/zh-Hans/01_home.png
  2. 打开 screenshot.config.json,按你的语言、设备和文案修改配置。
  3. 先执行 dry-run,确认路径和渲染计划没问题。
  4. 正式渲染到输出目录。
  5. screenshots check 校验最终目录。

配置文件长什么样

默认配置如下:

{
  "version": 1,
  "platform": "ios",
  "defaults": {
    "backgroundPresets": {},
    "background": {
      "type": "solid",
      "color": "#F5F7FA"
    },
    "titleColor": "#111827",
    "subtitleColor": "#4B5563",
    "fontFamily": "Inter, Arial, sans-serif",
    "orientation": "portrait",
    "deviceWidthRatio": 0.76,
    "deviceFrame": {
      "preset": "iphone-dark-01"
    }
  },
  "targets": [
    "iphone-6.5"
  ],
  "locales": [
    "zh-Hans"
  ],
  "frames": [
    {
      "name": "01_home",
      "raw": "raw/{locale}/01_home.png",
      "title": "快速完成估价",
      "subtitle": "关键流程清晰可见",
      "layout": "device-with-title-subtitle"
    }
  ]
}

配置字段说明

| 字段 | 含义 | 默认值 / 备注 | | --- | --- | --- | | version | 配置版本号 | 当前为 1 | | platform | 平台类型 | 当前只支持 ios | | defaults.backgroundPresets | 可复用背景预设字典 | 例如 { "hero": { ... } } | | defaults.backgroundPreset | 全局默认背景预设名 | 填了之后,未显式写 background 的 frame 会优先使用它 | | defaults.background | 全局背景配置 | 兼容纯色字符串,也支持 presetsolidlinear-gradientimageraw-blurstack | | defaults.titleColor | 标题颜色 | #111827 | | defaults.subtitleColor | 副标题颜色 | #4B5563 | | defaults.titleFontSize | 标题字号 | 单位 px;不填时按画布宽度自动计算 | | defaults.subtitleFontSize | 副标题字号 | 单位 px;不填时按画布宽度自动计算 | | defaults.fontFamily | SVG 文本使用的字体族 | Inter, Arial, sans-serif | | defaults.orientation | 输出方向 | portraitlandscape,默认 portrait | | defaults.deviceWidthRatio | 设备截图区域占画布宽度的比例 | 范围 0.350.95,默认 0.76 | | defaults.deviceFrame | 全局默认手机框配置 | 支持内置 preset 或自定义 src + screen | | targets | 要生成的设备槽位列表 | 当前支持 iphone-6.9iphone-6.5ipad-13 | | locales | 要生成的语言列表 | 例如 ["zh-Hans", "en-US"] | | frames[].name | 输出文件名 | 不写 .png 也会自动补上 | | frames[].raw | 原始截图路径 | 相对 screenshot.config.json 所在目录解析,支持 {locale}{target} 占位符 | | frames[].title | 标题文案 | 对应带标题布局时显示 | | frames[].subtitle | 副标题文案 | 只在 device-with-title-subtitle 布局里显示 | | frames[].layout | 渲染布局 | 见下方布局说明 | | frames[].rawFit | raw-fullscreen 下原图缩放方式 | 默认 cover;改成 contain 时可露出背景层 | | frames[].backgroundPreset | 单张图引用背景预设名 | 优先级低于显式 background,高于全局默认背景 | | frames[].background | 单张图覆盖背景配置 | 不填时继承 defaults.background | | frames[].titleColor | 单张图覆盖标题颜色 | 不填时继承 defaults.titleColor | | frames[].subtitleColor | 单张图覆盖副标题颜色 | 不填时继承 defaults.subtitleColor | | frames[].titleFontSize | 单张图覆盖标题字号 | 单位 px;不填时继承 defaults.titleFontSize 或自动计算 | | frames[].subtitleFontSize | 单张图覆盖副标题字号 | 单位 px;不填时继承 defaults.subtitleFontSize 或自动计算 | | frames[].deviceFrame | 单张图覆盖手机框配置 | 可只写 offsetYscale 等局部字段 | | frames[].target | 限制只在某个 target 生效 | 例如 iphone-6.9 | | frames[].locale | 限制只在某个 locale 生效 | 例如 en-US |

字号字段速查

如果你想在 screenshot.config.json 里调 title / subtitle 的字号,直接看这 4 个字段:

  • defaults.titleFontSize:全局默认标题字号
  • defaults.subtitleFontSize:全局默认副标题字号
  • frames[].titleFontSize:覆盖单张图标题字号
  • frames[].subtitleFontSize:覆盖单张图副标题字号

补充说明:

  • 单位都是 px,值必须是正数,例如 7238
  • frames[] 里的字号设置优先级高于 defaults
  • subtitle 只有在 layout: "device-with-title-subtitle" 时显示,所以 subtitleFontSize 也只会在这个布局下生效
  • 如果这些字段都不填,渲染器会按画布宽度自动计算字号

示例:

{
  "defaults": {
    "titleFontSize": 72,
    "subtitleFontSize": 38
  },
  "frames": [
    {
      "name": "01_home",
      "raw": "raw/{locale}/01_home.png",
      "layout": "device-with-title-subtitle",
      "title": "快速完成估价",
      "subtitle": "关键流程清晰可见",
      "titleFontSize": 84,
      "subtitleFontSize": 44
    }
  ]
}

iPhone 6.5 尺寸要求

如果你把 targets 设成 ["iphone-6.5"],当前可接受的上架图尺寸要求如下:

  • 竖屏:1242 × 2688px1284 × 2778px
  • 横屏:2688 × 1242px2778 × 1284px
  • 当前 screenshots renderdefaults.orientation: "portrait" 下会优先输出 1284 × 2778px
  • 如果改成 defaults.orientation: "landscape",当前会优先输出 2778 × 1284px
  • screenshots check 会接受以上 4 组尺寸

layout 有哪些类型

当前支持 3 种 layout。它们会直接影响标题、副标题、设备外框和背景的呈现方式。

| layout | 画面效果 | 适合场景 | 注意事项 | | --- | --- | --- | --- | | raw-fullscreen | 原图直接铺满整个输出画布,不显示设备外框、标题或副标题 | 已经是完整营销图、KV 图、海报风页面图 | rawFit: "cover" 时只输出原图;rawFit: "contain" 时才会露出背景层 | | device-with-title | 顶部显示一段标题,下方展示带手机框的设备截图 | 单卖点页、功能页、流程页 | 即使传了 subtitle,当前也不会显示 | | device-with-title-subtitle | 顶部显示标题和副标题,下方展示带手机框的设备截图 | 首页、详情页、需要两级文案的场景 | 这是默认布局;不填 subtitle 时会只显示标题区 |

raw-fullscreen 示例

这个布局会让原图直接成为最终产物,适合已经设计好的整张图。

{
  "name": "01_launch",
  "raw": "raw/{locale}/01_launch.png",
  "layout": "raw-fullscreen"
}

如果你想保留完整原图并让四周露出背景层,可以改成 contain

{
  "name": "02_story",
  "raw": "raw/{locale}/02_story.png",
  "layout": "raw-fullscreen",
  "rawFit": "contain",
  "background": {
    "type": "linear-gradient",
    "angle": 180,
    "stops": [
      { "offset": 0, "color": "#F8FAFC" },
      { "offset": 1, "color": "#DBEAFE" }
    ]
  }
}

device-with-title 示例

这个布局会在顶部保留标题区,下面展示一张居中的圆角设备截图。

{
  "name": "03_search",
  "raw": "raw/{locale}/03_search.png",
  "layout": "device-with-title",
  "title": "快速找到目标商品"
}

device-with-title-subtitle 示例

这个布局会比上一种多一行副标题,适合写一句补充说明。

{
  "name": "04_home",
  "raw": "raw/{locale}/04_home.png",
  "layout": "device-with-title-subtitle",
  "title": "首页信息一眼看清",
  "subtitle": "核心入口、状态和行动按钮集中展示"
}

手机框配置示例

默认配置会启用内置 iphone-dark-01 手机框。原始截图会放入手机屏幕区域,并按屏幕圆角裁剪,再叠加真实手机外框。

{
  "defaults": {
    "deviceFrame": {
      "preset": "iphone-dark-01"
    }
  }
}

如果单张图需要把手机整体上移或下移,可以只覆盖位置参数:

{
  "name": "05_profile",
  "raw": "raw/{locale}/05_profile.png",
  "layout": "device-with-title-subtitle",
  "title": "账户信息集中管理",
  "deviceFrame": {
    "offsetY": -80,
    "scale": 0.96
  }
}

如果你要使用自己的手机框素材,需要同时提供屏幕开窗区域。screen 的坐标以手机框原图像素为准:

{
  "deviceFrame": {
    "src": "frames/custom-phone.png",
    "screen": {
      "x": 112,
      "y": 67,
      "width": 800,
      "height": 1405,
      "radius": 78
    },
    "fit": "cover",
    "position": "top"
  }
}

注意:

  • 内置 preset 当前支持 iphone-dark-01iphone-dark-02
  • iphone-dark-01 有透明外部区域,更适合作默认手机框。
  • iphone-dark-02 原图没有透明通道,适合你自行处理透明底后再作为自定义 src 使用。
  • offsetY 为负数时手机上移,为正数时手机下移。

background 有哪些类型

同一套 background 结构可以写在这 3 个位置:

  • defaults.background:全局默认背景
  • defaults.backgroundPresets.<name>:背景预设
  • frames[].background:单张图覆盖背景

frames[].background 的优先级最高;如果你只想引用预设,也可以用 frames[].backgroundPreset 这个简写字段。

1. 纯色字符串

最短写法,效果等价于一个纯色 solid 背景。

{
  "background": "#F5F7FA"
}

2. solid

显式声明一个纯色背景。适合你后续想统一把所有背景都写成对象结构。

{
  "background": {
    "type": "solid",
    "color": "#0F172A"
  }
}

3. linear-gradient

生成线性渐变背景,适合品牌色过渡、浅色氛围底和大面积柔和过渡。

{
  "background": {
    "type": "linear-gradient",
    "angle": 180,
    "stops": [
      { "offset": 0, "color": "#F8FAFC" },
      { "offset": 1, "color": "#DBEAFE" }
    ]
  }
}

4. image

把本地图片铺成背景。适合纹理、插画、品牌海报或运营底图。

{
  "background": {
    "type": "image",
    "src": "backgrounds/hero.png",
    "fit": "cover",
    "position": "center",
    "blur": 0
  }
}

如果背景图太花,可以叠一层遮罩提升文字可读性:

{
  "background": {
    "type": "image",
    "src": "backgrounds/hero.png",
    "fit": "cover",
    "overlay": {
      "color": "#111827",
      "opacity": 0.18
    }
  }
}

5. raw-blur

把当前 raw 原图本身拉伸、模糊后当作背景。适合让设备图和背景保持同一视觉主题。

{
  "background": {
    "type": "raw-blur",
    "blur": 24,
    "overlay": {
      "color": "#111827",
      "opacity": 0.18
    }
  }
}

6. stack

按顺序叠加多层背景。适合把渐变、纹理图、遮罩和模糊层组合在一起。

{
  "background": {
    "type": "stack",
    "layers": [
      {
        "type": "linear-gradient",
        "angle": 180,
        "stops": [
          { "offset": 0, "color": "#F8FAFC" },
          { "offset": 1, "color": "#DBEAFE" }
        ],
        "opacity": 1
      },
      {
        "type": "image",
        "src": "backgrounds/noise.png",
        "fit": "cover",
        "opacity": 0.12,
        "blend": "overlay"
      },
      {
        "type": "solid",
        "color": "#0F172A",
        "opacity": 0.08
      }
    ]
  }
}

7. preset

先在 defaults.backgroundPresets 定义一套背景,再在单张图里引用,适合多张图复用同一视觉风格。

{
  "defaults": {
    "backgroundPresets": {
      "hero": {
        "type": "stack",
        "layers": [
          {
            "type": "linear-gradient",
            "angle": 180,
            "stops": [
              { "offset": 0, "color": "#F8FAFC" },
              { "offset": 1, "color": "#DBEAFE" }
            ]
          },
          {
            "type": "image",
            "src": "backgrounds/{locale}/{target}/{frame}.png",
            "fit": "cover",
            "opacity": 0.12,
            "blend": "overlay"
          }
        ]
      }
    }
  },
  "frames": [
    {
      "name": "01_home",
      "raw": "raw/{locale}/01_home.png",
      "background": {
        "type": "preset",
        "name": "hero"
      }
    }
  ]
}

如果你更喜欢短一点的写法,也可以这样引用同一个预设:

{
  "frames": [
    {
      "name": "01_home",
      "raw": "raw/{locale}/01_home.png",
      "backgroundPreset": "hero"
    }
  ]
}

注意:

  • image.src 是相对 screenshot.config.json 所在目录解析的。
  • image.src 支持 {locale}{target}{frame} 占位符。
  • image.fit 当前支持 covercontain
  • image.position 当前支持 centertopbottomleftright
  • raw-blur 总是使用当前 frame 的 raw 原图,不需要额外提供 src
  • stack.layers 会按顺序从下到上叠加,每层都可以写 opacityblend
  • blend 当前支持 overmultiplyscreenoverlaydarkenlightensoft-lighthard-light
  • 如果你不想在很多 frame 里重复写长背景配置,可以先放进 defaults.backgroundPresets,再通过 backgroundPreset{ "type": "preset", "name": "..." } 按名字引用。

常用例子

先预演,不写文件:

ipa-cli screenshots render ./screenshot.config.json --dry-run --format panel

正式渲染:

ipa-cli screenshots render ./screenshot.config.json --output ./screenshots --format panel

检查最终产物:

ipa-cli screenshots check ./screenshots --strict --format panel

从模拟器采集一张原始图到当前工作区:

ipa-cli screenshots from-simulator \
  --device "iPhone 16 Pro Max" \
  --output ./raw/zh-Hans/01_home.png \
  --format panel

如果你已经准备好多语言和多设备,可以像这样扩展:

{
  "defaults": {
    "background": {
      "type": "linear-gradient",
      "angle": 180,
      "stops": [
        { "offset": 0, "color": "#F8FAFC" },
        { "offset": 1, "color": "#DBEAFE" }
      ]
    }
  },
  "targets": ["iphone-6.9", "iphone-6.5", "ipad-13"],
  "locales": ["zh-Hans", "en-US"],
  "frames": [
    {
      "name": "01_home",
      "raw": "raw/{locale}/01_home.png",
      "title": "核心卖点",
      "subtitle": "一句话说明优势",
      "layout": "device-with-title-subtitle",
      "titleColor": "#0F172A"
    },
    {
      "name": "02_detail",
      "raw": "raw/{locale}/{target}/02_detail.png",
      "layout": "raw-fullscreen",
      "rawFit": "contain",
      "background": {
        "type": "image",
        "src": "backgrounds/hero.png",
        "fit": "cover"
      }
    }
  ]
}

什么时候用 from-ipa

如果你只是想先自动生成一版草稿,可以直接跳过这个工作区,执行:

ipa-cli screenshots from-ipa ./Demo.ipa \
  --workspace ./screenshots-workspace \
  --output ./screenshots \
  --format panel

这个命令会自动生成 raw/、配置文件和最终上架图,但更适合“包里已经有可复用图片素材”的场景,不等价于真实页面自动截图。