Claude Market
Menu
SkillsMCPPluginsSubmit MCPSkillPluginMCPMCP, plugin, or skillAdvertise
Claude Market
SkillsMCPPluginsSubmit MCPSkillPluginMCPMCP, plugin, or skillAdvertise

Featured

Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger →
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger →
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free →
Your own AI agent, running 24/7 with QwikClaw logoYour own AI agent, running 24/7 with QwikClaw

QwikClaw sets up and runs an always-on OpenClaw agent for you. One click, no config files, no server setup.

Deploy now →
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data — no proxies, no parsers, no maintenance.

Start building free →
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it — secured from day one.

Get it set up for you →
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free →
Reach 47,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here →
Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger →
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger →
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free →
Your own AI agent, running 24/7 with QwikClaw logoYour own AI agent, running 24/7 with QwikClaw

QwikClaw sets up and runs an always-on OpenClaw agent for you. One click, no config files, no server setup.

Deploy now →
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data — no proxies, no parsers, no maintenance.

Start building free →
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it — secured from day one.

Get it set up for you →
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free →
Reach 47,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here →
Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off
Launch on Hostinger →
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed
Launch on Hostinger →
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off
Try Firecrawl free →
Your own AI agent, running 24/7 with QwikClaw logoYour own AI agent, running 24/7 with QwikClaw
Deploy now →
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.
Start building free →
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams
Get it set up for you →
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit
Try DataForSEO free →
Reach 47,000+ AI builders
Advertise here →
Skills/aradotso/marketing-skills/ios-marketing-capture-automation
ios-marketing-capture-automation logo

ios-marketing-capture-automation

aradotso/marketing-skills
550 installs2 stars
Run it on Hostinger →up to 70% off + an extra 10% with code ZACAARON10Free API →

Installation

npx skills add https://github.com/aradotso/marketing-skills --skill ios-marketing-capture-automation

Summary

Automate multi-locale marketing screenshot capture for SwiftUI iOS apps with in-app capture system, demo data seeding, and element rendering.

SKILL.md

iOS Marketing Capture Automation

Skill by ara.so — Marketing Skills collection.

What This Skill Does

This skill helps you automate marketing screenshot capture for SwiftUI iOS apps by building an in-app capture system that:

  • Adds a #if DEBUG-gated capture system with zero production footprint
  • Seeds deterministic demo data so screenshots look populated and polished
  • Navigates to each screen programmatically via step-based coordinator
  • Snapshots full window including status bar, safe area, and presented sheets
  • Renders isolated elements (cards, widgets, charts) via ImageRenderer at 3x with transparency
  • Loops every locale automatically — one build, N relaunches with -AppleLanguages
  • Works with any SwiftUI navigation: TabView, NavigationStack, NavigationSplitView

Installation

Using npx skills (recommended)

npx skills add ParthJadhav/ios-marketing-capture

Global install (available across all projects):

npx skills add ParthJadhav/ios-marketing-capture -g

Agent-specific install:

npx skills add ParthJadhav/ios-marketing-capture -a claude-code

Manual installation

git clone https://github.com/ParthJadhav/ios-marketing-capture ~/.claude/skills/ios-marketing-capture

Requirements Checklist

Before starting, verify:

  • ✅ Xcode 16+ (synchronized folder groups support)
  • ✅ iOS 17+ deployment target (for ImageRenderer, @Observable)
  • ✅ A simulator runtime matching target iOS version
  • ✅ Python 3 (for JSON parsing in shell script)
  • ✅ SwiftUI-based app with defined navigation structure

Core Concepts

In-App Capture (Not XCUITest)

This approach uses in-app capture instead of XCUITest/Fastlane because:

  • No test target needed — many projects lack one, adding means fragile pbxproj edits
  • Direct access — ViewModels, SwiftData, ImageRenderer, UIWindow.drawHierarchy
  • Faster — xcodebuild build once, then simctl launch per locale
  • Element renders require it — ImageRenderer must run inside app process

Step-Based Coordinator

Each screenshot is a self-contained CaptureStep:

struct CaptureStep {
    let name: String                         // "01-home"
    let navigate: @MainActor () -> Void      // put app in right state
    let settle: Duration                     // wait for animations
    let cleanup: (@MainActor () -> Void)?    // tear down before next step
}

Implementation Pattern

1. Gather Requirements

When user asks to capture screenshots, collect:

  1. Screens to capture — exact tab names or navigation paths
  2. Elements to render — cards, widgets, charts to isolate
  3. Locales — explicit list or "all locales in xcstrings"
  4. Device — simulator model (e.g. "iPhone 17")
  5. Appearance — light, dark, or both
  6. Seed data requirements — what demo data needs to populate

2. Generated File Structure

Create this structure:

YourApp/
├── Debug/
│   └── MarketingCapture.swift      # Capture system (DEBUG-only)
├── ContentView.swift               # Modified — DEBUG hook
scripts/
└── capture-marketing.sh            # Build + locale loop

Output lands in:

marketing/
    en/
        01-home.png
        02-detail.png
        elements/
            card-item.png
            widget-small.png
    de/
        01-home.png
        ...

3. Core Capture System Code

#if DEBUG
import SwiftUI

struct CaptureStep {
    let name: String
    let navigate: @MainActor () -> Void
    let settle: Duration
    let cleanup: (@MainActor () -> Void)?
}

@Observable
final class MarketingCaptureCoordinator {
    var isCapturing = false
    var currentStep = 0
    
    private let steps: [CaptureStep]
    private let outputDir: URL
    private let elementsDir: URL
    
    init(steps: [CaptureStep], locale: String) {
        self.steps = steps
        
        let base = FileManager.default
            .urls(for: .documentDirectory, in: .userDomainMask)[0]
            .deletingLastPathComponent()
            .deletingLastPathComponent()
            .appendingPathComponent("marketing/\(locale)")
        
        self.outputDir = base
        self.elementsDir = base.appendingPathComponent("elements")
        
        try? FileManager.default.createDirectory(
            at: outputDir,
            withIntermediateDirectories: true
        )
        try? FileManager.default.createDirectory(
            at: elementsDir,
            withIntermediateDirectories: true
        )
    }
    
    @MainActor
    func startCapture() async {
        isCapturing = true
        currentStep = 0
        
        for step in steps {
            step.navigate()
            try? await Task.sleep(for: step.settle)
            captureWindow(name: step.name)
            step.cleanup?()
            currentStep += 1
        }
        
        isCapturing = false
        print("✅ Capture complete: \(outputDir.path)")
        exit(0)
    }
    
    private func captureWindow(name: String) {
        guard let window = UIApplication.shared
            .connectedScenes
            .compactMap({ $0 as? UIWindowScene })
            .first?.windows.first else { return }
        
        let renderer = UIGraphicsImageRenderer(bounds: window.bounds)
        let image = renderer.image { ctx in
            window.drawHierarchy(in: window.bounds, afterScreenUpdates: true)
        }
        
        let url = outputDir.appendingPathComponent("\(name).png")
        try? image.pngData()?.write(to: url)
    }
}

struct MarketingElementHarness {
    @MainActor
    static func renderElement<Content: View>(
        name: String,
        width: CGFloat,
        cornerRadius: CGFloat,
        background: Color,
        @ViewBuilder content: () -> Content
    ) {
        let renderer = ImageRenderer(content: content()
            .frame(width: width)
            .background(background)
            .clipShape(RoundedRectangle(cornerRadius: cornerRadius))
        )
        renderer.scale = 3.0
        
        guard let uiImage = renderer.uiImage else { return }
        
        let base = FileManager.default
            .urls(for: .documentDirectory, in: .userDomainMask)[0]
            .deletingLastPathComponent()
            .deletingLastPathComponent()
        
        let locale = Locale.current.language.languageCode?.identifier ?? "en"
        let elementsDir = base
            .appendingPathComponent("marketing/\(locale)/elements")
        
        try? FileManager.default.createDirectory(
            at: elementsDir,
            withIntermediateDirectories: true
        )
        
        let url = elementsDir.appendingPathComponent("\(name).png")
        try? uiImage.pngData()?.write(to: url)
    }
}
#endif

4. Navigation Pattern Examples

TabView Navigation
@Observable
final class AppCoordinator {
    var selectedTab = 0
    
    func setTab(_ index: Int) {
        selectedTab = index
    }
}

// In MarketingCapture.swift:
func makeSteps(coordinator: AppCoordinator) -> [CaptureStep] {
    [
        CaptureStep(
            name: "01-home",
            navigate: { coordinator.setTab(0) },
            settle: .seconds(0.5),
            cleanup: nil
        ),
        CaptureStep(
            name: "02-shelf",
            navigate: { coordinator.setTab(1) },
            settle: .seconds(0.5),
            cleanup: nil
        )
    ]
}
NavigationStack with Router
@Observable
final class Router {
    var path: [Route] = []
    
    func push(_ route: Route) {
        path.append(route)
    }
    
    func popToRoot() {
        path.removeAll()
    }
}

// Steps:
CaptureStep(
    name: "03-detail",
    navigate: {
        router.popToRoot()
        router.push(.coffeeDetail(coffee))
    },
    settle: .seconds(0.8),
    cleanup: { router.popToRoot() }
)
NavigationSplitView
@Observable
final class SplitCoordinator {
    var sidebarSelection: SidebarItem?
    var detailSelection: DetailItem?
}

// Steps:
CaptureStep(
    name: "04-settings",
    navigate: {
        coordinator.sidebarSelection = .settings
        coordinator.detailSelection = nil
    },
    settle: .seconds(0.6),
    cleanup: nil
)

5. Demo Data Seeding

#if DEBUG
@MainActor
func seedMarketingData(modelContext: ModelContext) {
    // Clear existing
    try? modelContext.delete(model: Coffee.self)
    
    // Seed deterministic data
    let coffees = [
        Coffee(
            name: "Morning Blend",
            roaster: "Blue Bottle",
            origin: "Ethiopia",
            notes: ["Blueberry", "Chocolate", "Citrus"],
            roastDate: Date().addingTimeInterval(-7 * 86400)
        ),
        Coffee(
            name: "Dark Horse",
            roaster: "Stumptown",
            origin: "Colombia",
            notes: ["Caramel", "Nuts", "Brown Sugar"],
            roastDate: Date().addingTimeInterval(-3 * 86400)
        )
    ]
    
    coffees.forEach { modelContext.insert($0) }
    try? modelContext.save()
}
#endif

6. Integrating with ContentView

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @State private var coordinator = AppCoordinator()
    
    #if DEBUG
    @State private var captureCoordinator: MarketingCaptureCoordinator?
    #endif
    
    var body: some View {
        TabView(selection: $coordinator.selectedTab) {
            HomeView()
                .tag(0)
                .tabItem { Label("Home", systemImage: "house") }
            
            ShelfView()
                .tag(1)
                .tabItem { Label("Shelf", systemImage: "books.vertical") }
        }
        #if DEBUG
        .task {
            if ProcessInfo.processInfo.environment["MARKETING_CAPTURE"] == "1" {
                seedMarketingData(modelContext: modelContext)
                
                let locale = Locale.current.language.languageCode?.identifier ?? "en"
                captureCoordinator = MarketingCaptureCoordinator(
                    steps: makeMarketingSteps(coordinator: coordinator),
                    locale: locale
                )
                
                try? await Task.sleep(for: .seconds(1))
                await captureCoordinator?.startCapture()
            }
        }
        #endif
    }
}

7. Element Rendering Examples

Widget Rendering
#if DEBUG
@MainActor
func renderWidgets() {
    let entry = PulseWidgetEntry(
        date: Date(),
        coffee: seedCoffee,
        recentBrew: seedBrew
    )
    
    // Small widget
    MarketingElementHarness.renderElement(
        name: "widget-pulse-small",
        width: 158,
        cornerRadius: 16,
        background: .white
    ) {
        PulseWidgetSmallView(entry: entry)
            .padding(16) // WidgetKit padding manually added
    }
    
    // Medium widget
    MarketingElementHarness.renderElement(
        name: "widget-pulse-medium",
        width: 338,
        cornerRadius: 16,
        background: .white
    ) {
        PulseWidgetMediumView(entry: entry)
            .padding(16)
    }
}
#endif
Card Rendering
#if DEBUG
@MainActor
func renderCards(coffees: [Coffee]) {
    for (index, coffee) in coffees.enumerated() {
        MarketingElementHarness.renderElement(
            name: "card-\(index + 1)",
            width: 380,
            cornerRadius: 20,
            background: Color(.systemBackground)
        ) {
            CoffeeCard(coffee: coffee)
                .padding(.horizontal, 16)
                .padding(.vertical, 12)
        }
    }
}
#endif
Chart Rendering
#if DEBUG
@MainActor
func renderCharts() {
    MarketingElementHarness.renderElement(
        name: "chart-cupping",
        width: 380,
        cornerRadius: 16,
        background: Color(.systemBackground)
    ) {
        CuppingRadarChart(scores: sampleScores)
            .frame(height: 300)
            .padding(20)
    }
}
#endif

8. Build and Launch Script

#!/bin/bash
# scripts/capture-marketing.sh

set -e

APP_NAME="YourApp"
SCHEME="YourApp"
DEVICE="iPhone 17"
IOS_VERSION="18.2"

LOCALES=("en" "de" "es" "fr" "ja")

SIMULATOR_ID=$(xcrun simctl list devices available | \
    grep "$DEVICE ($IOS_VERSION)" | head -1 | \
    grep -o '\[.*\]' | tr -d '[]')

if [ -z "$SIMULATOR_ID" ]; then
    echo "❌ Simulator '$DEVICE ($IOS_VERSION)' not found"
    exit 1
fi

echo "📱 Using simulator: $SIMULATOR_ID"

# Boot simulator
xcrun simctl boot "$SIMULATOR_ID" 2>/dev/null || true
sleep 2

# Build once
echo "🔨 Building..."
xcodebuild \
    -scheme "$SCHEME" \
    -destination "id=$SIMULATOR_ID" \
    -configuration Debug \
    -derivedDataPath ./build \
    build

APP_PATH=$(find ./build -name "${APP_NAME}.app" | head -1)
BUNDLE_ID=$(defaults read "$APP_PATH/Info.plist" CFBundleIdentifier)

echo "📦 Bundle ID: $BUNDLE_ID"

# Install once
xcrun simctl install "$SIMULATOR_ID" "$APP_PATH"

# Per-locale capture
for LOCALE in "${LOCALES[@]}"; do
    echo ""
    echo "📸 Capturing $LOCALE..."
    
    xcrun simctl launch \
        --terminate-running-process \
        "$SIMULATOR_ID" \
        "$BUNDLE_ID" \
        -AppleLanguages "($LOCALE)" \
        -MARKETING_CAPTURE 1
    
    sleep 8
done

# Copy to project
CONTAINER=$(xcrun simctl get_app_container "$SIMULATOR_ID" "$BUNDLE_ID" data)
cp -R "$CONTAINER/Documents/../../tmp/marketing" ./marketing/

echo ""
echo "✅ All locales captured → ./marketing/"

Critical Gotchas (Baked Into Skill)

1. Live Activities Persist Across Launches

Problem: Next locale crashes on stale SwiftData references.

Solution: End all Live Activities in cleanup:

for activity in Activity<PulseAttributes>.activities {
    await activity.end(nil, dismissalPolicy: .immediate)
}

2. Re-Seeding Per Locale

Problem: CloudKit sync churn causes crashes.

Solution: Seed once at launch, not per step.

3. ViewModels Setup Before Seed

Problem: VMs hold stale empty snapshots.

Solution: Seed data → wait 1s → instantiate VMs → capture.

4. Setting Trigger Binding to nil

Problem: Doesn't dismiss fullScreenCover — captures wrong sheet.

Solution: Use dedicated dismiss closure:

.fullScreenCover(isPresented: $showTimer) {
    TimerView(onDismiss: { showTimer = false })
}

5. NavigationPath Can't Be Popped Externally

Problem: Pushing over existing path captures wrong stack.

Solution: Always popToRoot() before push() in navigate block.

6. membershipExceptions Is an INCLUSION List

Problem: Widget target membership goes backwards — widget renders fail.

Solution: Set membershipExceptions for DEBUG files to exclude widget target:

// In pbxproj or via Xcode:
// MarketingCapture.swift → Target Membership → Widget ❌

7. ImageRenderer + ProgressView

Problem: Renders as prohibited symbol without explicit style.

Solution: Force .circular style:

ProgressView()
    .progressViewStyle(.circular)

8. .containerBackground Outside WidgetKit

Problem: No-op — widget renders have no background.

Solution: Manually add background in render harness:

WidgetView(entry: entry)
    .background(Color.white)

9. iPhone 8 Plus Gone on iOS 18+

Problem: Legacy 6.5" simulator unavailable.

Solution: Use iPhone 17 Pro Max or latest available large device.

10. Locale Launch Argument Format

Problem: Locale ignored if parens missing.

Solution: Always use "($LOCALE)" format:

-AppleLanguages "(de)"  # ✅
-AppleLanguages "de"    # ❌

11. SwiftUI Animations in ImageRenderer

Problem: Captures frame 0, not animated state.

Solution: Render non-animated state or use explicit .animation(nil).

Common Workflows

Capturing Timer Mid-Countdown

CaptureStep(
    name: "05-timer-active",
    navigate: {
        router.popToRoot()
        coordinator.startTimer(seconds: 180)
        // Timer view subscribes to coordinator.activeTimer
    },
    settle: .seconds(1.5), // Let timer animate in
    cleanup: {
        coordinator.stopTimer()
        router.popToRoot()
    }
)

Capturing Presented Sheet

@State private var showSheet = false

// Step:
CaptureStep(
    name: "06-add-coffee",
    navigate: {
        showSheet = true
    },
    settle: .seconds(0.8),
    cleanup: {
        showSheet = false
    }
)

// View:
.sheet(isPresented: $showSheet) {
    AddCoffeeView()
}

Rendering All Widgets

#if DEBUG
@MainActor
func renderAllWidgets() {
    let entries = [
        ("pulse-small", PulseWidgetSmallView.self, 158),
        ("pulse-medium", PulseWidgetMediumView.self, 338),
        ("pulse-large", PulseWidgetLargeView.self, 338)
    ]
    
    for (name, viewType, width) in entries {
        MarketingElementHarness.renderElement(
            name: "widget-\(name)",
            width: width,
            cornerRadius: 16,
            background: .white
        ) {
            viewType.init(entry: sampleEntry)
                .padding(16)
        }
    }
}
#endif

Troubleshooting

Capture exits immediately

Check: MARKETING_CAPTURE=1 env var is set in launch args.

xcrun simctl launch ... -MARKETING_CAPTURE 1

Locale not applied

Check: Parens in -AppleLanguages:

-AppleLanguages "(de)"  # ✅ Correct

Widget renders blank

Check: Manual padding added (WidgetKit adds 16pt automatically):

WidgetView(entry: entry)
    .padding(16)  // Add this

Screenshot captures wrong screen

Check: Settle duration long enough for animations:

settle: .seconds(0.8)  // Increase if needed

SwiftData crash on second locale

Check: Live Activities ended in cleanup:

cleanup: {
    Task {
        for activity in Activity<Attrs>.activities {
            await activity.end(nil, dismissalPolicy: .immediate)
        }
    }
}

Element renders with wrong size

Check: Frame width explicitly set:

content()
    .frame(width: 380)  // Must be explicit

Configuration Reference

Capture Step Properties

PropertyTypePurpose
nameStringFilename without extension (e.g. "01-home")
navigate@MainActor () -> VoidPut app in correct state
settleDurationWait time for animations
cleanup(@MainActor () -> Void)?Tear down before next step

Script Variables

VariableExamplePurpose
APP_NAME"YourApp"App target name
SCHEME"YourApp"Xcode scheme
DEVICE"iPhone 17"Simulator model
IOS_VERSION"18.2"iOS runtime
LOCALES("en" "de" "es")Locale codes

Environment Variables

Set in launch args or script:

MARKETING_CAPTURE=1        # Enable capture mode

Post-Processing

Use app-store-screenshots to composite captured PNGs into Apple-style marketing pages with device mockups, headlines, and gradients.

npx skills add ParthJadhav/app-store-screenshots

Then prompt:

Composite my marketing screenshots into App Store pages with device frames

When to Use This Skill

✅ Use when:

  • Capturing marketing screenshots for App Store
  • Rendering isolated components (cards, widgets, charts)
  • Multi-locale asset generation
  • SwiftUI-based iOS app with defined navigation
  • Need full control over demo data and app state

❌ Don't use when:

  • UIKit-based app (requires different capture approach)
  • XCUITest infrastructure already working well
  • Single locale, manual capture sufficient
  • App uses web views or external content (can't seed)

Example: Complete Coffee App Capture

#if DEBUG
@MainActor
func makeMarketingSteps(
    coordinator: AppCoordinator,
    router: Router,
    viewModel: HomeViewModel
) -> [CaptureStep] {
    let coffees = viewModel.coffees
    
    return [
        // Tab 1: Home
        CaptureStep(
            name: "01-home",
            navigate: { coordinator.setTab(0) },
            settle: .seconds(0.5),
            cleanup: nil
        ),
        
        // Tab 2: Shelf
        CaptureStep(
            name: "02-shelf",
            navigate: { coordinator.setTab(1) },
            settle: .seconds(0.5),
            cleanup: nil
        ),
        
        // Detail: First coffee
        CaptureStep(
            name: "03-detail",
            navigate: {
                coordinator.setTab(0)
                router.popToRoot()
                router.push(.coffeeDetail(coffees[0]))
            },
            settle: .seconds(0.8),
            cleanup: { router.popToRoot() }
        ),
        
        // Timer: Active brew
        CaptureStep(
            name: "04-timer",
            navigate: {
                coordinator.setTab(0)
                router.popToRoot()
                coordinator.startTimer(seconds: 180)
            },
            settle: .seconds(1.2),
            cleanup: {
                coordinator.stopTimer()
                router.popToRoot()
            }
        ),
        
        // Settings
        CaptureStep(
            name: "05-settings",
            navigate: { coordinator.setTab(2) },
            settle: .seconds(0.5),
            cleanup: nil
        ),
        
        // Elements: Cards
        CaptureStep(
            name: "elements",
            navigate: {
                for (index, coffee) in coffees.enumerated() {
                    MarketingElementHarness.renderElement(
                        name: "card-\(index + 1)",
                        width: 380,
                        cornerRadius: 20,
                        background: Color(.systemBackground)
                    ) {
                        CoffeeCard(coffee: coffee)
                            .padding(.horizontal, 16)
                            .padding(.vertical, 12)
                    }
                }
                
                renderAllWidgets()
            },
            settle: .seconds(0.1),
            cleanup: nil
        )
    ]
}
#endif

Run:

chmod +x scripts/capture-marketing.sh
./scripts/capture-marketing.sh

Output:

marketing/
    en/
        01-home.png
        02-shelf.png
        03-detail.png
        04-timer.png
        05-settings.png
        elements/
            card-1.png
            card-2.png
            widget-pulse-small.png
            widget-pulse-medium.png
    de/
        [same structure]
    es/
        [same structure]
    fr/
        [same structure]
    ja/
        [same structure]

Summary

This skill automates iOS marketing screenshot capture by:

  1. Gathering requirements — screens, elements, locales, device, appearance
  2. Generating capture system — DEBUG-gated coordinator + steps
  3. Seeding demo data — deterministic, locale-agnostic
  4. Navigating programmatically — TabView, NavigationStack, or SplitView
  5. Capturing window — drawHierarchy for full screenshots
  6. Rendering elements — ImageRenderer for isolated components
  7. Looping locales — simctl launch with -AppleLanguages

The result: one build, N launches, complete multi-locale marketing assets ready for App Store or further compositing.

Score

0–100
63/ 100

Grade

C

Popularity15/30

550 installs — growing adoption.

Completeness27/30

Documented: full SKILL.md body, description, one-line install. Missing: category/license metadata.

Trust15/25

Community skill with a public GitHub source repository you can review.

Freshness6/15

No update timestamp is tracked for this skill in our catalog.

Scored automatically from popularity, completeness, trust, and freshness — computed only from data in our catalog, never fabricated.

Proud of your score? Add this badge to your README.

Paste a snippet into your GitHub README. The badge updates automatically and links back to this page.

Ios Marketing Capture Automation skill score badge previewScore badge

Markdown

[![Ios Marketing Capture Automation skill](https://www.claudemarket.ai/skills/aradotso/marketing-skills/ios-marketing-capture-automation/badges/score.svg)](https://www.claudemarket.ai/skills/aradotso/marketing-skills/ios-marketing-capture-automation)

HTML

<a href="https://www.claudemarket.ai/skills/aradotso/marketing-skills/ios-marketing-capture-automation"><img src="https://www.claudemarket.ai/skills/aradotso/marketing-skills/ios-marketing-capture-automation/badges/score.svg" alt="Ios Marketing Capture Automation skill"/></a>

Ios Marketing Capture Automation FAQ

How do I install the Ios Marketing Capture Automation skill?

Run “npx skills add https://github.com/aradotso/marketing-skills --skill ios-marketing-capture-automation” in your terminal. The skill is added to your agent's skills directory and picked up automatically on the next run — no restart or extra configuration needed.

What does the Ios Marketing Capture Automation skill do?

Automate multi-locale marketing screenshot capture for SwiftUI iOS apps with in-app capture system, demo data seeding, and element rendering. The full SKILL.md on this page shows the exact instructions the skill gives your agent.

Is the Ios Marketing Capture Automation skill free?

Yes. Ios Marketing Capture Automation is a free, open-source skill published from aradotso/marketing-skills. As with any third-party skill, review the source repository before installing it into an agent with sensitive access.

Does Ios Marketing Capture Automation work with Claude Code and OpenClaw?

Yes. Skills use the portable SKILL.md format, so Ios Marketing Capture Automation works with Claude Code, OpenClaw, Codex, Hermes, and any other agent that reads SKILL.md skills.

Featured

Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger →
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger →
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free →
Your own AI agent, running 24/7 with QwikClaw logoYour own AI agent, running 24/7 with QwikClaw

QwikClaw sets up and runs an always-on OpenClaw agent for you. One click, no config files, no server setup.

Deploy now →
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data — no proxies, no parsers, no maintenance.

Start building free →
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it — secured from day one.

Get it set up for you →
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free →
Reach 47,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here →
Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger →
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger →
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free →
Your own AI agent, running 24/7 with QwikClaw logoYour own AI agent, running 24/7 with QwikClaw

QwikClaw sets up and runs an always-on OpenClaw agent for you. One click, no config files, no server setup.

Deploy now →
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data — no proxies, no parsers, no maintenance.

Start building free →
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it — secured from day one.

Get it set up for you →
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free →
Reach 47,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here →
Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off
Launch on Hostinger →
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed
Launch on Hostinger →
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off
Try Firecrawl free →
Your own AI agent, running 24/7 with QwikClaw logoYour own AI agent, running 24/7 with QwikClaw
Deploy now →
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.
Start building free →
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams
Get it set up for you →
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit
Try DataForSEO free →
Reach 47,000+ AI builders
Advertise here →

Categories

External DownloadsCommand ExecutionPrompt Injection
View on GitHub

Recommended skills

Browse all →
twitter-automation logo

twitter-automation

101-skills/skills

526K installsInstall
reddit-automation logo

reddit-automation

doany-skills/skills

211K installsInstall
marketing-psychology logo

marketing-psychology

coreyhaines31/marketingskills

121K installsInstall
marketing-ideas logo

marketing-ideas

coreyhaines31/marketingskills

109K installsInstall
find-skills logo

find-skills

vercel-labs/skills

2.8M installsInstall
frontend-design logo

frontend-design

anthropics/skills

731K installsInstall

Related guides

Hand-picked reading to help you choose, install, and use agent skills.

Guide10 Openclaw Skills Every Nextjs Developer NeedsGuideBest Openclaw Skills 2026GuideHow To Evaluate Openclaw Skill Before Installing

Skills by category

FrontendBackend & APIsTesting & QASecurityDevOps & CI/CDMCP & ToolingAutomationData & Analysis+20 more

MCP servers by category

AI & MLDeveloper ToolsVector & MemoryFiles & DocsDatabasesFinance & PaymentsBrowser & ScrapingCommunication+8 more

Marketplaces by category

developmentproductivitycommunicationdesignsecuritydatabaseworkflowcompliance+34 more

Claude Market

AI agent skills directory, marketplace, and workflow hub for OpenClaw, Hermes Agent, Claude Code, Codex, and MCP-powered operator stacks.

Independent project, not affiliated with Anthropic.

Resources

  • Browse Skills
  • Browse MCP Servers
  • Browse Plugins

More

  • Submit a Tool
  • Advertise
  • Free Tools
  • API
  • Shipping
  • Contact
  • Terms
  • Privacy

Know a company that should advertise here? Refer them and earn 10% — up to $300 per referral.

© 2026 Claude Market
Fazier badgeFeatured on Twelve ToolsFeatured on Wired BusinessRemote OpenClaw - Featured on AI Agents DirectoryListed on Turbo0Featured on Uneed