Skip to content
Deployment
Skill

/flame-harness-screenshot

Phase 9 — capture store screenshots in the game's configured locales via integration_test (ads hidden), fill ASO keywords, and upload via fastlane.

From plugin
flutter-flame-harness
6114 skills1 hook

Claude Code

$ npx -y skills add tjdrhs90/flutter-flame-harness --skill flame-harness-screenshot --agent claude-code

SKILL.md

flame-harness-screenshot.SKILL.md
name: flame-harness-screenshot
description: Phase 9 — capture store screenshots in the game's configured locales via integration_test (ads hidden), fill ASO keywords, and upload via fastlane.
argument-hint: ""
allowed-tools: [Read, Write, Edit, Bash, Glob]

flame-harness-screenshot

Phase 9 of the flutter-flame-harness pipeline. Captures KO and EN store screenshots by driving the game's `integration_test` harness on the required device sizes (ads hidden), fills ASO metadata (keywords, localized titles, descriptions), and uploads the screenshots via fastlane.

All file schemas (`config.md`, `state.md`, `pipeline-log.md`) and the phase transition table are defined in `docs/harness-protocol.md` — that document is the single source of truth (§1 for `config.md` and `credentials_dir`; §2 for `state.md`; §6 for log schemas; §7 for the `screenshot → submit` transition and the `status: running` rule). Do not redefine schemas here.

**Prerequisites:** The game has been built and uploaded (Phase 8 `flame-harness-build`). The iOS simulator is a 6.7" iPhone model and the Android emulator is a phone-sized device. `flutter drive` and fastlane must be installed on the developer's macOS machine.

---

Input — Read Inputs

Before any action, load:

1. `docs/harness/config.md` — extract `app_slug`, `bundle_id`, `app_name`, and `default_language` (per protocol §1). 2. `docs/harness/state.md` — confirm `next_role: screenshot` (per protocol §2).

Derive the game root path: `<projects-dir>/<app_slug>/`.

---

Phase 1 — Harness Setup

Copy the integration_test template

Copy `templates/screenshots_test.dart.template` into the game's `integration_test/` directory:

mkdir -p <game>/integration_test
cp templates/screenshots_test.dart.template \
   <game>/integration_test/screenshots_test.dart

Adapt the TODO markers

Open `<game>/integration_test/screenshots_test.dart` and replace every `// TODO(generator):` comment block with the game's real screen-driving code:

  • Replace `<__APP_SLUG__>` in the import with the actual package name (from `config.md` `app_slug`,

converting hyphens to underscores).

  • Seed mock SharedPreferences / Hive / Isar data to skip first-run tutorials and show a

representative UI state (high score, coins, unlocked skins).

  • Wire the locale controller to force the locale to the `SCREENSHOT_LOCALE` dart-define value so

screenshots are language-deterministic regardless of the simulator's system locale.

  • Replace the placeholder screen list with the game's actual key screens (home, gameplay,

game-over/results, optional secondary screen), keeping zero-padded two-digit name prefixes so fastlane and App Store Connect receive them in order.

Test driver

Ensure `<game>/test_driver/integration_test.dart` exists. **`integrationDriver()` has no default screenshot writer** — its native path is guarded by `onScreenshot != null`, so without the callback below every `takeScreenshot` byte is silently discarded and no file is ever written. Pass one:

import 'dart:io';

import 'package:integration_test/integration_test_driver_extended.dart';

Future<void> main() => integrationDriver(
  onScreenshot: (
    String name,
    List<int> bytes, [
    Map<String, Object?>? args,
  ]) async {
    // The driver runs on the host, so Platform.environment works here (inside
    // the test it would not — that side uses String.fromEnvironment).
    final dir = Platform.environment['SCREENSHOT_DIR'] ?? 'build/screenshots';
    final file = File('$dir/$name.png');
    await file.parent.create(recursive: true);
    await file.writeAsBytes(bytes);
    return true;
  },
);

---

Phase 2 — Capture

Device sizes

| Platform | Required device | |---|---| | iOS | 6.7" iPhone simulator (e.g. iPhone 15 Pro Max) | | Android | Phone emulator (e.g. Pixel 7, 1080 × 2400) |

Run `flutter devices` to identify the device ID. Use the `-d` flag to target the correct device.

Ads hidden during capture

Pass `--dart-define=screenshots=true` to every `flutter drive` invocation. The game's ad helper must check this flag and suppress all ad units (banner, interstitial, rewarded) during capture so no ad overlays appear in store screenshots. Screenshot mode should also skip the ATT prompt and mute audio (native prompts/sound break automated capture).

**No alpha channel** (App Store rejection): store screenshots — and the iOS app icon — must be flattened to opaque RGB. Check with `sips -g hasAlpha <file>` (must report `hasAlpha: no`).

**`sips -s format png` does NOT strip alpha** — it re-encodes and keeps the channel, so it silently leaves the rejection in place. Use one of these instead:

# Preferred — lossless, needs ImageMagick
magick in.png -background white -alpha remove -alpha off out.png

# macOS built-ins only — round-trip through JPEG (lossy, fine for screenshots)
sips -s format jpeg in.png --out tmp.jpg && sips -s format png tmp.jpg --out out.png

sips -g hasAlpha out.png   # verify: hasAlpha: no

See `docs/game-gotchas.md` → Store rejections.

// In the ad helper (example):
const bool isScreenshotMode =
    bool.fromEnvironment('screenshots', defaultValue: false);

Locale loop — KO and EN

Run the capture twice, once per locale (`ko` and `en`), using `--dart-define=SCREENSHOT_LOCALE=`:

`SCREENSHOT_DIR` is read by the `onScreenshot` callback above — give each locale its own directory so the two runs can't overwrite each other:

DEVICE_ID="<ios-simulator-id>"
GAME="<absolute-path-to-game-root>"

# KO screenshots — iOS
SCREENSHOT_DIR=build/screenshots/ios/ko flutter drive \
  --driver=test_driver/integration_test.dart \
  --target=integration_test/screenshots_test.dart \
  -d "$DEVICE_ID" \
  --dart-define=SCREENSHOT_LOCALE=ko \
  --dart-define=screenshots=true

# EN screenshots — iOS
SCREENSHOT_DIR=build/screenshots/ios/en-US flutter drive \
  --driver=test_driver/integration_test.dart \
  --target=integration_test/screenshots_t
Read more
@tjdrhs90
Ships withflutter-flame-harness

An autonomous game launch harness for Claude Code, Google Antigravity, and OpenAI Codex that takes a Flutter/Flame game from raw idea all the way to the app stores.

Stars on GitHub

Momentum

stars in total
61
Star history of tjdrhs90/flutter-flame-harness on GitHub, a chart by star-history.com

Other skills on flutter-flame-harness.

More skills from other plugins.

configuring-horizon

configuring-horizon

Use this skill whenever the user mentions Horizon by name in a Laravel context. Covers the full Horizon lifecycle: installing…

coolify10d66k
@coollabsio@coollabsioInstall Skill
vercel-cli

vercel-cli

Guides deployment, configuration, and troubleshooting with the Vercel CLI. Use when operating Vercel projects or resources…

vercel12d16k
@vercel@vercelInstall Skill
skypilot

skypilot

Use when launching cloud VMs, Kubernetes pods, or Slurm jobs for GPU/TPU/CPU workloads, training or fine-tuning models on cloud…

@skypilot-org@skypilot-orgInstall Skill
pinme

pinme

Use this skill when the user mentions "pinme", or needs to upload files, store to IPFS, create/publish/deploy websites or…

pinme2mo3.8k
@glitternetwork@glitternetworkInstall Skill

Questions about flame-harness-screenshot.

Which coding agents can use flame-harness-screenshot?
flame-harness-screenshot installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.