{"id":50768425,"url":"https://github.com/lightning1377/screenshot-factory-public","last_synced_at":"2026-06-11T16:01:49.696Z","repository":{"id":360517516,"uuid":"1248186231","full_name":"lightning1377/screenshot-factory-public","owner":"lightning1377","description":"Local tool for capturing, previewing, rendering, and preparing repeatable app-store screenshots from reusable templates.","archived":false,"fork":false,"pushed_at":"2026-05-26T18:00:12.000Z","size":827,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T20:03:21.615Z","etag":null,"topics":["android","automation","developer-tools","google-play-store","publisher-tools","puppeteer","screenshots"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lightning1377.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-24T09:55:24.000Z","updated_at":"2026-05-26T18:00:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lightning1377/screenshot-factory-public","commit_stats":null,"previous_names":["lightning1377/screenshot-factory-public"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/lightning1377/screenshot-factory-public","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightning1377%2Fscreenshot-factory-public","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightning1377%2Fscreenshot-factory-public/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightning1377%2Fscreenshot-factory-public/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightning1377%2Fscreenshot-factory-public/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lightning1377","download_url":"https://codeload.github.com/lightning1377/screenshot-factory-public/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightning1377%2Fscreenshot-factory-public/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34206492,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","automation","developer-tools","google-play-store","publisher-tools","puppeteer","screenshots"],"created_at":"2026-06-11T16:01:48.833Z","updated_at":"2026-06-11T16:01:49.690Z","avatar_url":"https://github.com/lightning1377.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Screenshot Factory\n\nScreenshot Factory is a local developer tool for producing app-store screenshots without turning\nthe process into a manual design chore every release.\n\nIt was built for mobile apps, especially Android and Capacitor apps, that need repeatable\nscreenshots across devices, locales, scenes, themes, and marketing layouts. You describe the app\nscreens once, trigger those screens through deep links, capture raw device screenshots, and render\nstore-ready images from reusable HTML templates.\n\n## What It Does\n\n- Captures screenshots from a connected Android device or emulator with `adb`.\n- Opens app scenes through deep links like `myapp://screenshot/home?lang=en\u0026theme=dark`.\n- Renders final phone/tablet marketing screenshots with Puppeteer and HTML templates.\n- Supports localized titles, theme variants, and multi-slot templates.\n- Provides both a CLI and a local browser UI for managing configs, capture runs, previews,\n  templates, and Play Store upload preparation.\n\n## The Problem \u0026 The Solution\n\n### The Problem\nPreparing app-store screenshots is historically a tedious, manual design chore that developers and release managers dread. For every release:\n1. **Manual Navigation \u0026 Device Setup:** Developers must configure multiple physical devices or emulators, manually navigate to specific app screens, set system language, trigger specific mock states, and take screenshots.\n2. **Design Splicing \u0026 Translation:** Captured files must be manually imported into design tools (like Figma or Photoshop) to fit device frames, translate text captions, and align layouts.\n3. **Inconsistency \u0026 Human Error:** A simple change in an app's UI or copy requires repeating the entire process, leading to misalignment, outdated images, and inconsistent store listings.\n\n### The Solution\n**Screenshot Factory** automates and unifies the entire screenshot pipeline from app code to store assets.\n* **Deep-Link Navigation:** Instantly routes your running app to specific scenes, seeding locales, data states, and themes dynamically.\n* **Automated Capture:** Programmatically takes raw device captures through ADB and structures them automatically on disk.\n* **HTML/CSS Templating:** Renders raw screens inside reusable, responsive HTML templates containing localized captions, background gradients, and device frames.\n* **Repeatable \u0026 Design-Free:** Configured once, the entire asset collection can be regenerated in seconds for every new version of the app.\n\n## Technical Architecture \u0026 Highlights\n\n* **Headless Browser Performance:** Under the hood, rendering is performed by **headless Puppeteer**. By loading HTML templates locally using the `file://` protocol, the factory bypasses HTTP/network latency. Screenshots are rendered at exact target store resolutions (e.g., `1080x1920` for phones, `2560x1600` for tablets) in milliseconds.\n* **Smart ADB Screen Stabilization:** To prevent blurred captures during view transitions, the runner uses a signature-based checking loop. It captures consecutive temporary frames on-device and hashes them using ADB `md5sum` (falling back to file metadata if `md5sum` is unavailable). The runner captures the final frame only when the screen signature stabilizes over multiple intervals, optimizing capture speed while guaranteeing crisp visuals.\n* **Concurrency \u0026 Job Management:** Built as an asynchronous, non-blocking service, capture and render operations run as background tasks. The dev server manages these tasks via maps and equips them with `AbortController` handles. This allows users to start, monitor logs in real-time, or safely cancel tasks via either the CLI or UI without blocking the API thread.\n* **CI/CD Pipeline Integration:** Because Screenshot Factory includes a fully-featured headless CLI, it integrates natively into automated build environments (such as GitHub Actions, Jenkins, or fastlane):\n  * **APK Lifecycle Automation:** The runner can automatically boot target emulators, install freshly compiled APKs, clear cached storage for a clean state, run deep links, and capture assets.\n  * **Play Store Deployment:** Integrates with the Google Play Developer API, utilizing service-account JSON keys to validate, pack, and directly upload metadata to active store listings.\n\n## Requirements\n\n- Node.js `\u003e= 18`\n- npm\n- Android SDK with `adb` available in `PATH`\n- A connected Android device or running Android emulator for capture\n- Chromium dependencies required by Puppeteer for rendering\n\nOptional:\n\n- Xcode CLI tools on macOS if you want the UI to list or boot iOS simulators.\n\n## Quick Start\n\nInstall dependencies:\n\n```bash\nnpm install\n```\n\nStart the local UI/API server:\n\n```bash\nnpm run dev\n```\n\nOpen [http://localhost:8000](http://localhost:8000).\n\nUse the example config as a starting point:\n\n```bash\ncp apps/example.config.json apps/my-app.json\n```\n\nThen edit `apps/my-app.json` with your app id, package name, scene list, locales, optional APK\npath, and optional Play Store service-account key path.\n\n## Local Tooling Note\n\nScreenshot Factory is designed as a trusted local developer tool. The dev server can read and\nwrite app configs, edit templates, serve local screenshots, and start capture/render/upload jobs.\nRun it on your own machine and do not expose the dev server to an untrusted network.\n\n## CLI Usage\n\nCapture raw screenshots:\n\n```bash\nnpm run cli -- run apps/my-app.json\n```\n\nRender final images:\n\n```bash\nnpm run cli -- render apps/my-app.json\n```\n\nUseful capture options:\n\n- `-d, --device \u003cid\u003e`: choose an adb serial\n- `-t, --type \u003ctype\u003e`: `phone` or `tablet`\n- `-v, --verbose`: verbose logging\n- `-f, --force`: continue even if APK installation fails\n\nRender options:\n\n- `-t, --type \u003ctype\u003e`: `phone` or `tablet`\n\n## Browser UI\n\nThe UI is the easiest way to work day to day:\n\n- `Home`: select or create an app config from `apps/*.json`.\n- `App Config`: edit scenes, locales, text slots, templates, themes, and slot bindings.\n- `Capture`: choose a device/emulator and run screenshot capture jobs.\n- `Preview`: inspect single scenes or preview all outputs before rendering.\n- `Templates`: edit and create local HTML templates.\n- `Upload`: prepare screenshots for Play Store upload and run uploads when configured.\n\n\u003c!-- readme-screenshots:start --\u003e\n### UI Screenshots\n\n| Home | App Config | Capture |\n| --- | --- | --- |\n| ![Home panel](docs/screenshots/home.png) | ![App Config panel](docs/screenshots/app-config.png) | ![Capture panel](docs/screenshots/capture.png) |\n\n| Preview | Templates | Upload |\n| --- | --- | --- |\n| ![Preview panel](docs/screenshots/preview.png) | ![Templates panel](docs/screenshots/templates.png) | ![Upload panel](docs/screenshots/upload.png) |\n\u003c!-- readme-screenshots:end --\u003e\n\n## App Configs\n\nApp configs live in `apps/*.json`. Private configs are ignored by default, while\n`apps/example.config.json` is tracked as a public starter.\n\nConfigs may reference app-owned files outside this repo:\n\n- `apkPath`: optional path to an APK to install before capture\n- `uploadKeyPath`: optional path to a Google Play service-account JSON key\n\nMinimal shape:\n\n```json\n{\n  \"id\": \"my-app\",\n  \"name\": \"My App\",\n  \"packageName\": \"com.example.myapp\",\n  \"apkPath\": \"/absolute/path/to/app.apk\",\n  \"uploadKeyPath\": \"/absolute/path/to/play-store-service-account.json\",\n  \"scenes\": [\"home\", \"details\"],\n  \"locales\": [\"en\"],\n  \"sceneConfigs\": [\n    {\n      \"templateId\": \"normal\",\n      \"slotSceneMap\": {\n        \"primary\": { \"scene\": \"home\", \"theme\": \"$current\" }\n      },\n      \"themes\": [\"light\"],\n      \"textSlots\": {\n        \"title\": {\n          \"en\": \"Show your app at its best\"\n        }\n      }\n    }\n  ]\n}\n```\n\nImportant fields:\n\n- `id`: used in screenshot output paths\n- `packageName`: Android package name used by `adb`\n- `scenes`: app routes/screens to capture\n- `locales`: locale codes to pass to the app\n- `sceneConfigs`: per-output template, theme, slot, and text configuration\n- `slotSceneMap`: maps template slots such as `primary` or `secondary` to captured app scenes\n\nTheme binding rules:\n\n- Missing theme or `\"$current\"` uses the current capture/render variant.\n- Explicit values like `\"light\"` or `\"dark\"` force that slot to use a specific theme.\n\n## Templates\n\nTemplates are plain HTML files in `templates/`. During preview and render, Screenshot Factory loads\nthem with query parameters:\n\n- `title`: localized title or text slot value\n- `screenshot`: primary/fallback screenshot path\n- `screenshots`: JSON map keyed by slot id\n- `theme`: current theme variant, when present\n- `darkMode=true`: included when the current theme is `dark`\n- `t`: cache buster used by the preview UI\n\nPublic example templates:\n\n- `normal` -\u003e `templates/phone.html` and `templates/tablet.html`\n- `example_multi` -\u003e `templates/phone_example_multi.html` and\n  `templates/tablet_example_multi.html`\n\nTemplate metadata lives beside the HTML:\n\n```json\n{\n  \"name\": \"example_multi\",\n  \"files\": {\n    \"phone\": \"phone_example_multi.html\",\n    \"tablet\": \"tablet_example_multi.html\"\n  },\n  \"slots\": [\n    { \"id\": \"primary\", \"label\": \"Primary Screenshot\", \"required\": true },\n    { \"id\": \"secondary\", \"label\": \"Secondary Screenshot\", \"required\": true }\n  ],\n  \"textSlots\": [{ \"id\": \"title\", \"label\": \"Main Title\" }]\n}\n```\n\nPrivate or app-specific templates should use the custom naming convention. These files are ignored\nby git:\n\n- `templates/custom_*.meta.json`\n- `templates/*custom*.html`\n\nExample:\n\n- `templates/custom_modern.meta.json`\n- `templates/phone_custom_modern.html`\n- `templates/tablet_custom_modern.html`\n\n## Output Layout\n\nRaw captures:\n\n```text\nscreenshots/raw/\u003cappId\u003e/\u003cphone|tablet\u003e/\u003clocale\u003e/\u003cscene\u003e.png\nscreenshots/raw/\u003cappId\u003e/\u003cphone|tablet\u003e/\u003clocale\u003e/\u003cscene\u003e_\u003ctheme\u003e.png\n```\n\nRendered outputs:\n\n```text\nscreenshots/final/\u003cappId\u003e/\u003cphone|tablet\u003e/\u003clocale\u003e/\u003cscene\u003e-market.png\nscreenshots/final/\u003cappId\u003e/\u003cphone|tablet\u003e/\u003clocale\u003e/\u003cscene\u003e-\u003ctheme\u003e-market.png\n```\n\nThe `screenshots/` directory is ignored because it is generated output.\n\n## Capacitor Integration\n\nThe helper in `src/contract/capacitor-snippet.ts` shows the app-side contract. It listens for URL\nopens like:\n\n```text\nmyapp://screenshot/\u003cscene\u003e?lang=\u003clocale\u003e\u0026theme=\u003ctheme\u003e\n```\n\nThe snippet sets screenshot/marketing-mode flags and routes by scene. In a real app, you can use\nthe `lang` and `theme` query params to switch localization, seed mock data, or apply a visual theme\nbefore the capture happens.\n\n## API Summary\n\nAll endpoints are mounted under `/api`.\n\n- `GET /api/apps`\n- `GET /api/apps/:id`\n- `PUT /api/apps/:id`\n- `POST /api/config/read`\n- `POST /api/config/save`\n- `POST /api/config/create`\n- `GET /api/templates`\n- `GET /api/templates/:name`\n- `PUT /api/templates/:name`\n- `POST /api/templates`\n- `POST /api/capture/run`\n- `GET /api/capture/runs/:id`\n- `DELETE /api/capture/runs/:id`\n- `POST /api/render/run`\n- `GET /api/render/runs/:id`\n- `DELETE /api/render/runs/:id`\n- `GET /api/devices`\n- `GET /api/capture/emulators`\n- `POST /api/capture/emulators/boot`\n- Upload endpoints under `/api/upload`\n\n## Development\n\nCommon commands:\n\n```bash\nnpm run dev              # start local UI/API server\nnpm run cli -- run ...   # capture via CLI\nnpm run cli -- render ...# render via CLI\nnpm test                 # run Vitest\nnpm run lint             # ESLint + TypeScript check\nnpm run build            # backend build\nnpm run build:frontend   # frontend typecheck build\n```\n\nCI runs linting, tests, backend build, and frontend typechecking.\n\n## Troubleshooting\n\n### No connected device\n\n```bash\nadb devices\n```\n\nIf no devices are listed, start an emulator or connect a physical device with USB debugging\nenabled.\n\n### Capture runs but the app does not navigate\n\nCheck that your app handles the screenshot deep link and that the package name is correct:\n\n```bash\nadb shell am start -W -a android.intent.action.VIEW -d \"myapp://screenshot/home\" com.example.myapp\n```\n\n### Render produced fewer files than expected\n\nCommon causes:\n\n- a raw screenshot is missing for a scene/theme\n- a required template slot is missing\n- a template file referenced by metadata does not exist\n- `sceneConfigs` and `scenes` are out of sync by index\n\nCheck the UI job logs or CLI output; missing inputs are reported there.\n\n### Template preview looks wrong\n\n- Empty template selection means `Use App Config (Auto)`.\n- Non-empty template selection overrides the app config for preview.\n- Check that `files.phone`, `files.tablet`, and slot ids in the metadata match the HTML template.\n\n## Contributing\n\nContributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull\nrequest.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightning1377%2Fscreenshot-factory-public","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flightning1377%2Fscreenshot-factory-public","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightning1377%2Fscreenshot-factory-public/lists"}