Files
DIYgodandClaude Opus 5.5 2131cec389 chore(store-assets): add the store screenshot and listing pipeline
Store copy for 12 listing locales, plus the tooling that captures the apps
with a demo account and renders the App Store, Google Play and Microsoft
Store screenshots and the README banner. Raw captures and rendered images
stay out of the repository (store-assets/.gitignore).

store-assets is a private workspace package, so playwright, sharp, pathe and
the other script dependencies are declared instead of resolved through
hoisting, and turbo typechecks it. The lockfile only gains its importer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 14:34:42 +08:00

65 lines
2.1 KiB
TypeScript

// Checks the rendered store images: every deck has one file per slide for
// every store locale, at the store size and without an alpha channel.
// tsx store-assets/scripts/check-output.ts
import { readdir } from "node:fs/promises"
import { join } from "pathe"
import sharp from "sharp"
import { decks } from "../src/decks"
import { listingLocales } from "../src/locales"
const root = join(import.meta.dirname, "..", "output")
const problems: string[] = []
let files = 0
const check = async (path: string, width: number, height: number) => {
const meta = await sharp(path)
.metadata()
.catch(() => null)
if (!meta) {
problems.push(`${path}: missing`)
return
}
files++
if (meta.width !== width || meta.height !== height || meta.hasAlpha) {
problems.push(`${path}: ${meta.width}x${meta.height}${meta.hasAlpha ? " with alpha" : ""}`)
}
}
for (const deck of decks) {
const { width, height } = deck.outputs[0]!
for (const locale of listingLocales) {
const storeLocales =
deck.store === "app-store"
? locale.appStore
: deck.store === "google-play"
? locale.googlePlay
: locale.microsoftStore
for (const storeLocale of storeLocales) {
const dir = join(root, deck.id, storeLocale)
const list = (await readdir(dir).catch(() => [])).filter((f) => f.endsWith(".png"))
if (list.length !== deck.slides.length) {
problems.push(`${deck.id}/${storeLocale}: ${list.length} of ${deck.slides.length} slides`)
}
for (const file of list) await check(join(dir, file), width, height)
}
}
}
for (const locale of listingLocales) {
for (const storeLocale of locale.googlePlay) {
await check(
join(root, "google-play/feature-graphic", storeLocale, "feature-graphic.png"),
1024,
500,
)
}
}
await check(join(root, "microsoft-store/extras/super-hero-art.png"), 3840, 2160)
await check(join(root, "microsoft-store/extras/store-logo-300.png"), 300, 300)
for (const problem of problems) console.log(problem)
console.log(`${files} images checked, ${problems.length} problems`)
process.exitCode = problems.length > 0 ? 1 : 0