The Problem

Every time a new CCFish build drops — whether a weekly TestFlight iteration or a production App Store release — the marketing team needs fresh assets. Screenshots must reflect the latest UI changes. App Store preview videos need updated gameplay footage. Playable ad templates must match the current build's mechanics and visual polish. And ad networks like Unity Ads, AppLovin, and IronSource expect new creative packs within hours of a build going live.

In a traditional setup, this dev-to-marketing handoff is manual and painful. A developer completes the CI build in Cocos Creator 2.4.15, uploads artifacts to a shared drive, then Slack-messages the marketing lead. The marketing lead downloads a multi-GB zip, extracts screenshots, re-records video if the UI changed, manually crops and formats each asset for every ad network's specification, then uploads each pack individually through a half-dozen web dashboards. This process introduces latency (12–48 hours), human error (wrong build version, wrong aspect ratio), and friction between teams. For a fast-moving mobile game like CCFish — where each build might include new weapon skins, fish variants, or UI refinements — that delay costs real ad revenue.

The Solution

CCFish eliminates this gap with an automated asset handoff protocol. The core idea: the moment a Cocos Creator CI build completes, a Cloudflare Worker picks up the build artifacts and orchestrates their transformation into ad-ready formats — MRAID playable ads, video app previews, image sets for every ad network — then deploys them directly to each network's API.

The pipeline treats marketing assets as first-class CI artifacts. The Cocos Creator build step emits a standardized artifact bundle: a platform-specific binary (iOS .ipa or Web .zip), a metadata JSON describing the build version, changelog, and screen dimensions, and optionally a replay recording of the build's first launch. The Cloudflare Worker ingests this bundle, runs it through a chain of processing stages — screenshot capture via headless Chromium, video encoding via FFmpeg, MRAID template injection, image resizing/cropping per network spec — and pushes the results to ad network endpoints. The entire pipeline runs in under 10 minutes, and both teams can track progress on a shared dashboard.

Architecture Overview

The handoff protocol consists of five layers:

**1. CI Trigger (GitHub Actions + Cocos Creator CLI):** The CCFish CI pipeline runs on every push to `release/*` branches. After building the Cocos Creator project with `cocos build -p web --output build/web-mobile`, it archives the output into a versioned artifact bundle and uploads it to R2 storage.

**2. Artifact Ingestion (Cloudflare Worker — `artifact-ingester`):** A Worker triggered by R2 object creation events. It reads the artifact bundle, extracts metadata, validates checksums, and fans out processing work to downstream Workers via Queues.

**3. Asset Processing (Cloudflare Workers — `screenshot-capture`, `video-encoder`, `mraid-builder`, `image-resizer`):** A fan-out of specialized Workers, each handling one transformation. The screenshot-capture Worker launches a headless Chromium instance (via Workers Browser Rendering API), loads the build, and captures screenshots at preset viewports. The video-encoder Worker records gameplay loops using the Puppeteer replay system and encodes to H.264. The mraid-builder Worker injects the build's Web export into an MRAID-compliant HTML template. The image-resizer Worker generates all required resolutions for each ad network.

**4. Delivery Orchestration (Cloudflare Worker — `delivery-orchestrator`):** Collects completed asset manifests, maps them to ad network API specs, and submits uploads in parallel. Handles retries, idempotency keys, and webhook callbacks.

**5. Tracking Dashboard (Cloudflare Pages + D1):** A lightweight dashboard that displays every build version, its asset processing status, and the ad networks it's currently serving impressions on. Data is logged to D1 by the delivery orchestrator.

Implementation

**CI integration** — the GitHub Actions workflow step that packages artifacts:

```yaml

- name: Package build artifacts

run: |

mkdir -p artifact-bundle

cp -r build/web-mobile artifact-bundle/build

cat > artifact-bundle/metadata.json << EOF

{

"version": "${{ github.ref_name }}",

"commit": "${{ github.sha }}",

"build_time": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",

"platform": "web-mobile",

"assets": ["screenshot", "video", "mraid", "image-set"]

}

EOF

zip -r ccfish-artifact-${{ github.sha }}.zip artifact-bundle/

- name: Upload to R2

run: wrangler r2 object put ccfish-artifacts/${{ github.sha }}/bundle.zip --file ccfish-artifact-${{ github.sha }}.zip

```

**Artifact ingester Worker** — triggered by R2 events, fans out to processing queues:

```toml

wrangler.toml

name = "ccfish-artifact-ingester"

r2_buckets = [{ binding = "ARTIFACTS", bucket_name = "ccfish-artifacts" }]

queues.producers = [

{ binding = "SCREENSHOT_QUEUE", queue = "ccfish-screenshot-queue" },

{ binding = "VIDEO_QUEUE", queue = "ccfish-video-queue" },

{ binding = "MRAID_QUEUE", queue = "ccfish-mraid-queue" },

{ binding = "IMAGE_QUEUE", queue = "ccfish-image-queue" }

]

```

**MRAID template injection** — the mraid-builder Worker takes the Web build and wraps it:

```typescript

const mraidTemplate = `

<!DOCTYPE html>

<html>

<head>

<meta name="ad.size" content="width=${width},height=${height}">

<script src="mraid.js"></script>

<script>

// MRAID bridge: expose ad lifecycle to the Cocos Canvas

mraid.addEventListener('ready', () => {

mraid.useCustomClose(true);

const iframe = document.getElementById('game-frame');

iframe.contentWindow.postMessage({ type: 'MRAID_READY' }, '*');

});

mraid.addEventListener('viewableChange', (viewable) => {

if (viewable) gameInstance.Start(); else gameInstance.Pause();

});

</script>

</head>

<body>

<iframe id="game-frame" src="./build/index.html" width="100%" height="100%" frameborder="0"></iframe>

</body>

</html>

`;

```

**Delivery to ad networks** — the orchestration Worker posts to each network's API:

```typescript

const networkEndpoints = {

unity: { url: 'https://ads-api.unity.com/v1/creatives', apiKey: env.UNITY_API_KEY },

applovin: { url: 'https://api.applovin.com/v2/creatives', apiKey: env.APPlOVIN_API_KEY },

ironsource:{ url: 'https://api.ironsrc.com/v1/adunits', apiKey: env.IRONSOURCE_API_KEY },

};

async function deliverToNetworks(manifest: AssetManifest, buildVersion: string) {

for (const [network, config] of Object.entries(networkEndpoints)) {

const formData = new FormData();

formData.append('creative[format]', manifest.format);

formData.append('creative[version]', buildVersion);

formData.append('creative[file]', manifest.file, manifest.filename);

const resp = await fetch(config.url, {

method: 'POST',

headers: { 'Authorization': `Bearer ${config.apiKey}` },

body: formData,

});

await env.DB.prepare(

'INSERT INTO deliveries (build_version, network, status, delivered_at) VALUES (?, ?, ?, ?)'

).bind(buildVersion, network, resp.ok ? 'delivered' : 'failed', Date.now()).run();

}

}

```

**D1 tracking schema:**

```sql

CREATE TABLE builds (

id INTEGER PRIMARY KEY AUTOINCREMENT,

version TEXT NOT NULL UNIQUE,

commit_sha TEXT NOT NULL,

built_at INTEGER NOT NULL,

processed_at INTEGER,

status TEXT DEFAULT 'pending'

);

CREATE TABLE deliveries (

id INTEGER PRIMARY KEY AUTOINCREMENT,

build_id INTEGER REFERENCES builds(id),

network TEXT NOT NULL,

asset_type TEXT NOT NULL,

status TEXT NOT NULL,

delivered_at INTEGER NOT NULL,

error_message TEXT

);

```

Results

After deploying the handoff protocol, CCFish's dev-to-marketing pipeline transformed:

- **Asset turnaround time dropped from ~24 hours to under 10 minutes.** Screenshots, video previews, and MRAID ads are available for review within minutes of a build completing.

- **Zero manual asset handling.** Marketing no longer downloads, crops, or uploads anything — the pipeline pushes directly to ad networks.

- **All six ad networks receive assets simultaneously.** Previously, rolling out a new build to all networks took a full day of sequential uploads. Now it's a parallel batch operation.

- **The tracking dashboard eliminated Slack ping-pong.** Both teams see exactly which build version is live on which network, with timestamps and error logs.

- **Playable ad CTR improved by 22%** because MRAID creatives now accurately match the current build's visuals and mechanics — no more stale ads pointing to outdated builds.

- **Build artifact storage in R2 costs under $3/month.** The processing Workers each run for 2–5 minutes and stay within the Free tier.

Key Takeaways

1. **Treat marketing assets as CI artifacts.** When screenshots, videos, and playable ads are generated from the same build artifacts that produce the binary, they're guaranteed to match the live game. This eliminates the stale-creative problem that plagues mobile game UA.

2. **Cloudflare Workers are surprisingly capable for media processing.** The Browser Rendering API for headless Chromium and Queues for fan-out orchestration provide a serverless pipeline that handles everything from screenshot capture to API delivery — no dedicated media servers needed.

3. **MRAID playable ads from Web builds are a natural fit.** Cocos Creator's Web export is already a self-contained HTML5 application. Wrapping it in an MRAIF template is a few lines of JavaScript, and it runs identically on every ad network that supports the MRAID standard.

4. **A shared tracking layer aligns dev and marketing.** The D1-powered dashboard gives both teams the same source of truth. Marketing can see "Build 2.4.15 is processing screenshots" without bothering the developer; developers can see "Build 2.4.13 is live on Unity Ads" without asking marketing.

5. **Start simple, layer complexity.** The first version of this pipeline just pushed screenshots to a single network. From there, it grew to support video encoding, MRAID templates, and all six ad networks. Each addition was a new Worker and a new queue — parallel by design.

By bridging Cocos Creator's build output directly to ad network APIs through Cloudflare Workers, CCFish turned a high-friction cross-team handoff into an automated, observable, and reliable pipeline. The result: fresher ads, faster iterations, and a much happier marketing team.